]> git.sesse.net Git - vlc/blob - modules/codec/jpeg.c
codec: implemented libjpeg module
[vlc] / modules / codec / jpeg.c
1 /*****************************************************************************
2  * jpeg.c: jpeg decoder module making use of libjpeg.
3  *****************************************************************************
4  * Copyright (C) 2013 VLC authors and VideoLAN
5  *
6  * Authors: Maxim Bublis <b@codemonkey.ru>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include <vlc_common.h>
28 #include <vlc_plugin.h>
29 #include <vlc_codec.h>
30 #include <jpeglib.h>
31 #include <setjmp.h>
32
33 /*
34  * jpeg decoder descriptor
35  */
36 struct decoder_sys_t
37 {
38     /* libjpeg error handler manager */
39     struct jpeg_error_mgr err;
40
41     /* setjmp buffer for internal libjpeg error handling */
42     jmp_buf setjmp_buffer;
43
44     decoder_t *p_dec;
45
46     bool b_error;
47 };
48
49 static int  OpenDecoder(vlc_object_t *);
50 static void CloseDecoder(vlc_object_t *);
51
52 static picture_t *DecodeBlock(decoder_t *, block_t **);
53
54 /*
55  * Module descriptor
56  */
57 vlc_module_begin()
58     set_category(CAT_INPUT)
59     set_subcategory(SUBCAT_INPUT_VCODEC)
60     set_description(N_("JPEG image decoder"))
61     set_capability("decoder", 1000)
62     set_callbacks(OpenDecoder, CloseDecoder)
63     add_shortcut("jpeg")
64 vlc_module_end()
65
66 /*
67  * Probe the decoder and return score
68  */
69 static int OpenDecoder(vlc_object_t *p_this)
70 {
71     decoder_t *p_dec = (decoder_t *)p_this;
72
73     if (p_dec->fmt_in.i_codec != VLC_CODEC_JPEG)
74     {
75         return VLC_EGENERIC;
76     }
77
78     /* Allocate the memory needed to store the decoder's structure */
79     p_dec->p_sys = malloc(sizeof(decoder_sys_t));
80     if (p_dec->p_sys == NULL)
81     {
82         return VLC_ENOMEM;
83     }
84
85     p_dec->p_sys->p_dec = p_dec;
86
87     /* Set output properties */
88     p_dec->fmt_out.i_cat = VIDEO_ES;
89
90     /* Set callbacks */
91     p_dec->pf_decode_video = DecodeBlock;
92
93     return VLC_SUCCESS;
94 }
95
96 /*
97  * Exit error handler for libjpeg
98  */
99 static void user_error_exit(j_common_ptr p_jpeg)
100 {
101     decoder_sys_t *p_sys = (decoder_sys_t *)p_jpeg->err;
102     p_sys->b_error = true;
103     p_sys->err.output_message(p_jpeg);
104     longjmp(p_sys->setjmp_buffer, 1);
105 }
106
107 /*
108  * Emit message error handler for libjpeg
109  */
110 static void user_error_message(j_common_ptr p_jpeg)
111 {
112     char error_msg[JMSG_LENGTH_MAX];
113
114     decoder_sys_t *p_sys = (decoder_sys_t *)p_jpeg->err;
115     p_sys->err.format_message(p_jpeg, error_msg);
116     msg_Err(p_sys->p_dec, "%s", error_msg);
117 }
118
119 /*
120  * This function must be fed with a complete compressed frame.
121  */
122 static picture_t *DecodeBlock(decoder_t *p_dec, block_t **pp_block)
123 {
124     decoder_sys_t *p_sys = p_dec->p_sys;
125     block_t *p_block;
126     picture_t *p_pic = 0;
127
128     struct jpeg_decompress_struct p_jpeg;
129     JSAMPARRAY p_row_pointers = NULL;
130
131     if (!pp_block || !*pp_block)
132     {
133         return NULL;
134     }
135
136     p_block = *pp_block;
137     p_sys->b_error = false;
138
139     if (p_block->i_flags & BLOCK_FLAG_DISCONTINUITY)
140     {
141         block_Release(p_block);
142         *pp_block = NULL;
143         return NULL;
144     }
145
146     p_jpeg.err = jpeg_std_error(&p_sys->err);
147     p_sys->err.error_exit = user_error_exit;
148     p_sys->err.output_message = user_error_message;
149
150     /* libjpeg longjmp's there in case of error */
151     if (setjmp(p_sys->setjmp_buffer))
152     {
153         goto error;
154     }
155
156     jpeg_create_decompress(&p_jpeg);
157     if (p_sys->b_error)
158     {
159         goto error;
160     }
161
162     jpeg_mem_src(&p_jpeg, p_block->p_buffer, p_block->i_buffer);
163     if (p_sys->b_error)
164     {
165         goto error;
166     }
167
168     jpeg_read_header(&p_jpeg, TRUE);
169     if (p_sys->b_error)
170     {
171         goto error;
172     }
173
174     p_jpeg.out_color_space = JCS_RGB;
175
176     jpeg_start_decompress(&p_jpeg);
177     if (p_sys->b_error)
178     {
179         goto error;
180     }
181
182     /* Set output properties */
183     p_dec->fmt_out.i_codec = VLC_CODEC_RGB24;
184     p_dec->fmt_out.video.i_width = p_jpeg.output_width;
185     p_dec->fmt_out.video.i_height = p_jpeg.output_height;
186     p_dec->fmt_out.video.i_sar_num = 1;
187     p_dec->fmt_out.video.i_sar_den = 1;
188     p_dec->fmt_out.video.i_rmask = 0x000000ff;
189     p_dec->fmt_out.video.i_gmask = 0x0000ff00;
190     p_dec->fmt_out.video.i_bmask = 0x00ff0000;
191
192     /* Get a new picture */
193     p_pic = decoder_NewPicture(p_dec);
194     if (!p_pic)
195     {
196         goto error;
197     }
198
199     /* Decode picture */
200     p_row_pointers = malloc(sizeof(JSAMPROW) * p_jpeg.output_height);
201     if (!p_row_pointers)
202     {
203         goto error;
204     }
205     for (int i = 0; i < (int)p_jpeg.output_height; i++) {
206         p_row_pointers[i] = p_pic->p->p_pixels + p_pic->p->i_pitch * i;
207     }
208
209     while (p_jpeg.output_scanline < p_jpeg.output_height)
210     {
211         jpeg_read_scanlines(&p_jpeg, p_row_pointers + p_jpeg.output_scanline,
212                                      p_jpeg.output_height - p_jpeg.output_scanline);
213         if (p_sys->b_error)
214         {
215             goto error;
216         }
217     }
218
219     jpeg_finish_decompress(&p_jpeg);
220     jpeg_destroy_decompress(&p_jpeg);
221     free(p_row_pointers);
222
223     p_pic->date = p_block->i_pts > VLC_TS_INVALID ? p_block->i_pts : p_block->i_dts;
224
225     block_Release(p_block);
226     *pp_block = NULL;
227
228     return p_pic;
229
230 error:
231
232     jpeg_destroy_decompress(&p_jpeg);
233     free(p_row_pointers);
234
235     block_Release(p_block);
236     *pp_block = NULL;
237
238     return NULL;
239 }
240
241 /*
242  * jpeg decoder destruction
243  */
244 static void CloseDecoder(vlc_object_t *p_this)
245 {
246     decoder_t *p_dec = (decoder_t *)p_this;
247     decoder_sys_t *p_sys = p_dec->p_sys;
248
249     free(p_sys);
250 }