[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