[vlc-commits] [Git][videolan/vlc][master] 5 commits: codec: jpeg: search every APP1 for XMP projection tag

Steve Lhomme (@robUx4) gitlab at videolan.org
Fri Dec 16 14:37:44 UTC 2022



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
7c3130c9 by Francois Cartegnie at 2022-12-16T13:42:59+00:00
codec: jpeg: search every APP1 for XMP projection tag

- - - - -
4e419fa5 by Francois Cartegnie at 2022-12-16T13:42:59+00:00
codec: jpeg: check projection values

- - - - -
1a82010c by Francois Cartegnie at 2022-12-16T13:42:59+00:00
codec: jpeg: constify

- - - - -
d80b8049 by Francois Cartegnie at 2022-12-16T13:42:59+00:00
codec: jpeg: use native readers

- - - - -
a0d6edda by Francois Cartegnie at 2022-12-16T13:42:59+00:00
codec: jpeg: check every APP1 for orientation

- - - - -


1 changed file:

- modules/codec/jpeg.c


Changes:

=====================================
modules/codec/jpeg.c
=====================================
@@ -214,44 +214,14 @@ static int OpenDecoder(vlc_object_t *p_this)
 typedef unsigned int uint;
 typedef unsigned short ushort;
 
-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 = vlc_bswap16( val );
-        #endif
-    }
-    else
-    {
-        #ifdef WORDS_BIGENDIAN
-        val = vlc_bswap16( val );
-        #endif
-    }
-    return val;
+static uint16_t
+de_get16( const void * ptr, uint endian ) {
+    return (endian == G_BIG_ENDIAN) ? GetWBE(ptr) : GetWLE(ptr);
 }
 
-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 = vlc_bswap32( val );
-        #endif
-    }
-    else
-    {
-        #ifdef WORDS_BIGENDIAN
-        val = vlc_bswap32( val );
-        #endif
-    }
-    return val;
+static uint32_t
+de_get32( const void * ptr, uint endian ) {
+    return (endian == G_BIG_ENDIAN) ? GetDWBE(ptr) : GetDWLE(ptr);
 }
 
 static bool getRDFFloat(const char *psz_rdf, float *out, const char *psz_var)
@@ -286,42 +256,31 @@ static bool getRDFFloat(const char *psz_rdf, float *out, const char *psz_var)
 
 /* read XMP metadata for projection according to
  * https://developers.google.com/streetview/spherical-metadata */
-static void jpeg_GetProjection(j_decompress_ptr cinfo, video_format_t *fmt)
+static bool jpeg_ParseXMP(const uint8_t *p_buf, size_t i_buf,
+                          video_format_t *fmt)
 {
-    jpeg_saved_marker_ptr xmp_marker = NULL;
-    jpeg_saved_marker_ptr cmarker = cinfo->marker_list;
-
-    while (cmarker)
-    {
-        if (cmarker->marker == EXIF_JPEG_MARKER)
-        {
-            if(cmarker->data_length >= 32 &&
-               !memcmp(cmarker->data, EXIF_XMP_STRING, 29))
-            {
-                xmp_marker = cmarker;
-                break;
-            }
-        }
-        cmarker = cmarker->next;
-    }
+    if(i_buf < 29)
+        return false;
 
-    if (xmp_marker == NULL)
-        return;
-    char *psz_rdf = malloc(xmp_marker->data_length - 29 + 1);
+    /* Allocate temp, zero terminated buffer */
+    /* Fixme: custom memicmp */
+    /* or Fixme: Who's not compliant to XML attributes case ? */
+    char *psz_rdf = malloc(i_buf - 29 + 1);
     if (unlikely(psz_rdf == NULL))
-        return;
-    memcpy(psz_rdf, xmp_marker->data + 29, xmp_marker->data_length - 29);
-    psz_rdf[xmp_marker->data_length - 29] = '\0';
+        return false;
+    memcpy(psz_rdf, p_buf + 29, i_buf - 29);
+    psz_rdf[i_buf - 29] = '\0';
+
+    if (!strcasestr(psz_rdf, "ProjectionType=\"equirectangular\"") &&
+        !strcasestr(psz_rdf, "ProjectionType>equirectangular"))
+    return false;
 
-    /* Try to find the string "GSpherical:Spherical" because the v1
-        spherical video spec says the tag must be there. */
-    if (strcasestr(psz_rdf, "ProjectionType=\"equirectangular\"") ||
-        strcasestr(psz_rdf, "ProjectionType>equirectangular"))
-        fmt->projection_mode = PROJECTION_MODE_EQUIRECTANGULAR;
+    fmt->projection_mode = PROJECTION_MODE_EQUIRECTANGULAR;
 
     /* pose handling */
     float value;
-    if (getRDFFloat(psz_rdf, &value, "PoseHeadingDegrees"))
+    if (getRDFFloat(psz_rdf, &value, "PoseHeadingDegrees") &&
+        value >= 0.f && value <= 360.f)
         fmt->pose.yaw = value;
 
     if (getRDFFloat(psz_rdf, &value, "PosePitchDegrees"))
@@ -340,23 +299,40 @@ static void jpeg_GetProjection(j_decompress_ptr cinfo, video_format_t *fmt)
     if (getRDFFloat(psz_rdf, &value, "InitialViewRollDegrees"))
         fmt->pose.roll = value;
 
-    if (getRDFFloat(psz_rdf, &value, "InitialHorizontalFOVDegrees"))
+    if (getRDFFloat(psz_rdf, &value, "InitialHorizontalFOVDegrees") &&
+        value >= FIELD_OF_VIEW_DEGREES_MIN && value <= FIELD_OF_VIEW_DEGREES_MAX)
         fmt->pose.fov = value;
 
     free(psz_rdf);
+
+    return true;
+}
+
+static void jpeg_FillProjection(j_decompress_ptr cinfo, video_format_t *fmt)
+{
+    for (jpeg_saved_marker_ptr cmarker = cinfo->marker_list;
+                               cmarker != NULL;
+                               cmarker = cmarker->next)
+    {
+        if(cmarker->marker == EXIF_JPEG_MARKER &&
+           cmarker->data_length >= 32 &&
+           !memcmp(cmarker->data, EXIF_XMP_STRING, 29) &&
+           jpeg_ParseXMP(cmarker->data, cmarker->data_length, fmt))
+           break; /* found projection marker */
+    }
 }
 
 /*
  * Look through the meta data in the libjpeg decompress structure to determine
- * if an EXIF Orientation tag is present. If so return its value (1-8),
- * otherwise return 0
+ * if an EXIF Orientation tag is present. If so return true and sets orientation
+ *  value (1-8), otherwise return false
  *
  * This function is based on the function get_orientation in io-jpeg.c, part of
  * the GdkPixbuf library, licensed under LGPLv2+.
  *   Copyright (C) 1999 Michael Zucchi, The Free Software Foundation
 */
-LOCAL( int )
-jpeg_GetOrientation( j_decompress_ptr cinfo )
+#define EXIF_IDENT_STRING   "Exif\0" /* Exif\000\000 */
+static bool jpeg_ParseExifApp1( const uint8_t *p_buf, size_t i_buf, int *orientation )
 {
 
     uint i;                    /* index into working buffer */
@@ -369,37 +345,13 @@ jpeg_GetOrientation( j_decompress_ptr cinfo )
     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 */
-
     const char leth[] = { 0x49, 0x49, 0x2a, 0x00 }; /* Little endian TIFF header */
     const char beth[] = { 0x4d, 0x4d, 0x00, 0x2a }; /* Big endian TIFF header */
 
-    #define EXIF_IDENT_STRING   "Exif\000\000"
     #define EXIF_ORIENT_TAGID   0x112
 
-    /* check for Exif marker (also called the APP1 marker) */
-    exif_marker = NULL;
-    cmarker = cinfo->marker_list;
-
-    while ( cmarker )
-    {
-        if ( cmarker->data_length >= 32 &&
-             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;
+    if (i_buf < 32)
+        return false;
 
     /* Check for TIFF header and catch endianness */
     i = 0;
@@ -422,13 +374,13 @@ jpeg_GetOrientation( j_decompress_ptr cinfo )
     while ( i < 16 )
     {
         /* Little endian TIFF header */
-        if ( memcmp( &exif_marker->data[i], leth, 4 ) == 0 )
+        if ( memcmp( &p_buf[i], leth, 4 ) == 0 )
         {
             endian = G_LITTLE_ENDIAN;
         }
         /* Big endian TIFF header */
         else
-        if ( memcmp( &exif_marker->data[i], beth, 4 ) == 0 )
+        if ( memcmp( &p_buf[i], beth, 4 ) == 0 )
         {
             endian = G_BIG_ENDIAN;
         }
@@ -445,53 +397,70 @@ jpeg_GetOrientation( j_decompress_ptr cinfo )
 
     /* So did we find a TIFF header or did we just hit end of buffer? */
     if ( tiff == 0 )
-        return 0;
+        return false;
 
     /* Read out the offset pointer to IFD0 */
-    offset = de_get32( &exif_marker->data[i] + 4, endian );
+    offset = de_get32( &p_buf[i] + 4, endian );
     i = i + offset;
 
     /* Check that we still are within the buffer and can read the tag count */
 
-    if ( i > exif_marker->data_length - 2 )
-        return 0;
+    if ( i > i_buf - 2 )
+        return false;
 
     /* 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 );
+    tags = de_get16( &p_buf[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 ( tags * 12U > exif_marker->data_length - i )
-        return 0;
+    if ( tags * 12U > i_buf - i )
+        return false;
 
     /* Check through IFD0 for tags of interest */
     while ( tags-- )
     {
-        tag_type = de_get16( &exif_marker->data[i], endian );
+        tag_type = de_get16( &p_buf[i], endian );
         /* Is this the orientation tag? */
         if ( tag_type == EXIF_ORIENT_TAGID )
         {
-            type = de_get16( &exif_marker->data[i + 2], endian );
-            count = de_get32( &exif_marker->data[i + 4], endian );
+            type = de_get16( &p_buf[i + 2], endian );
+            count = de_get32( &p_buf[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 false;
 
             /* 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 = de_get16( &p_buf[i + 8], endian );
+            *orientation = ( ret <= 8 ) ? ret : 0;
+            return true;
         }
         /* move the pointer to the next 12-byte tag field. */
         i = i + 12;
     }
 
-    return 0;     /* No EXIF Orientation tag found */
+    return false; /* No EXIF Orientation tag found */
+}
+
+static int jpeg_GetOrientation( j_decompress_ptr cinfo )
+{
+    int orientation = 0;
+    for (jpeg_saved_marker_ptr cmarker = cinfo->marker_list;
+                               cmarker != NULL;
+                               cmarker = cmarker->next)
+    {
+        if(cmarker->marker == EXIF_JPEG_MARKER &&
+           cmarker->data_length >= 32 &&
+           !memcmp(cmarker->data, EXIF_IDENT_STRING, sizeof(EXIF_IDENT_STRING)) &&
+           jpeg_ParseExifApp1(cmarker->data, cmarker->data_length, &orientation))
+           break; /* found orientation marker */
+    }
+    return orientation;
 }
 
 /*
@@ -544,7 +513,7 @@ static int DecodeBlock(decoder_t *p_dec, block_t *p_block)
         msg_Dbg( p_dec, "Jpeg orientation is %d", i_otag );
         p_dec->fmt_out.video.orientation = ORIENT_FROM_EXIF( i_otag );
     }
-    jpeg_GetProjection(&p_sys->p_jpeg, &p_dec->fmt_out.video);
+    jpeg_FillProjection(&p_sys->p_jpeg, &p_dec->fmt_out.video);
 
     /* Get a new picture */
     if (decoder_UpdateVideoFormat(p_dec))



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/3c12a797b8e44f56852a6cda5d65e1d8ef698228...a0d6edda54b329649c50b7de8c97b1509990fd20

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/3c12a797b8e44f56852a6cda5d65e1d8ef698228...a0d6edda54b329649c50b7de8c97b1509990fd20
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list