[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