]> git.sesse.net Git - vlc/blob - modules/codec/jpeg.c
mediacodec: fix warning
[vlc] / modules / codec / jpeg.c
1 /*****************************************************************************
2  * jpeg.c: jpeg decoder module making use of libjpeg.
3  *****************************************************************************
4  * Copyright (C) 2013-2014 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 /* JPEG_SYS_COMMON_MEMBERS:
34  * members common to encoder and decoder descriptors
35  */
36 #define JPEG_SYS_COMMON_MEMBERS                             \
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     vlc_object_t *p_obj;                                    \
45                                                             \
46 /**@}*/                                                     \
47
48 #define ENC_CFG_PREFIX "sout-jpeg-"
49 #define ENC_QUALITY_TEXT N_("Quality level")
50 #define ENC_QUALITY_LONGTEXT N_("Quality level " \
51     "for encoding (this can enlarge or reduce output image size).")
52
53
54 /*
55  * jpeg common descriptor
56  */
57 struct jpeg_sys_t
58 {
59     JPEG_SYS_COMMON_MEMBERS
60 };
61
62 typedef struct jpeg_sys_t jpeg_sys_t;
63
64 /*
65  * jpeg decoder descriptor
66  */
67 struct decoder_sys_t
68 {
69     JPEG_SYS_COMMON_MEMBERS
70
71     struct jpeg_decompress_struct p_jpeg;
72 };
73
74 static int  OpenDecoder(vlc_object_t *);
75 static void CloseDecoder(vlc_object_t *);
76
77 static picture_t *DecodeBlock(decoder_t *, block_t **);
78
79 /*
80  * jpeg encoder descriptor
81  */
82 struct encoder_sys_t
83 {
84     JPEG_SYS_COMMON_MEMBERS
85
86     struct jpeg_compress_struct p_jpeg;
87
88     int i_blocksize;
89     int i_quality;
90 };
91
92 static const char * const ppsz_enc_options[] = {
93     "quality",
94     NULL
95 };
96
97 static int  OpenEncoder(vlc_object_t *);
98 static void CloseEncoder(vlc_object_t *);
99
100 static block_t *EncodeBlock(encoder_t *, picture_t *);
101
102 /*
103  * Module descriptor
104  */
105 vlc_module_begin()
106     set_category(CAT_INPUT)
107     set_subcategory(SUBCAT_INPUT_VCODEC)
108     /* decoder main module */
109     set_description(N_("JPEG image decoder"))
110     set_capability("decoder", 1000)
111     set_callbacks(OpenDecoder, CloseDecoder)
112     add_shortcut("jpeg")
113
114     /* encoder submodule */
115     add_submodule()
116     add_shortcut("jpeg")
117     set_section(N_("Encoding"), NULL)
118     set_description(N_("JPEG image encoder"))
119     set_capability("encoder", 1000)
120     set_callbacks(OpenEncoder, CloseEncoder)
121     add_integer_with_range(ENC_CFG_PREFIX "quality", 95, 0, 100,
122                            ENC_QUALITY_TEXT, ENC_QUALITY_LONGTEXT, true)
123 vlc_module_end()
124
125
126 /*
127  * Exit error handler for libjpeg
128  */
129 static void user_error_exit(j_common_ptr p_jpeg)
130 {
131     jpeg_sys_t *p_sys = (jpeg_sys_t *)p_jpeg->err;
132     p_sys->err.output_message(p_jpeg);
133     longjmp(p_sys->setjmp_buffer, 1);
134 }
135
136 /*
137  * Emit message error handler for libjpeg
138  */
139 static void user_error_message(j_common_ptr p_jpeg)
140 {
141     char error_msg[JMSG_LENGTH_MAX];
142
143     jpeg_sys_t *p_sys = (jpeg_sys_t *)p_jpeg->err;
144     p_sys->err.format_message(p_jpeg, error_msg);
145     msg_Err(p_sys->p_obj, "%s", error_msg);
146 }
147
148 /*
149  * Probe the decoder and return score
150  */
151 static int OpenDecoder(vlc_object_t *p_this)
152 {
153     decoder_t *p_dec = (decoder_t *)p_this;
154
155     if (p_dec->fmt_in.i_codec != VLC_CODEC_JPEG)
156     {
157         return VLC_EGENERIC;
158     }
159
160     /* Allocate the memory needed to store the decoder's structure */
161     decoder_sys_t *p_sys = malloc(sizeof(decoder_sys_t));
162     if (p_sys == NULL)
163     {
164         return VLC_ENOMEM;
165     }
166
167     p_dec->p_sys = p_sys;
168
169     p_sys->p_obj = p_this;
170
171     p_sys->p_jpeg.err = jpeg_std_error(&p_sys->err);
172     p_sys->err.error_exit = user_error_exit;
173     p_sys->err.output_message = user_error_message;
174
175     /* Set output properties */
176     p_dec->fmt_out.i_cat = VIDEO_ES;
177
178     /* Set callbacks */
179     p_dec->pf_decode_video = DecodeBlock;
180
181     return VLC_SUCCESS;
182 }
183
184 /*
185  * This function must be fed with a complete compressed frame.
186  */
187 static picture_t *DecodeBlock(decoder_t *p_dec, block_t **pp_block)
188 {
189     decoder_sys_t *p_sys = p_dec->p_sys;
190     block_t *p_block;
191     picture_t *p_pic = 0;
192
193     JSAMPARRAY p_row_pointers = NULL;
194
195     if (!pp_block || !*pp_block)
196     {
197         return NULL;
198     }
199
200     p_block = *pp_block;
201
202     if (p_block->i_flags & BLOCK_FLAG_DISCONTINUITY)
203     {
204         block_Release(p_block);
205         *pp_block = NULL;
206         return NULL;
207     }
208
209     /* libjpeg longjmp's there in case of error */
210     if (setjmp(p_sys->setjmp_buffer))
211     {
212         goto error;
213     }
214
215     jpeg_create_decompress(&p_sys->p_jpeg);
216     jpeg_mem_src(&p_sys->p_jpeg, p_block->p_buffer, p_block->i_buffer);
217     jpeg_read_header(&p_sys->p_jpeg, TRUE);
218
219     p_sys->p_jpeg.out_color_space = JCS_RGB;
220
221     jpeg_start_decompress(&p_sys->p_jpeg);
222
223     /* Set output properties */
224     p_dec->fmt_out.i_codec = VLC_CODEC_RGB24;
225     p_dec->fmt_out.video.i_visible_width  = p_dec->fmt_out.video.i_width  = p_sys->p_jpeg.output_width;
226     p_dec->fmt_out.video.i_visible_height = p_dec->fmt_out.video.i_height = p_sys->p_jpeg.output_height;
227     p_dec->fmt_out.video.i_sar_num = 1;
228     p_dec->fmt_out.video.i_sar_den = 1;
229     p_dec->fmt_out.video.i_rmask = 0x000000ff;
230     p_dec->fmt_out.video.i_gmask = 0x0000ff00;
231     p_dec->fmt_out.video.i_bmask = 0x00ff0000;
232
233     /* Get a new picture */
234     p_pic = decoder_NewPicture(p_dec);
235     if (!p_pic)
236     {
237         goto error;
238     }
239
240     /* Decode picture */
241     p_row_pointers = malloc(sizeof(JSAMPROW) * p_sys->p_jpeg.output_height);
242     if (!p_row_pointers)
243     {
244         goto error;
245     }
246     for (unsigned i = 0; i < p_sys->p_jpeg.output_height; i++) {
247         p_row_pointers[i] = p_pic->p->p_pixels + p_pic->p->i_pitch * i;
248     }
249
250     while (p_sys->p_jpeg.output_scanline < p_sys->p_jpeg.output_height)
251     {
252         jpeg_read_scanlines(&p_sys->p_jpeg,
253                 p_row_pointers + p_sys->p_jpeg.output_scanline,
254                 p_sys->p_jpeg.output_height - p_sys->p_jpeg.output_scanline);
255     }
256
257     jpeg_finish_decompress(&p_sys->p_jpeg);
258     jpeg_destroy_decompress(&p_sys->p_jpeg);
259     free(p_row_pointers);
260
261     p_pic->date = p_block->i_pts > VLC_TS_INVALID ? p_block->i_pts : p_block->i_dts;
262
263     block_Release(p_block);
264     *pp_block = NULL;
265
266     return p_pic;
267
268 error:
269
270     jpeg_destroy_decompress(&p_sys->p_jpeg);
271     free(p_row_pointers);
272
273     block_Release(p_block);
274     *pp_block = NULL;
275
276     return NULL;
277 }
278
279 /*
280  * jpeg decoder destruction
281  */
282 static void CloseDecoder(vlc_object_t *p_this)
283 {
284     decoder_t *p_dec = (decoder_t *)p_this;
285     decoder_sys_t *p_sys = p_dec->p_sys;
286
287     free(p_sys);
288 }
289
290 /*
291  * Probe the encoder and return score
292  */
293 static int OpenEncoder(vlc_object_t *p_this)
294 {
295     encoder_t *p_enc = (encoder_t *)p_this;
296
297     config_ChainParse(p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg);
298
299     if (p_enc->fmt_out.i_codec != VLC_CODEC_JPEG)
300     {
301         return VLC_EGENERIC;
302     }
303
304     /* Allocate the memory needed to store encoder's structure */
305     encoder_sys_t *p_sys = malloc(sizeof(encoder_sys_t));
306     if (p_sys == NULL)
307     {
308         return VLC_ENOMEM;
309     }
310
311     p_enc->p_sys = p_sys;
312
313     p_sys->p_obj = p_this;
314
315     p_sys->p_jpeg.err = jpeg_std_error(&p_sys->err);
316     p_sys->err.error_exit = user_error_exit;
317     p_sys->err.output_message = user_error_message;
318
319     p_sys->i_quality = var_GetInteger(p_enc, ENC_CFG_PREFIX "quality");
320     p_sys->i_blocksize = 3 * p_enc->fmt_in.video.i_visible_width * p_enc->fmt_in.video.i_visible_height;
321
322     p_enc->fmt_in.i_codec = VLC_CODEC_J420;
323     p_enc->pf_encode_video = EncodeBlock;
324
325     return VLC_SUCCESS;
326 }
327
328 /*
329  * EncodeBlock
330  */
331 static block_t *EncodeBlock(encoder_t *p_enc, picture_t *p_pic)
332 {
333     encoder_sys_t *p_sys = p_enc->p_sys;
334
335     if (unlikely(!p_pic))
336     {
337         return NULL;
338     }
339     block_t *p_block = block_Alloc(p_sys->i_blocksize);
340     if (p_block == NULL)
341     {
342         return NULL;
343     }
344
345     JSAMPIMAGE p_row_pointers = NULL;
346
347     /* libjpeg longjmp's there in case of error */
348     if (setjmp(p_sys->setjmp_buffer))
349     {
350         goto error;
351     }
352
353     jpeg_create_compress(&p_sys->p_jpeg);
354     jpeg_mem_dest(&p_sys->p_jpeg, &p_block->p_buffer, &p_block->i_buffer);
355
356     p_sys->p_jpeg.image_width = p_enc->fmt_in.video.i_visible_width;
357     p_sys->p_jpeg.image_height = p_enc->fmt_in.video.i_visible_height;
358     p_sys->p_jpeg.input_components = 3;
359     p_sys->p_jpeg.in_color_space = JCS_YCbCr;
360
361     jpeg_set_defaults(&p_sys->p_jpeg);
362     jpeg_set_colorspace(&p_sys->p_jpeg, JCS_YCbCr);
363
364     p_sys->p_jpeg.raw_data_in = TRUE;
365 #if JPEG_LIB_VERSION >= 70
366     p_sys->p_jpeg.do_fancy_downsampling = FALSE;
367 #endif
368
369     jpeg_set_quality(&p_sys->p_jpeg, p_sys->i_quality, TRUE);
370
371     jpeg_start_compress(&p_sys->p_jpeg, TRUE);
372
373     /* Encode picture */
374     p_row_pointers = malloc(sizeof(JSAMPARRAY) * p_pic->i_planes);
375     if (p_row_pointers == NULL)
376     {
377         goto error;
378     }
379
380     for (int i = 0; i < p_pic->i_planes; i++)
381     {
382         p_row_pointers[i] = malloc(sizeof(JSAMPROW) * p_sys->p_jpeg.comp_info[i].v_samp_factor * DCTSIZE);
383     }
384
385     while (p_sys->p_jpeg.next_scanline < p_sys->p_jpeg.image_height)
386     {
387         for (int i = 0; i < p_pic->i_planes; i++)
388         {
389             int i_offset = p_sys->p_jpeg.next_scanline * p_sys->p_jpeg.comp_info[i].v_samp_factor / p_sys->p_jpeg.max_v_samp_factor;
390
391             for (int j = 0; j < p_sys->p_jpeg.comp_info[i].v_samp_factor * DCTSIZE; j++)
392             {
393                 p_row_pointers[i][j] = p_pic->p[i].p_pixels + p_pic->p[i].i_pitch * (i_offset + j);
394             }
395         }
396         jpeg_write_raw_data(&p_sys->p_jpeg, p_row_pointers, p_sys->p_jpeg.max_v_samp_factor * DCTSIZE);
397     }
398
399     jpeg_finish_compress(&p_sys->p_jpeg);
400     jpeg_destroy_compress(&p_sys->p_jpeg);
401
402     for (int i = 0; i < p_pic->i_planes; i++)
403     {
404         free(p_row_pointers[i]);
405     }
406     free(p_row_pointers);
407
408     p_block->i_dts = p_block->i_pts = p_pic->date;
409
410     return p_block;
411
412 error:
413     jpeg_destroy_compress(&p_sys->p_jpeg);
414
415     if (p_row_pointers != NULL)
416     {
417         for (int i = 0; i < p_pic->i_planes; i++)
418         {
419             free(p_row_pointers[i]);
420         }
421     }
422     free(p_row_pointers);
423
424     block_Release(p_block);
425
426     return NULL;
427 }
428
429 /*
430  * jpeg encoder destruction
431  */
432 static void CloseEncoder(vlc_object_t *p_this)
433 {
434     encoder_t *p_enc = (encoder_t *)p_this;
435     encoder_sys_t *p_sys = p_enc->p_sys;
436
437     free(p_sys);
438 }