<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>