mirror of
https://github.com/videolan/vlc.git
synced 2024-12-05 07:46:32 +08:00
Automatically orient JPEG image based on orientation flag, if present
Signed-off-by: Jean-Baptiste Kempf <jb@videolan.org>
This commit is contained in:
parent
c33cdace3b
commit
16b5785805
1
NEWS
1
NEWS
@ -67,6 +67,7 @@ Decoder:
|
||||
supporting H.263, H.264/MPEG-4 AVC, MPEG-4 Part 2, and DV depending on device
|
||||
and OS version
|
||||
* Support for the OggSpots video codec
|
||||
* JPEG images correctly oriented using embedded orientation tag, if present
|
||||
|
||||
Demuxers:
|
||||
* Support HD-DVD .evo (H.264, VC-1, MPEG-2, PCM, AC-3, E-AC3, MLP, DTS)
|
||||
|
@ -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@codemonkey.ru>
|
||||
*
|
||||
@ -181,6 +181,220 @@ static int OpenDecoder(vlc_object_t *p_this)
|
||||
return VLC_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* The following two functions are used to return 16 and 32 bit values from
|
||||
* the EXIF tag structure. That structure is borrowed from TIFF files and may be
|
||||
* in big endian or little endian format. The endian parameter tells us which.
|
||||
* Case Little Endian EXIF tag / Little Endian machine
|
||||
* - just memcpy the tag structure into the value to return
|
||||
* Case Little Endian EXIF tag / Big Endian machine
|
||||
* - memcpy the tag structure into value, and bswap it
|
||||
* Case Little Endian EXIF tag / Big Endian machine
|
||||
* - memcpy the tag structure into value, and bswap it
|
||||
* Case Big Endian EXIF tag / Big Endian machine
|
||||
* - just memcpy the tag structure into the value to return
|
||||
*
|
||||
* While there are byte manipulation functions in vlc_common.h, none of them
|
||||
* address that format of the data supplied may be either big or little endian.
|
||||
*
|
||||
* The claim is made that this is the best way to do it. Can you do better?
|
||||
*/
|
||||
|
||||
#define G_LITTLE_ENDIAN 1234
|
||||
#define G_BIG_ENDIAN 4321
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* 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 )
|
||||
{
|
||||
|
||||
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 */
|
||||
|
||||
const char leth[] = { 0x49, 0x49, 0x2a, 0x00 }; /* Little endian TIFF header */
|
||||
const char beth[] = { 0x4d, 0x4d, 0x00, 0x2a }; /* Big endian TIFF header */
|
||||
|
||||
#define EXIF_JPEG_MARKER 0xE1
|
||||
#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->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 == EXIF_ORIENT_TAGID )
|
||||
{
|
||||
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.
|
||||
*/
|
||||
@ -214,6 +428,7 @@ 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_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;
|
||||
@ -230,6 +445,14 @@ static picture_t *DecodeBlock(decoder_t *p_dec, block_t **pp_block)
|
||||
p_dec->fmt_out.video.i_gmask = 0x0000ff00;
|
||||
p_dec->fmt_out.video.i_bmask = 0x00ff0000;
|
||||
|
||||
int i_otag; /* Orientation tag has valid range of 1-8. 1 is normal orientation, 0 = unspecified = normal */
|
||||
i_otag = jpeg_GetOrientation( &p_sys->p_jpeg );
|
||||
if ( i_otag > 1 )
|
||||
{
|
||||
msg_Dbg( p_dec, "Jpeg 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);
|
||||
if (!p_pic)
|
||||
|
Loading…
Reference in New Issue
Block a user