<div dir="ltr"><div><div>Update patch to<br></div>a) reflect correction to ORIENT_FROM_EXIF <br></div>b) avoid unnecessary call to ORIENT_FROM_EXIF when normal orientation or no orientation tag (most common cases)<br><br>[PATCH] Automatically orient JPEG images using embedded orientation tag, if present<br><br>---<br> modules/codec/jpeg.c | 242 ++++++++++++++++++++++++++++++++++++++++++++++++++-<br> 1 file changed, 241 insertions(+), 1 deletion(-)<br><br>diff --git a/modules/codec/jpeg.c b/modules/codec/jpeg.c<br>index fdb91c7..1e275cd 100644<br>--- a/modules/codec/jpeg.c<br>+++ b/modules/codec/jpeg.c<br>@@ -1,7 +1,7 @@<br> /*****************************************************************************<br> * jpeg.c: jpeg decoder module making use of libjpeg.<br> *****************************************************************************<br>- * Copyright (C) 2013-2014 VLC authors and VideoLAN<br>+ * Copyright (C) 2013-2014,2016 VLC authors and VideoLAN<br> *<br> * Authors: Maxim Bublis <<a href="mailto:b@codemonkey.ru">b@codemonkey.ru</a>><br> *<br>@@ -50,6 +50,22 @@<br> #define ENC_QUALITY_LONGTEXT N_("Quality level " \<br> "for encoding (this can enlarge or reduce output image size).")<br> <br>+#define DEC_CFG_PREFIX "jpeg-"<br>+#define DEC_AUTOORIENT_TEXT N_( "Automatic Orientation" )<br>+#define DEC_AUTOORIENT_LONGTEXT N_( "Automatic rotation based on EXIF orientation tag." )<br>+<br>+const char leth[] = {<br>+ 0x49, 0x49, 0x2a, 0x00<br>+}; // Little endian TIFF header<br>+const char beth[] = {<br>+ 0x4d, 0x4d, 0x00, 0x2a<br>+}; // Big endian TIFF header<br>+<br>+#define G_LITTLE_ENDIAN 1234<br>+#define G_BIG_ENDIAN 4321<br>+<br>+#define EXIF_JPEG_MARKER 0xE1<br>+#define EXIF_IDENT_STRING "Exif\000\000"<br> <br> /*<br> * jpeg common descriptor<br>@@ -110,6 +126,13 @@ vlc_module_begin()<br> set_capability("decoder", 1000)<br> set_callbacks(OpenDecoder, CloseDecoder)<br> add_shortcut("jpeg")<br>+ /*<br>+ * Some JPEG get transformed to a normal orientation without resetting<br>+ * embedded orientation tag to reflect that.<br>+ * Allow disabling of autoorientation in case we have to work with such images.<br>+ */<br>+ add_bool( DEC_CFG_PREFIX "autoorient", true,<br>+ DEC_AUTOORIENT_TEXT, DEC_AUTOORIENT_LONGTEXT, true )<br> <br> /* encoder submodule */<br> add_submodule()<br>@@ -181,6 +204,201 @@ static int OpenDecoder(vlc_object_t *p_this)<br> return VLC_SUCCESS;<br> }<br> <br>+/* The EXIF headers in JPEG are based on TIFF and so<br>+ * may be in big endian or little endian format. We may be on a<br>+ * big endian machine or little endian machine.<br>+ * The following functions swap our 2 and 4 byte pairs, depending<br>+ * on which of the 4 possibilities we are dealing with.<br>+ * endian parameter tells us the source format, and WORDS_BIGENDIAN<br>+ * tells us how the machine we are running on stores that source<br>+ * format.<br>+*/<br>+<br>+LOCAL( unsigned short )<br>+de_get16( void * ptr, uint endian ) {<br>+ unsigned short val;<br>+<br>+ memcpy( &val, ptr, sizeof( val ) );<br>+ if ( endian == G_BIG_ENDIAN )<br>+ {<br>+ #ifndef WORDS_BIGENDIAN<br>+ val = bswap16( val );<br>+ #endif<br>+ }<br>+ else<br>+ {<br>+ #ifdef WORDS_BIGENDIAN<br>+ val = bswap16( val );<br>+ #endif<br>+ }<br>+ return val;<br>+}<br>+<br>+LOCAL( unsigned int )<br>+de_get32( void * ptr, uint endian ) {<br>+ unsigned int val;<br>+<br>+ memcpy( &val, ptr, sizeof( val ) );<br>+ if ( endian == G_BIG_ENDIAN )<br>+ {<br>+ #ifndef WORDS_BIGENDIAN<br>+ val = bswap32( val );<br>+ #endif<br>+ }<br>+ else<br>+ {<br>+ #ifdef WORDS_BIGENDIAN<br>+ val = bswap32( val );<br>+ #endif<br>+ }<br>+ return val;<br>+}<br>+<br>+/* jpeg_GetOrientation function based on code from GdkPixbuf library - JPEG image loader<br>+ * <a href="http://src.gnu-darwin.org/ports/x11-toolkits/gtk20/work/gtk+-2.12.3/gdk-pixbuf/io-jpeg.c">http://src.gnu-darwin.org/ports/x11-toolkits/gtk20/work/gtk+-2.12.3/gdk-pixbuf/io-jpeg.c</a><br>+ *<br>+ * Copyright (C) 1999 Michael Zucchi<br>+ * Copyright (C) 1999 The Free Software Foundation<br>+ */<br>+<br>+LOCAL( int )<br>+jpeg_GetOrientation( j_decompress_ptr cinfo ) {<br>+ /* This function looks through the meta data in the libjpeg decompress structure to<br>+ determine if an EXIF Orientation tag is present and if so return its value (1-8).<br>+ If no EXIF Orientation tag is found, 0 is returned. */<br>+<br>+ uint i; /* index into working buffer */<br>+ ushort tag_type; /* endianed tag type extracted from tiff header */<br>+ uint ret; /* Return value */<br>+ uint offset; /* de-endianed offset in various situations */<br>+ uint tags; /* number of tags in current ifd */<br>+ uint type; /* de-endianed type of tag */<br>+ uint count; /* de-endianed count of elements in a tag */<br>+ uint tiff = 0; /* offset to active tiff header */<br>+ uint endian = 0; /* detected endian of data */<br>+<br>+ jpeg_saved_marker_ptr exif_marker; /* Location of the Exif APP1 marker */<br>+ jpeg_saved_marker_ptr cmarker; /* Location to check for Exif APP1 marker */<br>+<br>+ /* check for Exif marker (also called the APP1 marker) */<br>+ exif_marker = NULL;<br>+ cmarker = cinfo->marker_list;<br>+<br>+ while ( cmarker )<br>+ {<br>+ if ( cmarker->marker == EXIF_JPEG_MARKER )<br>+ {<br>+ /* The Exif APP1 marker should contain a unique<br>+ identification string ("Exif\0\0"). Check for it. */<br>+ if ( !memcmp( cmarker->data, EXIF_IDENT_STRING, 6 ) )<br>+ {<br>+ exif_marker = cmarker;<br>+ }<br>+ }<br>+ cmarker = cmarker->next;<br>+ }<br>+<br>+ /* Did we find the Exif APP1 marker? */<br>+ if ( exif_marker == NULL )<br>+ return 0;<br>+<br>+ /* Do we have enough data? */<br>+ if ( exif_marker->data_length < 32 )<br>+ return 0;<br>+<br>+ /* Check for TIFF header and catch endianess */<br>+ i = 0;<br>+<br>+ /* Just skip data until TIFF header - it should be within 16 bytes from marker start.<br>+ Normal structure relative to APP1 marker -<br>+ 0x0000: APP1 marker entry = 2 bytes<br>+ 0x0002: APP1 length entry = 2 bytes<br>+ 0x0004: Exif Identifier entry = 6 bytes<br>+ 0x000A: Start of TIFF header (Byte order entry) - 4 bytes<br>+ - This is what we look for, to determine endianess.<br>+ 0x000E: 0th IFD offset pointer - 4 bytes<br>+<br>+ exif_marker->data points to the first data after the APP1 marker<br>+ and length entries, which is the exif identification string.<br>+ The TIFF header should thus normally be found at i=6, below,<br>+ and the pointer to IFD0 will be at 6+4 = 10.<br>+ */<br>+<br>+ while ( i < 16 )<br>+ {<br>+ /* Little endian TIFF header */<br>+ if ( memcmp( &exif_marker->data[i], leth, 4 ) == 0 )<br>+ {<br>+ endian = G_LITTLE_ENDIAN;<br>+ }<br>+ /* Big endian TIFF header */<br>+ else<br>+ if ( memcmp( &exif_marker->data[i], beth, 4 ) == 0 )<br>+ {<br>+ endian = G_BIG_ENDIAN;<br>+ }<br>+ /* Keep looking through buffer */<br>+ else<br>+ {<br>+ i++;<br>+ continue;<br>+ }<br>+ /* We have found either big or little endian TIFF header */<br>+ tiff = i;<br>+ break;<br>+ }<br>+<br>+ /* So did we find a TIFF header or did we just hit end of buffer? */<br>+ if ( tiff == 0 )<br>+ return 0;<br>+<br>+ /* Read out the offset pointer to IFD0 */<br>+ offset = de_get32( &exif_marker->data[i] + 4, endian );<br>+ i = i + offset;<br>+<br>+ /* Check that we still are within the buffer and can read the tag count */<br>+<br>+ if ( ( i + 2 ) > exif_marker->data_length )<br>+ return 0;<br>+<br>+ /* Find out how many tags we have in IFD0. As per the TIFF spec, the first<br>+ two bytes of the IFD contain a count of the number of tags. */<br>+ tags = de_get16( &exif_marker->data[i], endian );<br>+ i = i + 2;<br>+<br>+ /* Check that we still have enough data for all tags to check. The tags<br>+ are listed in consecutive 12-byte blocks. The tag ID, type, size, and<br>+ a pointer to the actual value, are packed into these 12 byte entries. */<br>+ if ( ( i + tags * 12 ) > exif_marker->data_length )<br>+ return 0;<br>+<br>+ /* Check through IFD0 for tags of interest */<br>+ while ( tags-- )<br>+ {<br>+ tag_type = de_get16( &exif_marker->data[i], endian );<br>+ /* Is this the orientation tag? */<br>+ if ( tag_type == 0x112 )<br>+ {<br>+ type = de_get16( &exif_marker->data[i + 2], endian );<br>+ count = de_get32( &exif_marker->data[i + 4], endian );<br>+<br>+ /* Check that type and count fields are OK. The orientation field<br>+ will consist of a single (count=1) 2-byte integer (type=3). */<br>+ if ( type != 3 || count != 1 )<br>+ return 0;<br>+<br>+ /* Return the orientation value. Within the 12-byte block, the<br>+ pointer to the actual data is at offset 8. */<br>+ ret = de_get16( &exif_marker->data[i + 8], endian );<br>+ return ( ret <= 8 ) ? ret : 0;<br>+ }<br>+ /* move the pointer to the next 12-byte tag field. */<br>+ i = i + 12;<br>+ }<br>+<br>+ return 0; /* No EXIF Orientation tag found */<br>+}<br>+<br> /*<br> * This function must be fed with a complete compressed frame.<br> */<br>@@ -192,6 +410,9 @@ static picture_t *DecodeBlock(decoder_t *p_dec, block_t **pp_block)<br> <br> JSAMPARRAY p_row_pointers = NULL;<br> <br>+ bool b_autoorient;<br>+ int i_otag;<br>+<br> if (!pp_block || !*pp_block)<br> {<br> return NULL;<br>@@ -214,6 +435,13 @@ static picture_t *DecodeBlock(decoder_t *p_dec, block_t **pp_block)<br> <br> jpeg_create_decompress(&p_sys->p_jpeg);<br> jpeg_mem_src(&p_sys->p_jpeg, p_block->p_buffer, p_block->i_buffer);<br>+ b_autoorient = var_InheritBool( p_dec, "jpeg-autoorient" );<br>+<br>+ if ( b_autoorient )<br>+ {<br>+ jpeg_save_markers( &p_sys->p_jpeg, EXIF_JPEG_MARKER, 0xffff );<br>+ }<br>+<br> jpeg_read_header(&p_sys->p_jpeg, TRUE);<br> <br> p_sys->p_jpeg.out_color_space = JCS_RGB;<br>@@ -229,6 +457,18 @@ static picture_t *DecodeBlock(decoder_t *p_dec, block_t **pp_block)<br> p_dec->fmt_out.video.i_rmask = 0x000000ff;<br> p_dec->fmt_out.video.i_gmask = 0x0000ff00;<br> p_dec->fmt_out.video.i_bmask = 0x00ff0000;<br>+ if ( b_autoorient )<br>+ {<br>+ i_otag = jpeg_GetOrientation( &p_sys->p_jpeg );<br>+ /*<br>+ * Orientation tag has valid range of 1-8. 1 is normal orientation.<br>+ */<br>+ if ( i_otag > 1 )<br>+ {<br>+ msg_Info( p_dec, "Orientation is %d", i_otag );<br>+ p_dec->fmt_out.video.orientation = ORIENT_FROM_EXIF( i_otag );<br>+ }<br>+ }<br> <br> /* Get a new picture */<br> p_pic = decoder_NewPicture(p_dec);<br>-- <br>2.7.4<br><br></div><div class="gmail_extra"><br><div class="gmail_quote">On 18 April 2016 at 08:06, Wayne McDougall <span dir="ltr"><<a href="mailto:waynemcdougall@gmail.com" target="_blank">waynemcdougall@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div><div>Please find an update patch:<br>[PATCH] Automatically orient JPEG images using orientation tag, if present<br><br></div>Addressed:<br><span name="Rémi Denis-Courmont"> Rémi's </span>ORIENT_FROM_EXIF - although I think the values supplied are in reverse order<br></div> Jean-Baptiste's <span>var_InheritBool<br><br></span></div><span>Comments added to address...<br> </span>Jean-Baptiste's <span>question as to whether it needs to be optional. I think yes it does.<br></span><span> </span>Jean-Baptiste's <span>suggestion to use existing big/little endian functions. I don't think they apply<br> because JPEG's tags can come in either format.</span><br><br>---<br><div><div><div> modules/codec/jpeg.c | 239 ++++++++++++++++++++++++++++++++++++++++++++++++++-<br> 1 file changed, 235 insertions(+), 4 deletions(-)<br><br>diff --git a/modules/codec/jpeg.c b/modules/codec/jpeg.c<br>index 0e3ae9d..d540365 100644<span class=""><br>--- a/modules/codec/jpeg.c<br>+++ b/modules/codec/jpeg.c<br>@@ -1,7 +1,7 @@<br> /*****************************************************************************<br> * jpeg.c: jpeg decoder module making use of libjpeg.<br> *****************************************************************************<br>- * Copyright (C) 2013-2014 VLC authors and VideoLAN<br>+ * Copyright (C) 2013-2014,2016 VLC authors and VideoLAN<br> *<br> * Authors: Maxim Bublis <<a href="mailto:b@codemonkey.ru" target="_blank">b@codemonkey.ru</a>><br> *<br>@@ -50,6 +50,22 @@<br> #define ENC_QUALITY_LONGTEXT N_( "Quality level " \<br> "for encoding (this can enlarge or reduce output image size)." )<br> <br></span><span class="">+#define DEC_CFG_PREFIX "jpeg-"<br>+#define DEC_AUTOORIENT_TEXT N_( "Automatic Orientation" )<br></span>+#define DEC_AUTOORIENT_LONGTEXT N_( "Automatic rotation based on EXIF orientation tag." )<span class=""><br>+<br>+const char leth[] = {<br>+ 0x49, 0x49, 0x2a, 0x00<br>+}; // Little endian TIFF header<br>+const char beth[] = {<br>+ 0x4d, 0x4d, 0x00, 0x2a<br>+}; // Big endian TIFF header<br>+<br>+#define G_LITTLE_ENDIAN 1234<br>+#define G_BIG_ENDIAN 4321<br>+<br>+#define EXIF_JPEG_MARKER 0xE1<br>+#define EXIF_IDENT_STRING "Exif\000\000"<br> <br> /*<br> * jpeg common descriptor<br></span>@@ -107,6 +123,13 @@ set_description( N_( "JPEG image decoder" ) )<span class=""><br> set_capability( "decoder", 1000 )<br> set_callbacks( OpenDecoder, CloseDecoder )<br> add_shortcut( "jpeg" )<br></span>+/*<br>+ * Some JPEG get transformed to a normal orientation without resetting<br>+ * embedded orientation tag to reflect that.<br>+ * Allow disabling of autoorientation in case we have to work with such images.<br>+*/<span class=""><br>+add_bool( DEC_CFG_PREFIX "autoorient", true,<br>+ DEC_AUTOORIENT_TEXT, DEC_AUTOORIENT_LONGTEXT, true )<br> <br> /* encoder submodule */<br> add_submodule()<br></span>@@ -178,6 +201,201 @@ static int OpenDecoder ( vlc_object_t * p_this )<br> return VLC_SUCCESS;<br> }<br> <br>+/* The EXIF headers in JPEG are based on TIFF and so<br>+ * may be in big endian or little endian format. We may be on a<br>+ * big endian machine or little endian machine.<br>+ * The following functions swap our 2 and 4 byte pairs, depending<br>+ * on which of the 4 possibilities we are dealing with.<br>+ * endian parameter tells us the source format, and WORDS_BIGENDIAN<br>+ * tells us how the machine we are running on stores that source<br>+ * format.<br>+*/<br>+<div><div class="h5"><br>+LOCAL( unsigned short )<br>+de_get16( void * ptr, uint endian ) {<br>+ unsigned short val;<br>+<br>+ memcpy( &val, ptr, sizeof( val ) );<br>+ if ( endian == G_BIG_ENDIAN )<br>+ {<br>+ #ifndef WORDS_BIGENDIAN<br>+ val = bswap16( val );<br>+ #endif<br>+ }<br>+ else<br>+ {<br>+ #ifdef WORDS_BIGENDIAN<br>+ val = bswap16( val );<br>+ #endif<br>+ }<br>+ return val;<br>+}<br>+<br>+LOCAL( unsigned int )<br>+de_get32( void * ptr, uint endian ) {<br>+ unsigned int val;<br>+<br>+ memcpy( &val, ptr, sizeof( val ) );<br>+ if ( endian == G_BIG_ENDIAN )<br>+ {<br>+ #ifndef WORDS_BIGENDIAN<br>+ val = bswap32( val );<br>+ #endif<br>+ }<br>+ else<br>+ {<br>+ #ifdef WORDS_BIGENDIAN<br>+ val = bswap32( val );<br>+ #endif<br>+ }<br>+ return val;<br>+}<br></div></div>+<span class=""><br>+/* jpeg_GetOrientation function based on code from GdkPixbuf library - JPEG image loader<br>+ * <a href="http://src.gnu-darwin.org/ports/x11-toolkits/gtk20/work/gtk+-2.12.3/gdk-pixbuf/io-jpeg.c" target="_blank">http://src.gnu-darwin.org/ports/x11-toolkits/gtk20/work/gtk+-2.12.3/gdk-pixbuf/io-jpeg.c</a><br>+ *<br>+ * Copyright (C) 1999 Michael Zucchi<br>+ * Copyright (C) 1999 The Free Software Foundation<br>+ */<br>+<br>+LOCAL( int )<br>+jpeg_GetOrientation( j_decompress_ptr cinfo ) {<br>+ /* This function looks through the meta data in the libjpeg decompress structure to<br>+ determine if an EXIF Orientation tag is present and if so return its value (1-8).<br></span>+ If no EXIF Orientation tag is found, 1 (normal orientation) is returned. */<span class=""><br>+<br>+ uint i; /* index into working buffer */<br>+ ushort tag_type; /* endianed tag type extracted from tiff header */<br>+ uint ret; /* Return value */<br>+ uint offset; /* de-endianed offset in various situations */<br>+ uint tags; /* number of tags in current ifd */<br></span>+ uint type; /* de-endianed type of tag */<div><div class="h5"><br>+ uint count; /* de-endianed count of elements in a tag */<br>+ uint tiff = 0; /* offset to active tiff header */<br>+ uint endian = 0; /* detected endian of data */<br>+<br>+ jpeg_saved_marker_ptr exif_marker; /* Location of the Exif APP1 marker */<br>+ jpeg_saved_marker_ptr cmarker; /* Location to check for Exif APP1 marker */<br>+<br>+ /* check for Exif marker (also called the APP1 marker) */<br>+ exif_marker = NULL;<br>+ cmarker = cinfo->marker_list;<br>+<br>+ while ( cmarker )<br>+ {<br>+ if ( cmarker->marker == EXIF_JPEG_MARKER )<br>+ {<br>+ /* The Exif APP1 marker should contain a unique<br>+ identification string ("Exif\0\0"). Check for it. */<br>+ if ( !memcmp( cmarker->data, EXIF_IDENT_STRING, 6 ) )<br>+ {<br>+ exif_marker = cmarker;<br>+ }<br>+ }<br>+ cmarker = cmarker->next;<br>+ }<br>+<br>+ /* Did we find the Exif APP1 marker? */<br>+ if ( exif_marker == NULL )<br></div></div>+ return 1;<span class=""><br>+<br>+ /* Do we have enough data? */<br>+ if ( exif_marker->data_length < 32 )<br></span>+ return 1;<div><div class="h5"><br>+<br>+ /* Check for TIFF header and catch endianess */<br>+ i = 0;<br>+<br>+ /* Just skip data until TIFF header - it should be within 16 bytes from marker start.<br>+ Normal structure relative to APP1 marker -<br>+ 0x0000: APP1 marker entry = 2 bytes<br>+ 0x0002: APP1 length entry = 2 bytes<br>+ 0x0004: Exif Identifier entry = 6 bytes<br>+ 0x000A: Start of TIFF header (Byte order entry) - 4 bytes<br>+ - This is what we look for, to determine endianess.<br>+ 0x000E: 0th IFD offset pointer - 4 bytes<br>+<br>+ exif_marker->data points to the first data after the APP1 marker<br>+ and length entries, which is the exif identification string.<br>+ The TIFF header should thus normally be found at i=6, below,<br>+ and the pointer to IFD0 will be at 6+4 = 10.<br>+ */<br>+<br>+ while ( i < 16 )<br>+ {<br>+ /* Little endian TIFF header */<br>+ if ( memcmp( &exif_marker->data[i], leth, 4 ) == 0 )<br>+ {<br>+ endian = G_LITTLE_ENDIAN;<br>+ }<br>+ /* Big endian TIFF header */<br>+ else<br>+ if ( memcmp( &exif_marker->data[i], beth, 4 ) == 0 )<br>+ {<br>+ endian = G_BIG_ENDIAN;<br>+ }<br>+ /* Keep looking through buffer */<br>+ else<br>+ {<br>+ i++;<br>+ continue;<br>+ }<br>+ /* We have found either big or little endian TIFF header */<br>+ tiff = i;<br>+ break;<br>+ }<br>+<br>+ /* So did we find a TIFF header or did we just hit end of buffer? */<br>+ if ( tiff == 0 )<br></div></div>+ return 1;<span class=""><br>+<br>+ /* Read out the offset pointer to IFD0 */<br>+ offset = de_get32( &exif_marker->data[i] + 4, endian );<br>+ i = i + offset;<br>+<br>+ /* Check that we still are within the buffer and can read the tag count */<br>+<br>+ if ( ( i + 2 ) > exif_marker->data_length )<br></span>+ return 1;<span class=""><br>+<br>+ /* Find out how many tags we have in IFD0. As per the TIFF spec, the first<br>+ two bytes of the IFD contain a count of the number of tags. */<br>+ tags = de_get16( &exif_marker->data[i], endian );<br>+ i = i + 2;<br>+<br>+ /* Check that we still have enough data for all tags to check. The tags<br>+ are listed in consecutive 12-byte blocks. The tag ID, type, size, and<br>+ a pointer to the actual value, are packed into these 12 byte entries. */<br>+ if ( ( i + tags * 12 ) > exif_marker->data_length )<br></span>+ return 1;<span class=""><br>+<br>+ /* Check through IFD0 for tags of interest */<br>+ while ( tags-- )<br>+ {<br>+ tag_type = de_get16( &exif_marker->data[i], endian );<br>+ /* Is this the orientation tag? */<br>+ if ( tag_type == 0x112 )<br>+ {<br>+ type = de_get16( &exif_marker->data[i + 2], endian );<br>+ count = de_get32( &exif_marker->data[i + 4], endian );<br>+<br>+ /* Check that type and count fields are OK. The orientation field<br>+ will consist of a single (count=1) 2-byte integer (type=3). */<br>+ if ( type != 3 || count != 1 )<br></span>+ return 1;<span class=""><br>+<br>+ /* Return the orientation value. Within the 12-byte block, the<br>+ pointer to the actual data is at offset 8. */<br>+ ret = de_get16( &exif_marker->data[i + 8], endian );<br></span>+ return ( ret <= 8 && ret > 0 ) ? ret : 1;<span class=""><br>+ }<br>+ /* move the pointer to the next 12-byte tag field. */<br>+ i = i + 12;<br>+ }<br>+<br></span>+ return 1; /* No EXIF Orientation tag found */<span class=""><br>+}<br>+<br> /*<br> * This function must be fed with a complete compressed frame.<br> */<br></span>@@ -186,8 +404,8 @@ static picture_t * DecodeBlock ( decoder_t * p_dec, block_t * * pp_block )<span class=""><br> decoder_sys_t * p_sys = p_dec->p_sys;<br> block_t * p_block;<br> picture_t * p_pic = 0;<br>-<br> JSAMPARRAY p_row_pointers = NULL;<br>+ bool b_autoorient;<br> <br></span><span class=""> if ( !pp_block || !*pp_block )<br> {<br></span>@@ -211,8 +429,14 @@ static picture_t * DecodeBlock ( decoder_t * p_dec, block_t * * pp_block )<span class=""><br> <br> jpeg_create_decompress( &p_sys->p_jpeg );<br> jpeg_mem_src( &p_sys->p_jpeg, p_block->p_buffer, p_block->i_buffer );<br>- jpeg_read_header( &p_sys->p_jpeg, TRUE );<br></span>+ b_autoorient = var_InheritBool( p_dec, "jpeg-autoorient" );<span class=""><br> <br>+ if ( b_autoorient )<br>+ {<br></span><span class="">+ jpeg_save_markers( &p_sys->p_jpeg, EXIF_JPEG_MARKER, 0xffff );<br>+ }<br>+<br></span>+ jpeg_read_header( &p_sys->p_jpeg, TRUE );<br> p_sys->p_jpeg.out_color_space = JCS_RGB;<br> <br> jpeg_start_decompress( &p_sys->p_jpeg );<br>@@ -226,6 +450,14 @@ static picture_t * DecodeBlock ( decoder_t * p_dec, block_t * * pp_block )<br> p_dec->fmt_out.video.i_rmask = 0x000000ff;<br> p_dec->fmt_out.video.i_gmask = 0x0000ff00;<br> p_dec->fmt_out.video.i_bmask = 0x00ff0000;<span class=""><br>+ if ( b_autoorient )<br>+ {<br></span>+ /*<br>+ * Orientation tag has valid range of 1-8. We force to 1 if undefined - 1 = normal orientation<br>+ * It seems as if ORIENT_FROM_EXIF in vlc_es.h has values in reverse order so pass in ( 9 - Orientation tag )<br>+ */<br>+ p_dec->fmt_out.video.orientation = ORIENT_FROM_EXIF( 9 - jpeg_GetOrientation( &p_sys->p_jpeg ) );<br>+ }<br> <br> /* Get a new picture */<br> p_pic = decoder_NewPicture( p_dec );<br>@@ -265,7 +497,6 @@ static picture_t * DecodeBlock ( decoder_t * p_dec, block_t * * pp_block )<span class=""><br> <br> jpeg_destroy_decompress( &p_sys->p_jpeg );<br> free( p_row_pointers );<br>-<br> block_Release( p_block );<br> return NULL;<br> }<br>-- <br>2.7.4<br><br></span></div></div></div></div>
</blockquote></div><br></div>