Module: libav
Branch: master
Commit: cb7e2c1ca864a2ff44c851689ba8a2d4a81dfd27

Author:    Kharkov Alexander <[email protected]>
Committer: Anton Khirnov <[email protected]>
Date:      Fri Mar 18 08:26:51 2011 +0100

flvdec: read index stored in the 'keyframes' tag.

'keyframes' metatag is not part of the standard, it is just
convention to use such kind of metatag information for indexing.
Structure is following, it allows to have it inconsistent:
keyframes:
 times (array):
  time0 (num)
  time1 (num)
  time2 (num)
 filepositions (array)
  position0 (num)
  position1 (num)

Signed-off-by: Anton Khirnov <[email protected]>

---

 libavformat/flvdec.c |   66 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 66 insertions(+), 0 deletions(-)

diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
index 2152f7d..972b4d9 100644
--- a/libavformat/flvdec.c
+++ b/libavformat/flvdec.c
@@ -31,6 +31,10 @@
 #include "avio_internal.h"
 #include "flv.h"
 
+#define KEYFRAMES_TAG            "keyframes"
+#define KEYFRAMES_TIMESTAMP_TAG  "times"
+#define KEYFRAMES_BYTEOFFSET_TAG "filepositions"
+
 typedef struct {
     int wrong_dts; ///< wrong dts due to negative cts
 } FLVContext;
@@ -125,6 +129,64 @@ static int amf_get_string(AVIOContext *ioc, char *buffer, 
int buffsize) {
     return length;
 }
 
+static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, 
AVStream *vstream, int64_t max_pos) {
+    unsigned int arraylen = 0, timeslen = 0, fileposlen = 0, i;
+    double num_val;
+    char str_val[256];
+    int64_t *times = NULL;
+    int64_t *filepositions = NULL;
+    int ret = 0;
+
+    while (avio_tell(ioc) < max_pos - 2 && amf_get_string(ioc, str_val, 
sizeof(str_val)) > 0) {
+        int64_t* current_array;
+
+        // Expect array object in context
+        if (avio_r8(ioc) != AMF_DATA_TYPE_ARRAY)
+            break;
+
+        arraylen = avio_rb32(ioc);
+        /*
+         * Expect only 'times' or 'filepositions' sub-arrays in other case 
refuse to use such metadata
+         * for indexing
+         */
+        if (!strcmp(KEYFRAMES_TIMESTAMP_TAG, str_val) && !times) {
+            if (!(times = av_mallocz(sizeof(*times) * arraylen))) {
+                ret = AVERROR(ENOMEM);
+                goto finish;
+            }
+            timeslen = arraylen;
+            current_array = times;
+        } else if (!strcmp(KEYFRAMES_BYTEOFFSET_TAG, str_val) && 
!filepositions) {
+            if (!(filepositions = av_mallocz(sizeof(*filepositions) * 
arraylen))) {
+                ret = AVERROR(ENOMEM);
+                goto finish;
+            }
+            fileposlen = arraylen;
+            current_array = filepositions;
+        } else // unexpected metatag inside keyframes, will not use such 
metadata for indexing
+            break;
+
+        for (i = 0; i < arraylen && avio_tell(ioc) < max_pos - 1; i++) {
+            if (avio_r8(ioc) != AMF_DATA_TYPE_NUMBER)
+                goto finish;
+            num_val = av_int2dbl(avio_rb64(ioc));
+            current_array[i] = num_val;
+        }
+    }
+
+    if (timeslen == fileposlen)
+         for(i = 0; i < arraylen; i++)
+             av_add_index_entry(vstream, filepositions[i], times[i]*1000, 0, 
0, AVINDEX_KEYFRAME);
+    else
+        av_log(s, AV_LOG_WARNING, "Invalid keyframes object, skipping.\n");
+
+finish:
+    av_freep(&times);
+    av_freep(&filepositions);
+    avio_seek(ioc, max_pos, SEEK_SET);
+    return ret;
+}
+
 static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream 
*vstream, const char *key, int64_t max_pos, int depth) {
     AVCodecContext *acodec, *vcodec;
     AVIOContext *ioc;
@@ -149,6 +211,10 @@ static int amf_parse_object(AVFormatContext *s, AVStream 
*astream, AVStream *vst
         case AMF_DATA_TYPE_OBJECT: {
             unsigned int keylen;
 
+            if (!strcmp(KEYFRAMES_TAG, key) && depth == 1)
+                if (parse_keyframes_index(s, ioc, vstream, max_pos) < 0)
+                    return -1;
+
             while(avio_tell(ioc) < max_pos - 2 && (keylen = avio_rb16(ioc))) {
                 avio_skip(ioc, keylen); //skip key string
                 if(amf_parse_object(s, NULL, NULL, NULL, max_pos, depth + 1) < 
0)

_______________________________________________
libav-commits mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-commits

Reply via email to