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

XinZheng Zhang zhangxzheng at gmail.com
Wed Jul 20 16:46:13 EEST 2016


There has an error when seeking in a flv file, which key frames was
sorted before video frame.
This ensures that all the key frames was cached, and add to
corresponding stream when it was created.

On Wed, Jul 20, 2016 at 9:30 PM, zhangxinzheng <zhangxzheng at gmail.com> wrote:
> From: Xinzheng Zhang <zhangxzheng at gmail.com>
>
> ---
>  libavformat/flvdec.c | 52 +++++++++++++++++++++++++++++++++++++++++++++-------
>  1 file changed, 45 insertions(+), 7 deletions(-)
>
> diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
> index 2bf1e05..8a73b68 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,12 @@
>
>  #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 +68,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 +106,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 +118,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 +331,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 +340,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 +398,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 +455,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 +670,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 +690,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.5.4 (Apple Git-61)
>


More information about the ffmpeg-devel mailing list