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