[vlc-devel] [PATCH] Automatically orient JPEG image based on orientation flag, if set

Wayne McDougall waynemcdougall at gmail.com
Mon Apr 18 07:19:01 CEST 2016


Update patch to
a) reflect correction to ORIENT_FROM_EXIF
b) avoid unnecessary call to ORIENT_FROM_EXIF when normal orientation or no
orientation tag (most common cases)

[PATCH] Automatically orient JPEG images using embedded orientation tag, if
present

---
 modules/codec/jpeg.c | 242
++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 241 insertions(+), 1 deletion(-)

diff --git a/modules/codec/jpeg.c b/modules/codec/jpeg.c
index fdb91c7..1e275cd 100644
--- a/modules/codec/jpeg.c
+++ b/modules/codec/jpeg.c
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * jpeg.c: jpeg decoder module making use of libjpeg.

*****************************************************************************
- * Copyright (C) 2013-2014 VLC authors and VideoLAN
+ * Copyright (C) 2013-2014,2016 VLC authors and VideoLAN
  *
  * Authors: Maxim Bublis <b at codemonkey.ru>
  *
@@ -50,6 +50,22 @@
 #define ENC_QUALITY_LONGTEXT N_("Quality level " \
     "for encoding (this can enlarge or reduce output image size).")

+#define DEC_CFG_PREFIX "jpeg-"
+#define DEC_AUTOORIENT_TEXT N_( "Automatic Orientation" )
+#define DEC_AUTOORIENT_LONGTEXT N_( "Automatic rotation based on EXIF
orientation tag." )
+
+const char leth[] = {
+    0x49, 0x49, 0x2a, 0x00
+};                                              // Little endian TIFF
header
+const char beth[] = {
+    0x4d, 0x4d, 0x00, 0x2a
+};                                              // Big endian TIFF header
+
+#define G_LITTLE_ENDIAN     1234
+#define G_BIG_ENDIAN        4321
+
+#define EXIF_JPEG_MARKER    0xE1
+#define EXIF_IDENT_STRING   "Exif\000\000"

 /*
  * jpeg common descriptor
@@ -110,6 +126,13 @@ vlc_module_begin()
     set_capability("decoder", 1000)
     set_callbacks(OpenDecoder, CloseDecoder)
     add_shortcut("jpeg")
+    /*
+     * Some JPEG get transformed to a normal orientation without resetting
+     * embedded orientation tag to reflect that.
+     * Allow disabling of autoorientation in case we have to work with
such images.
+    */
+    add_bool( DEC_CFG_PREFIX "autoorient", true,
+              DEC_AUTOORIENT_TEXT, DEC_AUTOORIENT_LONGTEXT, true )

     /* encoder submodule */
     add_submodule()
@@ -181,6 +204,201 @@ static int OpenDecoder(vlc_object_t *p_this)
     return VLC_SUCCESS;
 }

+/* The EXIF headers in JPEG are based on TIFF and so
+ * may be in big endian or little endian format. We may be on a
+ * big endian machine or little endian machine.
+ * The following functions swap our 2 and 4 byte pairs, depending
+ * on which of the 4 possibilities we are dealing with.
+ * endian parameter tells us the source format, and WORDS_BIGENDIAN
+ * tells us how the machine we are running on stores that source
+ * format.
+*/
+
+LOCAL( unsigned short )
+de_get16( void * ptr, uint endian ) {
+    unsigned short val;
+
+    memcpy( &val, ptr, sizeof( val ) );
+    if ( endian == G_BIG_ENDIAN )
+    {
+        #ifndef WORDS_BIGENDIAN
+        val = bswap16( val );
+        #endif
+    }
+    else
+    {
+        #ifdef WORDS_BIGENDIAN
+        val = bswap16( val );
+        #endif
+    }
+    return val;
+}
+
+LOCAL( unsigned int )
+de_get32( void * ptr, uint endian ) {
+    unsigned int val;
+
+    memcpy( &val, ptr, sizeof( val ) );
+    if ( endian == G_BIG_ENDIAN )
+    {
+        #ifndef WORDS_BIGENDIAN
+        val = bswap32( val );
+        #endif
+    }
+    else
+    {
+        #ifdef WORDS_BIGENDIAN
+        val = bswap32( val );
+        #endif
+    }
+    return val;
+}
+
+/* jpeg_GetOrientation function based on code from GdkPixbuf library -
JPEG image loader
+ *
http://src.gnu-darwin.org/ports/x11-toolkits/gtk20/work/gtk+-2.12.3/gdk-pixbuf/io-jpeg.c
+ *
+ * Copyright (C) 1999 Michael Zucchi
+ * Copyright (C) 1999 The Free Software Foundation
+ */
+
+LOCAL( int )
+jpeg_GetOrientation( j_decompress_ptr cinfo ) {
+    /* This function looks through the meta data in the libjpeg decompress
structure to
+       determine if an EXIF Orientation tag is present and if so return
its value (1-8).
+       If no EXIF Orientation tag is found, 0 is returned. */
+
+    uint i;                    /* index into working buffer */
+    ushort tag_type;           /* endianed tag type extracted from tiff
header */
+    uint ret;                  /* Return value */
+    uint offset;               /* de-endianed offset in various situations
*/
+    uint tags;                 /* number of tags in current ifd */
+    uint type;                 /* de-endianed type of tag */
+    uint count;                /* de-endianed count of elements in a tag */
+    uint tiff = 0;             /* offset to active tiff header */
+    uint endian = 0;           /* detected endian of data */
+
+    jpeg_saved_marker_ptr exif_marker;      /* Location of the Exif APP1
marker */
+    jpeg_saved_marker_ptr cmarker;          /* Location to check for Exif
APP1 marker */
+
+    /* check for Exif marker (also called the APP1 marker) */
+    exif_marker = NULL;
+    cmarker = cinfo->marker_list;
+
+    while ( cmarker )
+    {
+        if ( cmarker->marker == EXIF_JPEG_MARKER )
+        {
+            /* The Exif APP1 marker should contain a unique
+               identification string ("Exif\0\0"). Check for it. */
+            if ( !memcmp( cmarker->data, EXIF_IDENT_STRING, 6 ) )
+            {
+                exif_marker = cmarker;
+            }
+        }
+        cmarker = cmarker->next;
+    }
+
+    /* Did we find the Exif APP1 marker? */
+    if ( exif_marker == NULL )
+        return 0;
+
+    /* Do we have enough data? */
+    if ( exif_marker->data_length < 32 )
+        return 0;
+
+    /* Check for TIFF header and catch endianess */
+    i = 0;
+
+    /* Just skip data until TIFF header - it should be within 16 bytes
from marker start.
+       Normal structure relative to APP1 marker -
+            0x0000: APP1 marker entry = 2 bytes
+            0x0002: APP1 length entry = 2 bytes
+            0x0004: Exif Identifier entry = 6 bytes
+            0x000A: Start of TIFF header (Byte order entry) - 4 bytes
+                    - This is what we look for, to determine endianess.
+            0x000E: 0th IFD offset pointer - 4 bytes
+
+            exif_marker->data points to the first data after the APP1
marker
+            and length entries, which is the exif identification string.
+            The TIFF header should thus normally be found at i=6, below,
+            and the pointer to IFD0 will be at 6+4 = 10.
+    */
+
+    while ( i < 16 )
+    {
+        /* Little endian TIFF header */
+        if ( memcmp( &exif_marker->data[i], leth, 4 ) == 0 )
+        {
+            endian = G_LITTLE_ENDIAN;
+        }
+        /* Big endian TIFF header */
+        else
+        if ( memcmp( &exif_marker->data[i], beth, 4 ) == 0 )
+        {
+            endian = G_BIG_ENDIAN;
+        }
+        /* Keep looking through buffer */
+        else
+        {
+            i++;
+            continue;
+        }
+        /* We have found either big or little endian TIFF header */
+        tiff = i;
+        break;
+    }
+
+    /* So did we find a TIFF header or did we just hit end of buffer? */
+    if ( tiff == 0 )
+        return 0;
+
+    /* Read out the offset pointer to IFD0 */
+    offset = de_get32( &exif_marker->data[i] + 4, endian );
+    i = i + offset;
+
+    /* Check that we still are within the buffer and can read the tag
count */
+
+    if ( ( i + 2 ) > exif_marker->data_length )
+        return 0;
+
+    /* Find out how many tags we have in IFD0. As per the TIFF spec, the
first
+       two bytes of the IFD contain a count of the number of tags. */
+    tags = de_get16( &exif_marker->data[i], endian );
+    i = i + 2;
+
+    /* Check that we still have enough data for all tags to check. The tags
+       are listed in consecutive 12-byte blocks. The tag ID, type, size,
and
+       a pointer to the actual value, are packed into these 12 byte
entries. */
+    if ( ( i + tags * 12 ) > exif_marker->data_length )
+        return 0;
+
+    /* Check through IFD0 for tags of interest */
+    while ( tags-- )
+    {
+        tag_type = de_get16( &exif_marker->data[i], endian );
+        /* Is this the orientation tag? */
+        if ( tag_type == 0x112 )
+        {
+            type = de_get16( &exif_marker->data[i + 2], endian );
+            count = de_get32( &exif_marker->data[i + 4], endian );
+
+            /* Check that type and count fields are OK. The orientation
field
+               will consist of a single (count=1) 2-byte integer (type=3).
*/
+            if ( type != 3 || count != 1 )
+                return 0;
+
+            /* Return the orientation value. Within the 12-byte block, the
+               pointer to the actual data is at offset 8. */
+            ret = de_get16( &exif_marker->data[i + 8], endian );
+            return ( ret <= 8 ) ? ret : 0;
+        }
+        /* move the pointer to the next 12-byte tag field. */
+        i = i + 12;
+    }
+
+    return 0;     /* No EXIF Orientation tag found */
+}
+
 /*
  * This function must be fed with a complete compressed frame.
  */
@@ -192,6 +410,9 @@ static picture_t *DecodeBlock(decoder_t *p_dec, block_t
**pp_block)

     JSAMPARRAY p_row_pointers = NULL;

+    bool b_autoorient;
+    int i_otag;
+
     if (!pp_block || !*pp_block)
     {
         return NULL;
@@ -214,6 +435,13 @@ static picture_t *DecodeBlock(decoder_t *p_dec,
block_t **pp_block)

     jpeg_create_decompress(&p_sys->p_jpeg);
     jpeg_mem_src(&p_sys->p_jpeg, p_block->p_buffer, p_block->i_buffer);
+    b_autoorient = var_InheritBool( p_dec, "jpeg-autoorient" );
+
+    if ( b_autoorient )
+    {
+        jpeg_save_markers( &p_sys->p_jpeg, EXIF_JPEG_MARKER, 0xffff );
+    }
+
     jpeg_read_header(&p_sys->p_jpeg, TRUE);

     p_sys->p_jpeg.out_color_space = JCS_RGB;
@@ -229,6 +457,18 @@ static picture_t *DecodeBlock(decoder_t *p_dec,
block_t **pp_block)
     p_dec->fmt_out.video.i_rmask = 0x000000ff;
     p_dec->fmt_out.video.i_gmask = 0x0000ff00;
     p_dec->fmt_out.video.i_bmask = 0x00ff0000;
+    if ( b_autoorient )
+    {
+        i_otag = jpeg_GetOrientation( &p_sys->p_jpeg );
+         /*
+         * Orientation tag has valid range of 1-8. 1 is normal orientation.
+         */
+        if ( i_otag > 1 )
+        {
+            msg_Info( p_dec, "Orientation is %d", i_otag );
+            p_dec->fmt_out.video.orientation = ORIENT_FROM_EXIF( i_otag );
+        }
+    }

     /* Get a new picture */
     p_pic = decoder_NewPicture(p_dec);
-- 
2.7.4


On 18 April 2016 at 08:06, Wayne McDougall <waynemcdougall at gmail.com> wrote:

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


More information about the vlc-devel mailing list