[FFmpeg-devel] [PATCH] avformat/fivdec: cached keyframes before video or audio stream was created

Xinzheng Zhang zhangxzheng at gmail.com
Thu Jul 21 05:36:20 EEST 2016


---
 libavformat/flvdec.c | 51 ++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 44 insertions(+), 7 deletions(-)

diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
index 2bf1e05..b4fb4e2 100644
--- a/libavformat/flvdec.c
+++ b/libavformat/flvdec.c
@@ -30,6 +30,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/intfloat.h"
 #include "libavutil/mathematics.h"
+#include "libavutil/mem.h"
 #include "libavcodec/bytestream.h"
 #include "libavcodec/mpeg4audio.h"
 #include "avformat.h"
@@ -41,6 +42,11 @@
 
 #define RESYNC_BUFFER_SIZE (1<<20)
 
+typedef struct FLVKeyFrame {
+    int64_t pos;
+    int64_t timestamp;
+} FLVKeyFrame;
+
 typedef struct FLVContext {
     const AVClass *class; ///< Class for private options.
     int trust_metadata;   ///< configure streams according onMetaData
@@ -61,6 +67,10 @@ typedef struct FLVContext {
 
     int broken_sizes;
     int sum_flv_tag_size;
+
+    int head_flags; //r8
+    FLVKeyFrame *keyframes;
+    int keyframe_count;
 } FLVContext;
 
 static int probe(AVProbeData *p, int live)
@@ -95,6 +105,9 @@ static int live_flv_probe(AVProbeData *p)
 static AVStream *create_stream(AVFormatContext *s, int codec_type)
 {
     AVStream *st = avformat_new_stream(s, NULL);
+    FLVContext *flv = s->priv_data;
+    int flags = flv->head_flags;
+    int i = 0;
     if (!st)
         return NULL;
     st->codecpar->codec_type = codec_type;
@@ -104,6 +117,17 @@ static AVStream *create_stream(AVFormatContext *s, int codec_type)
         s->ctx_flags &= ~AVFMTCTX_NOHEADER;
 
     avpriv_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */
+    if ((!(flags & FLV_HEADER_FLAG_HASVIDEO) && codec_type == AVMEDIA_TYPE_AUDIO) ||
+        (codec_type == AVMEDIA_TYPE_VIDEO)
+        ) {
+        for (; i < flv->keyframe_count; i++) {
+            FLVKeyFrame *keyframe = &flv->keyframes[i];
+            av_add_index_entry(st, keyframe->pos, keyframe->timestamp,
+                               0, 0, AVINDEX_KEYFRAME);
+        }
+        flv->keyframe_count = 0;
+        av_freep(&flv->keyframes);
+    }
     return st;
 }
 
@@ -306,7 +330,7 @@ static int amf_get_string(AVIOContext *ioc, char *buffer, int buffsize)
 }
 
 static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc,
-                                 AVStream *vstream, int64_t max_pos)
+                                 AVStream *vstream, AVStream *astream, int64_t max_pos)
 {
     FLVContext *flv       = s->priv_data;
     unsigned int timeslen = 0, fileposlen = 0, i;
@@ -315,8 +339,12 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc,
     int64_t *filepositions = NULL;
     int ret                = AVERROR(ENOSYS);
     int64_t initial_pos    = avio_tell(ioc);
+    int head_flags         = flv->head_flags;
+    AVStream *kf_stream    = vstream;
+    if (!kf_stream && astream && (!(head_flags & FLV_HEADER_FLAG_HASVIDEO) && (head_flags & FLV_HEADER_FLAG_HASAUDIO)))
+        kf_stream = astream;
 
-    if (vstream->nb_index_entries>0) {
+    if (kf_stream && kf_stream->nb_index_entries > 0) {
         av_log(s, AV_LOG_WARNING, "Skipping duplicate index\n");
         return 0;
     }
@@ -369,8 +397,16 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc,
 
     if (timeslen == fileposlen && fileposlen>1 && max_pos <= filepositions[0]) {
         for (i = 0; i < fileposlen; i++) {
-            av_add_index_entry(vstream, filepositions[i], times[i] * 1000,
-                               0, 0, AVINDEX_KEYFRAME);
+            if (kf_stream) {
+                av_add_index_entry(kf_stream, filepositions[i], times[i] * 1000,
+                                   0, 0, AVINDEX_KEYFRAME);
+            } else {
+                FLVKeyFrame frame = {0};
+                frame.pos = filepositions[i];
+                frame.timestamp = times[i] * 1000;
+                av_dynarray2_add((void **)&flv->keyframes, &flv->keyframe_count,sizeof(FLVKeyFrame), (const uint8_t *)&frame);
+            }
+
             if (i < 2) {
                 flv->validate_index[i].pos = filepositions[i];
                 flv->validate_index[i].dts = times[i] * 1000;
@@ -418,10 +454,10 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
         }
         break;
     case AMF_DATA_TYPE_OBJECT:
-        if ((vstream || astream) && key &&
+        if (key &&
             ioc->seekable &&
             !strcmp(KEYFRAMES_TAG, key) && depth == 1)
-            if (parse_keyframes_index(s, ioc, vstream ? vstream : astream,
+            if (parse_keyframes_index(s, ioc, vstream, astream,
                                       max_pos) < 0)
                 av_log(s, AV_LOG_ERROR, "Keyframe index parsing failed\n");
 
@@ -633,7 +669,7 @@ static int flv_read_header(AVFormatContext *s)
     int offset;
 
     avio_skip(s->pb, 4);
-    avio_r8(s->pb); // flags
+    flv->head_flags = avio_r8(s->pb); // flags
 
     s->ctx_flags |= AVFMTCTX_NOHEADER;
 
@@ -653,6 +689,7 @@ static int flv_read_close(AVFormatContext *s)
     FLVContext *flv = s->priv_data;
     for (i=0; i<FLV_STREAM_TYPE_NB; i++)
         av_freep(&flv->new_extradata[i]);
+    av_freep(&flv->keyframes);
     return 0;
 }
 
-- 
2.6.4 (Apple Git-63)



More information about the ffmpeg-devel mailing list