qml: remove context indicator
[vlc.git] / modules / codec / jpeg.c
blob486502b2113c620a5370d0ff38a0c18c4d5da780
1 /*****************************************************************************
2 * jpeg.c: jpeg decoder module making use of libjpeg.
3 *****************************************************************************
4 * Copyright (C) 2013-2014,2016 VLC authors and VideoLAN
6 * Authors: Maxim Bublis <b@codemonkey.ru>
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.
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.
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 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 #include <vlc_common.h>
28 #include <vlc_plugin.h>
29 #include <vlc_codec.h>
30 #include <vlc_charset.h>
32 #include <jpeglib.h>
33 #include <setjmp.h>
35 /* JPEG_SYS_COMMON_MEMBERS:
36 * members common to encoder and decoder descriptors
38 #define JPEG_SYS_COMMON_MEMBERS \
39 /**@{*/ \
40 /* libjpeg error handler manager */ \
41 struct jpeg_error_mgr err; \
43 /* setjmp buffer for internal libjpeg error handling */ \
44 jmp_buf setjmp_buffer; \
46 vlc_object_t *p_obj; \
48 /**@}*/ \
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).")
57 * jpeg common descriptor
59 struct jpeg_sys_t
61 JPEG_SYS_COMMON_MEMBERS
64 typedef struct jpeg_sys_t jpeg_sys_t;
67 * jpeg decoder descriptor
69 typedef struct
71 JPEG_SYS_COMMON_MEMBERS
73 JSAMPARRAY p_row_pointers;
74 struct jpeg_decompress_struct p_jpeg;
75 } decoder_sys_t;
77 static int OpenDecoder(vlc_object_t *);
78 static void CloseDecoder(vlc_object_t *);
80 static int DecodeBlock(decoder_t *, block_t *);
83 * jpeg encoder descriptor
85 typedef struct
87 JPEG_SYS_COMMON_MEMBERS
89 struct jpeg_compress_struct p_jpeg;
91 int i_blocksize;
92 int i_quality;
93 } encoder_sys_t;
95 static const char * const ppsz_enc_options[] = {
96 "quality",
97 NULL
100 static int OpenEncoder(vlc_object_t *);
101 static void CloseEncoder(vlc_object_t *);
103 static block_t *EncodeBlock(encoder_t *, picture_t *);
106 * Module descriptor
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")
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()
130 * Exit error handler for libjpeg
132 static void user_error_exit(j_common_ptr p_jpeg)
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);
140 * Emit message error handler for libjpeg
142 static void user_error_message(j_common_ptr p_jpeg)
144 char error_msg[JMSG_LENGTH_MAX];
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);
152 * Probe the decoder and return score
154 static int OpenDecoder(vlc_object_t *p_this)
156 decoder_t *p_dec = (decoder_t *)p_this;
158 if (p_dec->fmt_in.i_codec != VLC_CODEC_JPEG)
160 return VLC_EGENERIC;
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)
167 return VLC_ENOMEM;
170 p_dec->p_sys = p_sys;
172 p_sys->p_obj = p_this;
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;
178 /* Set callbacks */
179 p_dec->pf_decode = DecodeBlock;
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);
189 return VLC_SUCCESS;
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
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.
209 * The claim is made that this is the best way to do it. Can you do better?
212 #define G_LITTLE_ENDIAN 1234
213 #define G_BIG_ENDIAN 4321
215 typedef unsigned int uint;
216 typedef unsigned short ushort;
218 LOCAL( unsigned short )
219 de_get16( void * ptr, uint endian ) {
220 unsigned short val;
222 memcpy( &val, ptr, sizeof( val ) );
223 if ( endian == G_BIG_ENDIAN )
225 #ifndef WORDS_BIGENDIAN
226 val = vlc_bswap16( val );
227 #endif
229 else
231 #ifdef WORDS_BIGENDIAN
232 val = vlc_bswap16( val );
233 #endif
235 return val;
238 LOCAL( unsigned int )
239 de_get32( void * ptr, uint endian ) {
240 unsigned int val;
242 memcpy( &val, ptr, sizeof( val ) );
243 if ( endian == G_BIG_ENDIAN )
245 #ifndef WORDS_BIGENDIAN
246 val = vlc_bswap32( val );
247 #endif
249 else
251 #ifdef WORDS_BIGENDIAN
252 val = vlc_bswap32( val );
253 #endif
255 return val;
258 static bool getRDFFloat(const char *psz_rdf, float *out, const char *psz_var)
260 char *p_start = strcasestr(psz_rdf, psz_var);
261 if (p_start == NULL)
262 return false;
264 size_t varlen = strlen(psz_var);
265 p_start += varlen;
266 char *p_end = NULL;
267 /* XML style */
268 if (p_start[0] == '>')
270 p_start += 1;
271 p_end = strchr(p_start, '<');
273 else if (p_start[0] == '=' && p_start[1] == '"')
275 p_start += 2;
276 p_end = strchr(p_start, '"');
278 if (unlikely(p_end == NULL || p_end == p_start + 1))
279 return false;
281 *out = us_strtof(p_start, NULL);
282 return true;
285 #define EXIF_JPEG_MARKER 0xE1
286 #define EXIF_XMP_STRING "http://ns.adobe.com/xap/1.0/\000"
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)
292 jpeg_saved_marker_ptr xmp_marker = NULL;
293 jpeg_saved_marker_ptr cmarker = cinfo->marker_list;
295 while (cmarker)
297 if (cmarker->marker == EXIF_JPEG_MARKER)
299 if(cmarker->data_length >= 32 &&
300 !memcmp(cmarker->data, EXIF_XMP_STRING, 29))
302 xmp_marker = cmarker;
303 break;
306 cmarker = cmarker->next;
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';
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;
323 /* pose handling */
324 float value;
325 if (getRDFFloat(psz_rdf, &value, "PoseHeadingDegrees"))
326 fmt->pose.yaw = value;
328 if (getRDFFloat(psz_rdf, &value, "PosePitchDegrees"))
329 fmt->pose.pitch = value;
331 if (getRDFFloat(psz_rdf, &value, "PoseRollDegrees"))
332 fmt->pose.roll = value;
334 /* initial view */
335 if (getRDFFloat(psz_rdf, &value, "InitialViewHeadingDegrees"))
336 fmt->pose.yaw = value;
338 if (getRDFFloat(psz_rdf, &value, "InitialViewPitchDegrees"))
339 fmt->pose.pitch = value;
341 if (getRDFFloat(psz_rdf, &value, "InitialViewRollDegrees"))
342 fmt->pose.roll = value;
344 if (getRDFFloat(psz_rdf, &value, "InitialHorizontalFOVDegrees"))
345 fmt->pose.fov = value;
347 free(psz_rdf);
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
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
359 LOCAL( int )
360 jpeg_GetOrientation( j_decompress_ptr cinfo )
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 */
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 */
376 const char leth[] = { 0x49, 0x49, 0x2a, 0x00 }; /* Little endian TIFF header */
377 const char beth[] = { 0x4d, 0x4d, 0x00, 0x2a }; /* Big endian TIFF header */
379 #define EXIF_IDENT_STRING "Exif\000\000"
380 #define EXIF_ORIENT_TAGID 0x112
382 /* check for Exif marker (also called the APP1 marker) */
383 exif_marker = NULL;
384 cmarker = cinfo->marker_list;
386 while ( cmarker )
388 if ( cmarker->data_length >= 32 &&
389 cmarker->marker == EXIF_JPEG_MARKER )
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 ) )
395 exif_marker = cmarker;
398 cmarker = cmarker->next;
401 /* Did we find the Exif APP1 marker? */
402 if ( exif_marker == NULL )
403 return 0;
405 /* Check for TIFF header and catch endianess */
406 i = 0;
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
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.
423 while ( i < 16 )
425 /* Little endian TIFF header */
426 if ( memcmp( &exif_marker->data[i], leth, 4 ) == 0 )
428 endian = G_LITTLE_ENDIAN;
430 /* Big endian TIFF header */
431 else
432 if ( memcmp( &exif_marker->data[i], beth, 4 ) == 0 )
434 endian = G_BIG_ENDIAN;
436 /* Keep looking through buffer */
437 else
439 i++;
440 continue;
442 /* We have found either big or little endian TIFF header */
443 tiff = i;
444 break;
447 /* So did we find a TIFF header or did we just hit end of buffer? */
448 if ( tiff == 0 )
449 return 0;
451 /* Read out the offset pointer to IFD0 */
452 offset = de_get32( &exif_marker->data[i] + 4, endian );
453 i = i + offset;
455 /* Check that we still are within the buffer and can read the tag count */
457 if ( i > exif_marker->data_length - 2 )
458 return 0;
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;
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;
471 /* Check through IFD0 for tags of interest */
472 while ( tags-- )
474 tag_type = de_get16( &exif_marker->data[i], endian );
475 /* Is this the orientation tag? */
476 if ( tag_type == EXIF_ORIENT_TAGID )
478 type = de_get16( &exif_marker->data[i + 2], endian );
479 count = de_get32( &exif_marker->data[i + 4], endian );
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;
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;
491 /* move the pointer to the next 12-byte tag field. */
492 i = i + 12;
495 return 0; /* No EXIF Orientation tag found */
499 * This function must be fed with a complete compressed frame.
501 static int DecodeBlock(decoder_t *p_dec, block_t *p_block)
503 decoder_sys_t *p_sys = p_dec->p_sys;
504 picture_t *p_pic = 0;
506 p_sys->p_row_pointers = NULL;
508 if (!p_block) /* No Drain */
509 return VLCDEC_SUCCESS;
511 if (p_block->i_flags & BLOCK_FLAG_CORRUPTED )
513 block_Release(p_block);
514 return VLCDEC_SUCCESS;
517 /* libjpeg longjmp's there in case of error */
518 if (setjmp(p_sys->setjmp_buffer))
520 goto error;
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);
528 p_sys->p_jpeg.out_color_space = JCS_RGB;
530 jpeg_start_decompress(&p_sys->p_jpeg);
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;
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 )
542 msg_Dbg( p_dec, "Jpeg orientation is %d", i_otag );
543 p_dec->fmt_out.video.orientation = ORIENT_FROM_EXIF( i_otag );
545 jpeg_GetProjection(&p_sys->p_jpeg, &p_dec->fmt_out.video);
547 /* Get a new picture */
548 if (decoder_UpdateVideoFormat(p_dec))
550 goto error;
552 p_pic = decoder_NewPicture(p_dec);
553 if (!p_pic)
555 goto error;
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)
562 goto error;
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;
568 while (p_sys->p_jpeg.output_scanline < p_sys->p_jpeg.output_height)
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);
575 jpeg_finish_decompress(&p_sys->p_jpeg);
576 jpeg_destroy_decompress(&p_sys->p_jpeg);
577 free(p_sys->p_row_pointers);
579 p_pic->date = p_block->i_pts != VLC_TICK_INVALID ? p_block->i_pts : p_block->i_dts;
581 block_Release(p_block);
582 decoder_QueueVideo( p_dec, p_pic );
583 return VLCDEC_SUCCESS;
585 error:
587 jpeg_destroy_decompress(&p_sys->p_jpeg);
588 free(p_sys->p_row_pointers);
590 block_Release(p_block);
591 return VLCDEC_SUCCESS;
595 * jpeg decoder destruction
597 static void CloseDecoder(vlc_object_t *p_this)
599 decoder_t *p_dec = (decoder_t *)p_this;
600 decoder_sys_t *p_sys = p_dec->p_sys;
602 free(p_sys);
606 * Probe the encoder and return score
608 static int OpenEncoder(vlc_object_t *p_this)
610 encoder_t *p_enc = (encoder_t *)p_this;
612 config_ChainParse(p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg);
614 if (p_enc->fmt_out.i_codec != VLC_CODEC_JPEG)
616 return VLC_EGENERIC;
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)
623 return VLC_ENOMEM;
626 p_enc->p_sys = p_sys;
628 p_sys->p_obj = p_this;
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;
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;
637 p_enc->fmt_in.i_codec = VLC_CODEC_J420;
638 p_enc->pf_encode_video = EncodeBlock;
640 return VLC_SUCCESS;
644 * EncodeBlock
646 static block_t *EncodeBlock(encoder_t *p_enc, picture_t *p_pic)
648 encoder_sys_t *p_sys = p_enc->p_sys;
650 if (unlikely(!p_pic))
652 return NULL;
654 block_t *p_block = block_Alloc(p_sys->i_blocksize);
655 if (p_block == NULL)
657 return NULL;
660 JSAMPIMAGE p_row_pointers = NULL;
661 unsigned long size = p_block->i_buffer;
663 /* libjpeg longjmp's there in case of error */
664 if (setjmp(p_sys->setjmp_buffer))
666 goto error;
669 jpeg_create_compress(&p_sys->p_jpeg);
670 jpeg_mem_dest(&p_sys->p_jpeg, &p_block->p_buffer, &size);
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;
677 jpeg_set_defaults(&p_sys->p_jpeg);
678 jpeg_set_colorspace(&p_sys->p_jpeg, JCS_YCbCr);
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
685 jpeg_set_quality(&p_sys->p_jpeg, p_sys->i_quality, TRUE);
687 jpeg_start_compress(&p_sys->p_jpeg, TRUE);
689 /* Encode picture */
690 p_row_pointers = vlc_alloc(p_pic->i_planes, sizeof(JSAMPARRAY));
691 if (p_row_pointers == NULL)
693 goto error;
696 for (int i = 0; i < p_pic->i_planes; i++)
698 p_row_pointers[i] = vlc_alloc(p_sys->p_jpeg.comp_info[i].v_samp_factor, sizeof(JSAMPROW) * DCTSIZE);
701 while (p_sys->p_jpeg.next_scanline < p_sys->p_jpeg.image_height)
703 for (int i = 0; i < p_pic->i_planes; i++)
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;
707 for (int j = 0; j < p_sys->p_jpeg.comp_info[i].v_samp_factor * DCTSIZE; j++)
709 p_row_pointers[i][j] = p_pic->p[i].p_pixels + p_pic->p[i].i_pitch * (i_offset + j);
712 jpeg_write_raw_data(&p_sys->p_jpeg, p_row_pointers, p_sys->p_jpeg.max_v_samp_factor * DCTSIZE);
715 jpeg_finish_compress(&p_sys->p_jpeg);
716 jpeg_destroy_compress(&p_sys->p_jpeg);
718 for (int i = 0; i < p_pic->i_planes; i++)
720 free(p_row_pointers[i]);
722 free(p_row_pointers);
724 p_block->i_buffer = size;
725 p_block->i_dts = p_block->i_pts = p_pic->date;
727 return p_block;
729 error:
730 jpeg_destroy_compress(&p_sys->p_jpeg);
732 if (p_row_pointers != NULL)
734 for (int i = 0; i < p_pic->i_planes; i++)
736 free(p_row_pointers[i]);
739 free(p_row_pointers);
741 block_Release(p_block);
743 return NULL;
747 * jpeg encoder destruction
749 static void CloseEncoder(vlc_object_t *p_this)
751 encoder_t *p_enc = (encoder_t *)p_this;
752 encoder_sys_t *p_sys = p_enc->p_sys;
754 free(p_sys);