[FFmpeg-devel] [PATCH] AVI metadata retrieval improvements

Thilo Borgmann thilo.borgmann at mail.de
Tue Mar 4 18:55:52 CET 2014


Am 04.03.14 17:16, schrieb gregory.wolfe at kodakalaris.com:
>
> [...]
>
> This patch enhances two aspects of metadata retrieval from AVI files.
> I've attached before/after command line output from ffmpeg for each
> modification.  Test video files that can be used to generate the
> before/after output have been uploaded to the FFmpeg FTP server.

Is there also an upload of AviStreamMetadataFixDSCF0004.avi ?

> [...]

>From 976705e1fa4b2f8e114da19be02819eb0df24ad6 Mon Sep 17 00:00:00 2001
From: "Gregory J. Wolfe" <gregory.wolfe at kodakalaris.com>
Date: Mon, 3 Mar 2014 12:39:58 -0500
Subject: [PATCH 3/3] AVI metadata retrieval improvements.

Added function avi_extract_stream_metadata().  Some cameras (e.g., Fuji) store
stream metadata following the "strd" stream data tag.  avi_read_header() calls
ff_get_extradata() to read and save this data in the codec's "extradata" slot.
This new function extracts metadata from "extradata" by first looking for the
AVIF tag, then extracting metadata from the EXIF tags which follow it.

In a separate change, some cameras (e.g., Casio) store the date format as
yyyy/mm/dd/ hh:mm.  Added code to get rid of the "/" following "dd".
---
 libavformat/avidec.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 113 insertions(+)

diff --git a/libavformat/avidec.c b/libavformat/avidec.c
index bab62a0..df25cab 100644
--- a/libavformat/avidec.c
+++ b/libavformat/avidec.c
@@ -332,6 +332,10 @@ static void avi_metadata_creation_time(AVDictionary
**metadata, char *date)
             }
     } else if (date[4] == '/' && date[7] == '/') {
         date[4] = date[7] = '-';
+        // some cameras (e.g., Casio) store date format as yyyy/mm/dd/ hh:mm

+        // (added by Greg Wolfe, Kodak Alaris)

as already mentioned, please remove these redundant info (the author's already
in git log and git blame...)

+        if  ( date[10] == '/' )
+            date[10] = ' ';
         av_dict_set(metadata, "creation_time", date, 0);
     }
 }
@@ -379,6 +383,112 @@ static void avi_read_nikon(AVFormatContext *s, uint64_t end)
     }
 }

+// extract stream metadata (added by Greg Wolfe, Kodak Alaris)
+static void avi_extract_stream_metadata(AVStream *st)

+{//avi_extract_stream_metadata

This is also just a needless comment, please remove.

+
+    // Some cameras (e.g., Fuji) store stream metadata following the "strd"
stream data
+    // tag.  avi_read_header() calls ff_get_extradata() to read and save this
data in the
+    // codec's "extradata" slot.
+    //
+    // This function extracts metadata from "extradata" by first looking for
the AVIF tag,
+    // then extracting metadata from the EXIF tags which follow it.

I think this comment should better be put in a regular doxygen comment so the
users can find this info in the docs.

+    uint8_t *pData,*pEnd;
+    int Len,AVIFTag;
+
+    if  ( st == 0 )
+        return;
+    pData = st->codec->extradata;
+    Len = st->codec->extradata_size;
+    pEnd = pData + Len;
+
+    if ( (pData == 0) || (Len < 10) )
+        return;        // nothing worth looking at!
+
+    AVIFTag = pData[0] | (pData[1] << 8) | (pData[2] << 16) | (pData[3] << 24);
+    pData += 4;
+    if  ( AVIFTag == MKTAG('A', 'V', 'I', 'F') )
+    {//process EXIF tags

K&R nit, please stick to, here and at the other occasions: if (x == y) { //...

+        uint8_t *pTagTable;
+        int TagTableCount,iTag;
+
+        pData += 4;    // skip two 16-bit fields that we don't care about
+        pTagTable = pData;    // start of the tag table; data offsets are
relative to this
+        TagTableCount = pData[0] | (pData[1] << 8);    // number of entries in
EXIF tag table
+        pData += 2;
+
+        // each tag entry is 12 bytes long; sanity check
+        if  ( (pData + 12 * TagTableCount) > pEnd )
+            return;        // tag table extends beyond end of available data;
bail out
+
+        for  ( iTag = 0; iTag < TagTableCount; iTag++, pData += 12 )
+        {//iTag loop
+
+            unsigned int TagID,TagType,TagDataLen,TagDataOffset;
+            uint8_t *pTagData;
+            char Buffer[1024];
+
+            TagID = pData[0] | (pData[1] << 8);
+            TagType = pData[2] | (pData[3] << 8);
+            TagDataLen = pData[4] | (pData[5] << 8) | (pData[6] << 16) |
(pData[7] << 24);
+            TagDataOffset = pData[8] | (pData[9] << 8) | (pData[10] << 16) |
(pData[11] << 24);
+
+            pTagData = pTagTable + TagDataOffset;
+            if  ( (TagDataLen > 0) && ((pTagData + TagDataLen) <= pEnd) )
+            {//valid tag data
+
+                if  ( TagDataLen > (sizeof(Buffer)-1) )
+                    TagDataLen = sizeof(Buffer) - 1;
+
+                if  ( TagID == 0x010f )
+                {//maker
+                    memcpy(Buffer,pTagData,TagDataLen);
+                    Buffer[TagDataLen] = 0;
+                    av_dict_set(&st->metadata,"maker",Buffer,0);
+                }//maker
+                else if  ( TagID == 0x0110 )
+                {//model
+                    memcpy(Buffer,pTagData,TagDataLen);
+                    Buffer[TagDataLen] = 0;
+                    av_dict_set(&st->metadata,"model",Buffer,0);
+                }//model
+                else if  ( TagID == 0x0112 )
+                {//orientation
+                    int Orientation = pTagData[0] | (pTagData[1] << 8);
+                    if  ( (Orientation >= 1) || (Orientation <= 8) )
+                    {
+                        Buffer[0] = '0' + Orientation;
+                        Buffer[1] = 0;
+                        av_dict_set(&st->metadata,"orientation",Buffer,0);
+                    }
+                }//orientation
+                else if  ( TagID == 0x0131 )
+                {//software
+                    memcpy(Buffer,pTagData,TagDataLen);
+                    Buffer[TagDataLen] = 0;
+                    av_dict_set(&st->metadata,"software",Buffer,0);
+                }//software
+                else if  ( TagID == 0x0132 )
+                {//modify date (DateTime in EXIF spec)
+                    memcpy(Buffer,pTagData,TagDataLen);
+                    Buffer[TagDataLen] = 0;
+                    // Since this is an EXIF tag, the date/time will be in EXIF
format; massage
+                    // to make consistent with avi_metadata_creation_time() result.
+                    if  ( (Buffer[4] == ':') && (Buffer[7] == ':') )
+                        Buffer[4] = Buffer[7] = '-';
+                    av_dict_set(&st->metadata,"creation_time",Buffer,0);
+                }//modify date (DateTime in EXIF spec)
+
+            }//valid tag data
+
+        }//iTag loop
+
+    }//process EXIF tags

There is already code for processing EXIF tags that should be used here. Please
have a look at libavcodec/exif and libavcodec/mjpegdec.

Also, the tag ID's used should be referenced if they are not given in the EXIF
spec but somewhere else.

+}//avi_extract_stream_metadata
+
 static int avi_read_header(AVFormatContext *s)
 {
     AVIContext *avi = s->priv_data;
@@ -789,6 +899,9 @@ static int avi_read_header(AVFormatContext *s)

                 if (st->codec->extradata_size & 1) //FIXME check if the encoder
really did this correctly
                     avio_r8(pb);
+
+                // extract stream metadata (added by Greg Wolfe, Kodak Alaris)
+                avi_extract_stream_metadata(st);
             }
             break;
         case MKTAG('i', 'n', 'd', 'x'):
-- 
1.8.5.2.msysgit.0


-Thilo



More information about the ffmpeg-devel mailing list