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