486502b2113c620a5370d0ff38a0c18c4d5da780
[vlc.git] / modules / codec / jpeg.c
1 /*****************************************************************************
2  * jpeg.c: jpeg decoder module making use of libjpeg.
3  *****************************************************************************
4  * Copyright (C) 2013-2014,2016 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 <vlc_charset.h>
31
32 #include <jpeglib.h>
33 #include <setjmp.h>
34
35 /* JPEG_SYS_COMMON_MEMBERS:
36  * members common to encoder and decoder descriptors
37  */
38 #define JPEG_SYS_COMMON_MEMBERS                             \
39 /**@{*/                                                     \
40     /* libjpeg error handler manager */                     \
41     struct jpeg_error_mgr err;                              \
42                                                             \
43     /* setjmp buffer for internal libjpeg error handling */ \
44     jmp_buf setjmp_buffer;                                  \
45                                                             \
46     vlc_object_t *p_obj;                                    \
47                                                             \
48 /**@}*/                                                     \
49
50 #define ENC_CFG_PREFIX "sout-jpeg-"
51 #define ENC_QUALITY_TEXT N_("Quality level")
52 #define ENC_QUALITY_LONGTEXT N_("Quality level " \
53     "for encoding (this can enlarge or reduce output image size).")
54
55
56 /*
57  * jpeg common descriptor
58  */
59 struct jpeg_sys_t
60 {
61     JPEG_SYS_COMMON_MEMBERS
62 };
63
64 typedef struct jpeg_sys_t jpeg_sys_t;
65
66 /*
67  * jpeg decoder descriptor
68  */
69 typedef struct
70 {
71     JPEG_SYS_COMMON_MEMBERS
72
73     JSAMPARRAY p_row_pointers;
74     struct jpeg_decompress_struct p_jpeg;
75 } decoder_sys_t;
76
77 static int  OpenDecoder(vlc_object_t *);
78 static void CloseDecoder(vlc_object_t *);
79
80 static int DecodeBlock(decoder_t *, block_t *);
81
82 /*
83  * jpeg encoder descriptor
84  */
85 typedef struct
86 {
87     JPEG_SYS_COMMON_MEMBERS
88
89     struct jpeg_compress_struct p_jpeg;
90
91     int i_blocksize;
92     int i_quality;
93 } encoder_sys_t;
94
95 static const char * const ppsz_enc_options[] = {
96     "quality",
97     NULL
98 };
99
100 static int  OpenEncoder(vlc_object_t *);
101 static void CloseEncoder(vlc_object_t *);
102
103 static block_t *EncodeBlock(encoder_t *, picture_t *);
104
105 /*
106  * Module descriptor
107  */
108 vlc_module_begin()
109     set_category(CAT_INPUT)
110     set_subcategory(SUBCAT_INPUT_VCODEC)
111     /* decoder main module */
112     set_description(N_("JPEG image decoder"))
113     set_capability("video decoder", 1000)
114     set_callbacks(OpenDecoder, CloseDecoder)
115     add_shortcut("jpeg")
116
117     /* encoder submodule */
118     add_submodule()
119     add_shortcut("jpeg")
120     set_section(N_("Encoding"), NULL)
121     set_description(N_("JPEG image encoder"))
122     set_capability("encoder", 1000)
123     set_callbacks(OpenEncoder, CloseEncoder)
124     add_integer_with_range(ENC_CFG_PREFIX "quality", 95, 0, 100,
125                            ENC_QUALITY_TEXT, ENC_QUALITY_LONGTEXT, true)
126 vlc_module_end()
127
128
129 /*
130  * Exit error handler for libjpeg
131  */
132 static void user_error_exit(j_common_ptr p_jpeg)
133 {
134     jpeg_sys_t *p_sys = (jpeg_sys_t *)p_jpeg->err;
135     p_sys->err.output_message(p_jpeg);
136     longjmp(p_sys->setjmp_buffer, 1);
137 }
138
139 /*
140  * Emit message error handler for libjpeg
141  */
142 static void user_error_message(j_common_ptr p_jpeg)
143 {
144     char error_msg[JMSG_LENGTH_MAX];
145
146     jpeg_sys_t *p_sys = (jpeg_sys_t *)p_jpeg->err;
147     p_sys->err.format_message(p_jpeg, error_msg);
148     msg_Err(p_sys->p_obj, "%s", error_msg);
149 }
150
151 /*
152  * Probe the decoder and return score
153  */
154 static int OpenDecoder(vlc_object_t *p_this)
155 {
156     decoder_t *p_dec = (decoder_t *)p_this;
157
158     if (p_dec->fmt_in.i_codec != VLC_CODEC_JPEG)
159     {
160         return VLC_EGENERIC;
161     }
162
163     /* Allocate the memory needed to store the decoder's structure */
164     decoder_sys_t *p_sys = malloc(sizeof(decoder_sys_t));
165     if (p_sys == NULL)
166     {
167         return VLC_ENOMEM;
168     }
169
170     p_dec->p_sys = p_sys;
171
172     p_sys->p_obj = p_this;
173
174     p_sys->p_jpeg.err = jpeg_std_error(&p_sys->err);
175     p_sys->err.error_exit = user_error_exit;
176     p_sys->err.output_message = user_error_message;
177
178     /* Set callbacks */
179     p_dec->pf_decode = DecodeBlock;
180
181     p_dec->fmt_out.video.i_chroma =
182     p_dec->fmt_out.i_codec = VLC_CODEC_RGB24;
183     p_dec->fmt_out.video.transfer  = TRANSFER_FUNC_SRGB;
184     p_dec->fmt_out.video.space     = COLOR_SPACE_SRGB;
185     p_dec->fmt_out.video.primaries = COLOR_PRIMARIES_SRGB;
186     p_dec->fmt_out.video.color_range = COLOR_RANGE_FULL;
187     video_format_FixRgb(&p_dec->fmt_out.video);
188
189     return VLC_SUCCESS;
190 }
191
192 /*
193  * The following two functions are used to return 16 and 32 bit values from
194  * the EXIF tag structure. That structure is borrowed from TIFF files and may be
195  * in big endian or little endian format. The boolean b_bigEndian parameter
196  * is TRUE if the EXIF data is in big endian format, and FALSE for little endian
197  * Case Little Endian EXIF tag / Little Endian machine
198  *   - just memcpy the tag structure into the value to return
199  * Case Little Endian EXIF tag / Big Endian machine
200  *    - memcpy the tag structure into value, and bswap it
201  * Case Little Endian EXIF tag / Big Endian machine
202  *   - memcpy the tag structure into value, and bswap it
203  * Case Big Endian EXIF tag / Big Endian machine
204  *   - just memcpy the tag structure into the value to return
205  *
206  * While there are byte manipulation functions in vlc_common.h, none of them
207  * address that format of the data supplied may be either big or little endian.
208  *
209  * The claim is made that this is the best way to do it. Can you do better?
210 */
211
212 #define G_LITTLE_ENDIAN     1234
213 #define G_BIG_ENDIAN        4321
214
215 typedef unsigned int uint;
216 typedef unsigned short ushort;
217
218 LOCAL( unsigned short )
219 de_get16( void * ptr, uint endian ) {
220     unsigned short val;
221
222     memcpy( &val, ptr, sizeof( val ) );
223     if ( endian == G_BIG_ENDIAN )
224     {
225         #ifndef WORDS_BIGENDIAN
226         val = vlc_bswap16( val );
227         #endif
228     }
229     else
230     {
231         #ifdef WORDS_BIGENDIAN
232         val = vlc_bswap16( val );
233         #endif
234     }
235     return val;
236 }
237
238 LOCAL( unsigned int )
239 de_get32( void * ptr, uint endian ) {
240     unsigned int val;
241
242     memcpy( &val, ptr, sizeof( val ) );
243     if ( endian == G_BIG_ENDIAN )
244     {
245         #ifndef WORDS_BIGENDIAN
246         val = vlc_bswap32( val );
247         #endif
248     }
249     else
250     {
251         #ifdef WORDS_BIGENDIAN
252         val = vlc_bswap32( val );
253         #endif
254     }
255     return val;
256 }
257
258 static bool getRDFFloat(const char *psz_rdf, float *out, const char *psz_var)
259 {
260     char *p_start = strcasestr(psz_rdf, psz_var);
261     if (p_start == NULL)
262         return false;
263
264     size_t varlen = strlen(psz_var);
265     p_start += varlen;
266     char *p_end = NULL;
267     /* XML style */
268     if (p_start[0] == '>')
269     {
270         p_start += 1;
271         p_end = strchr(p_start, '<');
272     }
273     else if (p_start[0] == '=' && p_start[1] == '"')
274     {
275         p_start += 2;
276         p_end = strchr(p_start, '"');
277     }
278     if (unlikely(p_end == NULL || p_end == p_start + 1))
279         return false;
280
281     *out = us_strtof(p_start, NULL);
282     return true;
283 }
284
285 #define EXIF_JPEG_MARKER    0xE1
286 #define EXIF_XMP_STRING     "http://ns.adobe.com/xap/1.0/\000"
287
288 /* read XMP metadata for projection according to
289  * https://developers.google.com/streetview/spherical-metadata */
290 static void jpeg_GetProjection(j_decompress_ptr cinfo, video_format_t *fmt)
291 {
292     jpeg_saved_marker_ptr xmp_marker = NULL;
293     jpeg_saved_marker_ptr cmarker = cinfo->marker_list;
294
295     while (cmarker)
296     {
297         if (cmarker->marker == EXIF_JPEG_MARKER)
298         {
299             if(cmarker->data_length >= 32 &&
300                !memcmp(cmarker->data, EXIF_XMP_STRING, 29))
301             {
302                 xmp_marker = cmarker;
303                 break;
304             }
305         }
306         cmarker = cmarker->next;
307     }
308
309     if (xmp_marker == NULL)
310         return;
311     char *psz_rdf = malloc(xmp_marker->data_length - 29 + 1);
312     if (unlikely(psz_rdf == NULL))
313         return;
314     memcpy(psz_rdf, xmp_marker->data + 29, xmp_marker->data_length - 29);
315     psz_rdf[xmp_marker->data_length - 29] = '\0';
316
317     /* Try to find the string "GSpherical:Spherical" because the v1
318         spherical video spec says the tag must be there. */
319     if (strcasestr(psz_rdf, "ProjectionType=\"equirectangular\"") ||
320         strcasestr(psz_rdf, "ProjectionType>equirectangular"))
321         fmt->projection_mode = PROJECTION_MODE_EQUIRECTANGULAR;
322
323     /* pose handling */
324     float value;
325     if (getRDFFloat(psz_rdf, &value, "PoseHeadingDegrees"))
326         fmt->pose.yaw = value;
327
328     if (getRDFFloat(psz_rdf, &value, "PosePitchDegrees"))
329         fmt->pose.pitch = value;
330
331     if (getRDFFloat(psz_rdf, &value, "PoseRollDegrees"))
332         fmt->pose.roll = value;
333
334     /* initial view */
335     if (getRDFFloat(psz_rdf, &value, "InitialViewHeadingDegrees"))
336         fmt->pose.yaw = value;
337
338     if (getRDFFloat(psz_rdf, &value, "InitialViewPitchDegrees"))
339         fmt->pose.pitch = value;
340
341     if (getRDFFloat(psz_rdf, &value, "InitialViewRollDegrees"))
342         fmt->pose.roll = value;
343
344     if (getRDFFloat(psz_rdf, &value, "InitialHorizontalFOVDegrees"))
345         fmt->pose.fov = value;
346
347     free(psz_rdf);
348 }
349
350 /*
351  * Look through the meta data in the libjpeg decompress structure to determine
352  * if an EXIF Orientation tag is present. If so return its value (1-8),
353  * otherwise return 0
354  *
355  * This function is based on the function get_orientation in io-jpeg.c, part of
356  * the GdkPixbuf library, licensed under LGPLv2+.
357  *   Copyright (C) 1999 Michael Zucchi, The Free Software Foundation
358 */
359 LOCAL( int )
360 jpeg_GetOrientation( j_decompress_ptr cinfo )
361 {
362
363     uint i;                    /* index into working buffer */
364     ushort tag_type;           /* endianed tag type extracted from tiff header */
365     uint ret;                  /* Return value */
366     uint offset;               /* de-endianed offset in various situations */
367     uint tags;                 /* number of tags in current ifd */
368     uint type;                 /* de-endianed type of tag */
369     uint count;                /* de-endianed count of elements in a tag */
370     uint tiff = 0;             /* offset to active tiff header */
371     uint endian = 0;           /* detected endian of data */
372
373     jpeg_saved_marker_ptr exif_marker;      /* Location of the Exif APP1 marker */
374     jpeg_saved_marker_ptr cmarker;          /* Location to check for Exif APP1 marker */
375
376     const char leth[] = { 0x49, 0x49, 0x2a, 0x00 }; /* Little endian TIFF header */
377     const char beth[] = { 0x4d, 0x4d, 0x00, 0x2a }; /* Big endian TIFF header */
378
379     #define EXIF_IDENT_STRING   "Exif\000\000"
380     #define EXIF_ORIENT_TAGID   0x112
381
382     /* check for Exif marker (also called the APP1 marker) */
383     exif_marker = NULL;
384     cmarker = cinfo->marker_list;
385
386     while ( cmarker )
387     {
388         if ( cmarker->data_length >= 32 &&
389              cmarker->marker == EXIF_JPEG_MARKER )
390         {
391             /* The Exif APP1 marker should contain a unique
392                identification string ("Exif\0\0"). Check for it. */
393             if ( !memcmp( cmarker->data, EXIF_IDENT_STRING, 6 ) )
394             {
395                 exif_marker = cmarker;
396             }
397         }
398         cmarker = cmarker->next;
399     }
400
401     /* Did we find the Exif APP1 marker? */
402     if ( exif_marker == NULL )
403         return 0;
404
405     /* Check for TIFF header and catch endianess */
406     i = 0;
407
408     /* Just skip data until TIFF header - it should be within 16 bytes from marker start.
409        Normal structure relative to APP1 marker -
410             0x0000: APP1 marker entry = 2 bytes
411             0x0002: APP1 length entry = 2 bytes
412             0x0004: Exif Identifier entry = 6 bytes
413             0x000A: Start of TIFF header (Byte order entry) - 4 bytes
414                     - This is what we look for, to determine endianess.
415             0x000E: 0th IFD offset pointer - 4 bytes
416
417             exif_marker->data points to the first data after the APP1 marker
418             and length entries, which is the exif identification string.
419             The TIFF header should thus normally be found at i=6, below,
420             and the pointer to IFD0 will be at 6+4 = 10.
421     */
422
423     while ( i < 16 )
424     {
425         /* Little endian TIFF header */
426         if ( memcmp( &exif_marker->data[i], leth, 4 ) == 0 )
427         {
428             endian = G_LITTLE_ENDIAN;
429         }
430         /* Big endian TIFF header */
431         else
432         if ( memcmp( &exif_marker->data[i], beth, 4 ) == 0 )
433         {
434             endian = G_BIG_ENDIAN;
435         }
436         /* Keep looking through buffer */
437         else
438         {
439             i++;
440             continue;
441         }
442         /* We have found either big or little endian TIFF header */
443         tiff = i;
444         break;
445     }
446
447     /* So did we find a TIFF header or did we just hit end of buffer? */
448     if ( tiff == 0 )
449         return 0;
450
451     /* Read out the offset pointer to IFD0 */
452     offset = de_get32( &exif_marker->data[i] + 4, endian );
453     i = i + offset;
454
455     /* Check that we still are within the buffer and can read the tag count */
456
457     if ( i > exif_marker->data_length - 2 )
458         return 0;
459
460     /* Find out how many tags we have in IFD0. As per the TIFF spec, the first
461        two bytes of the IFD contain a count of the number of tags. */
462     tags = de_get16( &exif_marker->data[i], endian );
463     i = i + 2;
464
465     /* Check that we still have enough data for all tags to check. The tags
466        are listed in consecutive 12-byte blocks. The tag ID, type, size, and
467        a pointer to the actual value, are packed into these 12 byte entries. */
468     if ( tags * 12U > exif_marker->data_length - i )
469         return 0;
470
471     /* Check through IFD0 for tags of interest */
472     while ( tags-- )
473     {
474         tag_type = de_get16( &exif_marker->data[i], endian );
475         /* Is this the orientation tag? */
476         if ( tag_type == EXIF_ORIENT_TAGID )
477         {
478             type = de_get16( &exif_marker->data[i + 2], endian );
479             count = de_get32( &exif_marker->data[i + 4], endian );
480
481             /* Check that type and count fields are OK. The orientation field
482                will consist of a single (count=1) 2-byte integer (type=3). */
483             if ( type != 3 || count != 1 )
484                 return 0;
485
486             /* Return the orientation value. Within the 12-byte block, the
487                pointer to the actual data is at offset 8. */
488             ret = de_get16( &exif_marker->data[i + 8], endian );
489             return ( ret <= 8 ) ? ret : 0;
490         }
491         /* move the pointer to the next 12-byte tag field. */
492         i = i + 12;
493     }
494
495     return 0;     /* No EXIF Orientation tag found */
496 }
497
498 /*
499  * This function must be fed with a complete compressed frame.
500  */
501 static int DecodeBlock(decoder_t *p_dec, block_t *p_block)
502 {
503     decoder_sys_t *p_sys = p_dec->p_sys;
504     picture_t *p_pic = 0;
505
506     p_sys->p_row_pointers = NULL;
507
508     if (!p_block) /* No Drain */
509         return VLCDEC_SUCCESS;
510
511     if (p_block->i_flags & BLOCK_FLAG_CORRUPTED )
512     {
513         block_Release(p_block);
514         return VLCDEC_SUCCESS;
515     }
516
517     /* libjpeg longjmp's there in case of error */
518     if (setjmp(p_sys->setjmp_buffer))
519     {
520         goto error;
521     }
522
523     jpeg_create_decompress(&p_sys->p_jpeg);
524     jpeg_mem_src(&p_sys->p_jpeg, p_block->p_buffer, p_block->i_buffer);
525     jpeg_save_markers( &p_sys->p_jpeg, EXIF_JPEG_MARKER, 0xffff );
526     jpeg_read_header(&p_sys->p_jpeg, TRUE);
527
528     p_sys->p_jpeg.out_color_space = JCS_RGB;
529
530     jpeg_start_decompress(&p_sys->p_jpeg);
531
532     /* Set output properties */
533     p_dec->fmt_out.video.i_visible_width  = p_dec->fmt_out.video.i_width  = p_sys->p_jpeg.output_width;
534     p_dec->fmt_out.video.i_visible_height = p_dec->fmt_out.video.i_height = p_sys->p_jpeg.output_height;
535     p_dec->fmt_out.video.i_sar_num = 1;
536     p_dec->fmt_out.video.i_sar_den = 1;
537
538     int i_otag; /* Orientation tag has valid range of 1-8. 1 is normal orientation, 0 = unspecified = normal */
539     i_otag = jpeg_GetOrientation( &p_sys->p_jpeg );
540     if ( i_otag > 1 )
541     {
542         msg_Dbg( p_dec, "Jpeg orientation is %d", i_otag );
543         p_dec->fmt_out.video.orientation = ORIENT_FROM_EXIF( i_otag );
544     }
545     jpeg_GetProjection(&p_sys->p_jpeg, &p_dec->fmt_out.video);
546
547     /* Get a new picture */
548     if (decoder_UpdateVideoFormat(p_dec))
549     {
550         goto error;
551     }
552     p_pic = decoder_NewPicture(p_dec);
553     if (!p_pic)
554     {
555         goto error;
556     }
557
558     /* Decode picture */
559     p_sys->p_row_pointers = vlc_alloc(p_sys->p_jpeg.output_height, sizeof(JSAMPROW));
560     if (!p_sys->p_row_pointers)
561     {
562         goto error;
563     }
564     for (unsigned i = 0; i < p_sys->p_jpeg.output_height; i++) {
565         p_sys->p_row_pointers[i] = p_pic->p->p_pixels + p_pic->p->i_pitch * i;
566     }
567
568     while (p_sys->p_jpeg.output_scanline < p_sys->p_jpeg.output_height)
569     {
570         jpeg_read_scanlines(&p_sys->p_jpeg,
571                 p_sys->p_row_pointers + p_sys->p_jpeg.output_scanline,
572                 p_sys->p_jpeg.output_height - p_sys->p_jpeg.output_scanline);
573     }
574
575     jpeg_finish_decompress(&p_sys->p_jpeg);
576     jpeg_destroy_decompress(&p_sys->p_jpeg);
577     free(p_sys->p_row_pointers);
578
579     p_pic->date = p_block->i_pts != VLC_TICK_INVALID ? p_block->i_pts : p_block->i_dts;
580
581     block_Release(p_block);
582     decoder_QueueVideo( p_dec, p_pic );
583     return VLCDEC_SUCCESS;
584
585 error:
586
587     jpeg_destroy_decompress(&p_sys->p_jpeg);
588     free(p_sys->p_row_pointers);
589
590     block_Release(p_block);
591     return VLCDEC_SUCCESS;
592 }
593
594 /*
595  * jpeg decoder destruction
596  */
597 static void CloseDecoder(vlc_object_t *p_this)
598 {
599     decoder_t *p_dec = (decoder_t *)p_this;
600     decoder_sys_t *p_sys = p_dec->p_sys;
601
602     free(p_sys);
603 }
604
605 /*
606  * Probe the encoder and return score
607  */
608 static int OpenEncoder(vlc_object_t *p_this)
609 {
610     encoder_t *p_enc = (encoder_t *)p_this;
611
612     config_ChainParse(p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg);
613
614     if (p_enc->fmt_out.i_codec != VLC_CODEC_JPEG)
615     {
616         return VLC_EGENERIC;
617     }
618
619     /* Allocate the memory needed to store encoder's structure */
620     encoder_sys_t *p_sys = malloc(sizeof(encoder_sys_t));
621     if (p_sys == NULL)
622     {
623         return VLC_ENOMEM;
624     }
625
626     p_enc->p_sys = p_sys;
627
628     p_sys->p_obj = p_this;
629
630     p_sys->p_jpeg.err = jpeg_std_error(&p_sys->err);
631     p_sys->err.error_exit = user_error_exit;
632     p_sys->err.output_message = user_error_message;
633
634     p_sys->i_quality = var_GetInteger(p_enc, ENC_CFG_PREFIX "quality");
635     p_sys->i_blocksize = 3 * p_enc->fmt_in.video.i_visible_width * p_enc->fmt_in.video.i_visible_height;
636
637     p_enc->fmt_in.i_codec = VLC_CODEC_J420;
638     p_enc->pf_encode_video = EncodeBlock;
639
640     return VLC_SUCCESS;
641 }
642
643 /*
644  * EncodeBlock
645  */
646 static block_t *EncodeBlock(encoder_t *p_enc, picture_t *p_pic)
647 {
648     encoder_sys_t *p_sys = p_enc->p_sys;
649
650     if (unlikely(!p_pic))
651     {
652         return NULL;
653     }
654     block_t *p_block = block_Alloc(p_sys->i_blocksize);
655     if (p_block == NULL)
656     {
657         return NULL;
658     }
659
660     JSAMPIMAGE p_row_pointers = NULL;
661     unsigned long size = p_block->i_buffer;
662
663     /* libjpeg longjmp's there in case of error */
664     if (setjmp(p_sys->setjmp_buffer))
665     {
666         goto error;
667     }
668
669     jpeg_create_compress(&p_sys->p_jpeg);
670     jpeg_mem_dest(&p_sys->p_jpeg, &p_block->p_buffer, &size);
671
672     p_sys->p_jpeg.image_width = p_enc->fmt_in.video.i_visible_width;
673     p_sys->p_jpeg.image_height = p_enc->fmt_in.video.i_visible_height;
674     p_sys->p_jpeg.input_components = 3;
675     p_sys->p_jpeg.in_color_space = JCS_YCbCr;
676
677     jpeg_set_defaults(&p_sys->p_jpeg);
678     jpeg_set_colorspace(&p_sys->p_jpeg, JCS_YCbCr);
679
680     p_sys->p_jpeg.raw_data_in = TRUE;
681 #if JPEG_LIB_VERSION >= 70
682     p_sys->p_jpeg.do_fancy_downsampling = FALSE;
683 #endif
684
685     jpeg_set_quality(&p_sys->p_jpeg, p_sys->i_quality, TRUE);
686
687     jpeg_start_compress(&p_sys->p_jpeg, TRUE);
688
689     /* Encode picture */
690     p_row_pointers = vlc_alloc(p_pic->i_planes, sizeof(JSAMPARRAY));
691     if (p_row_pointers == NULL)
692     {
693         goto error;
694     }
695
696     for (int i = 0; i < p_pic->i_planes; i++)
697     {
698         p_row_pointers[i] = vlc_alloc(p_sys->p_jpeg.comp_info[i].v_samp_factor, sizeof(JSAMPROW) * DCTSIZE);
699     }
700
701     while (p_sys->p_jpeg.next_scanline < p_sys->p_jpeg.image_height)
702     {
703         for (int i = 0; i < p_pic->i_planes; i++)
704         {
705             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;
706
707             for (int j = 0; j < p_sys->p_jpeg.comp_info[i].v_samp_factor * DCTSIZE; j++)
708             {
709                 p_row_pointers[i][j] = p_pic->p[i].p_pixels + p_pic->p[i].i_pitch * (i_offset + j);
710             }
711         }
712         jpeg_write_raw_data(&p_sys->p_jpeg, p_row_pointers, p_sys->p_jpeg.max_v_samp_factor * DCTSIZE);
713     }
714
715     jpeg_finish_compress(&p_sys->p_jpeg);
716     jpeg_destroy_compress(&p_sys->p_jpeg);
717
718     for (int i = 0; i < p_pic->i_planes; i++)
719     {
720         free(p_row_pointers[i]);
721     }
722     free(p_row_pointers);
723
724     p_block->i_buffer = size;
725     p_block->i_dts = p_block->i_pts = p_pic->date;
726
727     return p_block;
728
729 error:
730     jpeg_destroy_compress(&p_sys->p_jpeg);
731
732     if (p_row_pointers != NULL)
733     {
734         for (int i = 0; i < p_pic->i_planes; i++)
735         {
736             free(p_row_pointers[i]);
737         }
738     }
739     free(p_row_pointers);
740
741     block_Release(p_block);
742
743     return NULL;
744 }
745
746 /*
747  * jpeg encoder destruction
748  */
749 static void CloseEncoder(vlc_object_t *p_this)
750 {
751     encoder_t *p_enc = (encoder_t *)p_this;
752     encoder_sys_t *p_sys = p_enc->p_sys;
753
754     free(p_sys);
755 }