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