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

Message ID 1469535466-79933-1-git-send-email-zhangxzheng@gmail.com
State Changes Requested
Headers show

Commit Message

Xinzheng Zhang July 26, 2016, 12:17 p.m. UTC
---
 libavformat/flvdec.c | 84 ++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 69 insertions(+), 15 deletions(-)

Comments

Michael Niedermayer July 26, 2016, 5:12 p.m. UTC | #1
On Tue, Jul 26, 2016 at 08:17:46PM +0800, Xinzheng Zhang wrote:
> ---
>  libavformat/flvdec.c | 84 ++++++++++++++++++++++++++++++++++++++++++----------
>  1 file changed, 69 insertions(+), 15 deletions(-)
> 
> diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
> index 2bf1e05..82b9f83 100644
> --- a/libavformat/flvdec.c
> +++ b/libavformat/flvdec.c
> @@ -61,6 +61,12 @@ typedef struct FLVContext {
>  
>      int broken_sizes;
>      int sum_flv_tag_size;
> +
> +    int vhead_exists;
> +    int ahead_exists;
> +    int keyframe_count;
> +    int64_t *keyframe_times;
> +    int64_t *keyframe_filepositions;
>  } FLVContext;
>  
>  static int probe(AVProbeData *p, int live)
> @@ -92,6 +98,42 @@ static int live_flv_probe(AVProbeData *p)
>      return probe(p, 1);
>  }
>  
> +static void add_keyframes_index(AVFormatContext *s)
> +{
> +    FLVContext *flv           = s->priv_data;
> +    AVStream *current_stream  = NULL;
> +    AVStream *vstream         = NULL;
> +    AVStream *astream         = NULL;
> +    unsigned int i,j                ;
> +
> +    for (i = 0; i< s->nb_streams; i++) {
> +        if (s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
> +            vstream = s->streams[i];
> +        } else if (s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
> +            astream = s->streams[i];
> +        }
> +    }

this shouldt be needed
just keep track of the stram index that the table belongs to
that is add a flv->keyframe_stream_index


> +
> +    AVStream *streams[2] = {vstream, astream};
> +    for (i = 0; i < 2; i++) {
> +        current_stream = streams[i];
> +        if (current_stream && current_stream->nb_index_entries==0) {
> +            for (j = 0; j < flv->keyframe_count; j++) {
> +                av_add_index_entry(current_stream, flv->keyframe_filepositions[j], flv->keyframe_times[j] * 1000,
> +                                   0, 0, AVINDEX_KEYFRAME);
> +            }
> +        }
> +    }
> +
> +    // free keyframe index only if all expected streams have been created
> +    if (((vstream && vstream->nb_index_entries>0) || !flv->vhead_exists) &&
> +        ((astream && astream->nb_index_entries>0) || !flv->ahead_exists)) {
> +        av_freep(&flv->keyframe_times);
> +        av_freep(&flv->keyframe_filepositions);
> +        flv->keyframe_count = 0;
> +    }
> +}

spliting add_keyframes_index() out must be in a seperate patch

also i would not trust the *head_exists flags, IIRC they can be
wrong and they are not needed
the function should just take the table load it with
av_add_index_entry() and free the table.
The rest should not be needed
should be much simpler unless iam missing something


[...]
> @@ -305,8 +348,7 @@ 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)
> +static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, int64_t max_pos)
>  {
>      FLVContext *flv       = s->priv_data;
>      unsigned int timeslen = 0, fileposlen = 0, i;
> @@ -316,7 +358,7 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc,
>      int ret                = AVERROR(ENOSYS);
>      int64_t initial_pos    = avio_tell(ioc);
>  
> -    if (vstream->nb_index_entries>0) {
> +    if (flv->keyframe_count > 0) {
>          av_log(s, AV_LOG_WARNING, "Skipping duplicate index\n");
>          return 0;
>      }

this looks wrong, a file can contain an index for each stream
that shouldnt trigger a warning, only if there are 2 for the same
stream its a duplicate


[...]
Xinzheng Zhang July 26, 2016, 5:31 p.m. UTC | #2
On Wed, Jul 27, 2016 at 1:12 AM, Michael Niedermayer
<michael@niedermayer.cc> wrote:
> On Tue, Jul 26, 2016 at 08:17:46PM +0800, Xinzheng Zhang wrote:
>> ---
>>  libavformat/flvdec.c | 84 ++++++++++++++++++++++++++++++++++++++++++----------
>>  1 file changed, 69 insertions(+), 15 deletions(-)
>>
>> diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
>> index 2bf1e05..82b9f83 100644
>> --- a/libavformat/flvdec.c
>> +++ b/libavformat/flvdec.c
>> @@ -61,6 +61,12 @@ typedef struct FLVContext {
>>
>>      int broken_sizes;
>>      int sum_flv_tag_size;
>> +
>> +    int vhead_exists;
>> +    int ahead_exists;
>> +    int keyframe_count;
>> +    int64_t *keyframe_times;
>> +    int64_t *keyframe_filepositions;
>>  } FLVContext;
>>
>>  static int probe(AVProbeData *p, int live)
>> @@ -92,6 +98,42 @@ static int live_flv_probe(AVProbeData *p)
>>      return probe(p, 1);
>>  }
>>
>> +static void add_keyframes_index(AVFormatContext *s)
>> +{
>> +    FLVContext *flv           = s->priv_data;
>> +    AVStream *current_stream  = NULL;
>> +    AVStream *vstream         = NULL;
>> +    AVStream *astream         = NULL;
>> +    unsigned int i,j                ;
>> +
>> +    for (i = 0; i< s->nb_streams; i++) {
>> +        if (s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
>> +            vstream = s->streams[i];
>> +        } else if (s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
>> +            astream = s->streams[i];
>> +        }
>> +    }
>
> this shouldt be needed
> just keep track of the stram index that the table belongs to
> that is add a flv->keyframe_stream_index
>
>
ok

>> +
>> +    AVStream *streams[2] = {vstream, astream};
>> +    for (i = 0; i < 2; i++) {
>> +        current_stream = streams[i];
>> +        if (current_stream && current_stream->nb_index_entries==0) {
>> +            for (j = 0; j < flv->keyframe_count; j++) {
>> +                av_add_index_entry(current_stream, flv->keyframe_filepositions[j], flv->keyframe_times[j] * 1000,
>> +                                   0, 0, AVINDEX_KEYFRAME);
>> +            }
>> +        }
>> +    }
>> +
>> +    // free keyframe index only if all expected streams have been created
>> +    if (((vstream && vstream->nb_index_entries>0) || !flv->vhead_exists) &&
>> +        ((astream && astream->nb_index_entries>0) || !flv->ahead_exists)) {
>> +        av_freep(&flv->keyframe_times);
>> +        av_freep(&flv->keyframe_filepositions);
>> +        flv->keyframe_count = 0;
>> +    }
>> +}
>
> spliting add_keyframes_index() out must be in a seperate patch
>
> also i would not trust the *head_exists flags, IIRC they can be
> wrong and they are not needed
> the function should just take the table load it with
> av_add_index_entry() and free the table.
> The rest should not be needed
> should be much simpler unless iam missing something
>
>

If I don't trust the head_exists flags, when should I free the index table?
Should I keep the index util both a\v stream have been loaded or keep
it util the flv_read_close().

> [...]
>> @@ -305,8 +348,7 @@ 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)
>> +static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, int64_t max_pos)
>>  {
>>      FLVContext *flv       = s->priv_data;
>>      unsigned int timeslen = 0, fileposlen = 0, i;
>> @@ -316,7 +358,7 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc,
>>      int ret                = AVERROR(ENOSYS);
>>      int64_t initial_pos    = avio_tell(ioc);
>>
>> -    if (vstream->nb_index_entries>0) {
>> +    if (flv->keyframe_count > 0) {
>>          av_log(s, AV_LOG_WARNING, "Skipping duplicate index\n");
>>          return 0;
>>      }
>
> this looks wrong, a file can contain an index for each stream
> that shouldnt trigger a warning, only if there are 2 for the same
> stream its a duplicate
>
>
ok

> [...]
> --
> Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
>
> What does censorship reveal? It reveals fear. -- Julian Assange
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
Michael Niedermayer July 26, 2016, 11:25 p.m. UTC | #3
On Wed, Jul 27, 2016 at 01:31:29AM +0800, XinZheng Zhang wrote:
> On Wed, Jul 27, 2016 at 1:12 AM, Michael Niedermayer
> <michael@niedermayer.cc> wrote:
> > On Tue, Jul 26, 2016 at 08:17:46PM +0800, Xinzheng Zhang wrote:
[...]
> >> +
> >> +    AVStream *streams[2] = {vstream, astream};
> >> +    for (i = 0; i < 2; i++) {
> >> +        current_stream = streams[i];
> >> +        if (current_stream && current_stream->nb_index_entries==0) {
> >> +            for (j = 0; j < flv->keyframe_count; j++) {
> >> +                av_add_index_entry(current_stream, flv->keyframe_filepositions[j], flv->keyframe_times[j] * 1000,
> >> +                                   0, 0, AVINDEX_KEYFRAME);
> >> +            }
> >> +        }
> >> +    }
> >> +
> >> +    // free keyframe index only if all expected streams have been created
> >> +    if (((vstream && vstream->nb_index_entries>0) || !flv->vhead_exists) &&
> >> +        ((astream && astream->nb_index_entries>0) || !flv->ahead_exists)) {
> >> +        av_freep(&flv->keyframe_times);
> >> +        av_freep(&flv->keyframe_filepositions);
> >> +        flv->keyframe_count = 0;
> >> +    }
> >> +}
> >
> > spliting add_keyframes_index() out must be in a seperate patch
> >
> > also i would not trust the *head_exists flags, IIRC they can be
> > wrong and they are not needed
> > the function should just take the table load it with
> > av_add_index_entry() and free the table.
> > The rest should not be needed
> > should be much simpler unless iam missing something
> >
> >
> 
> If I don't trust the head_exists flags, when should I free the index table?
> Should I keep the index util both a\v stream have been loaded or keep
> it util the flv_read_close().

the table was freed after av_add_index_entry()
that should still work fine unless i miss somethig

some cleanup code at close might be needed to catch error conditions
so theres never a memleak

[...]
Michael Niedermayer July 26, 2016, 11:27 p.m. UTC | #4
On Tue, Jul 26, 2016 at 08:17:46PM +0800, Xinzheng Zhang wrote:
> ---
>  libavformat/flvdec.c | 84 ++++++++++++++++++++++++++++++++++++++++++----------
>  1 file changed, 69 insertions(+), 15 deletions(-)

also: someone please fix the spelling&grammer in the commit message:

"avformat/fivdec: cached keyframes before video or audio stream was created"

[...]
Xinzheng Zhang July 27, 2016, 1:56 a.m. UTC | #5
On Wed, Jul 27, 2016 at 7:25 AM, Michael Niedermayer
<michael@niedermayer.cc> wrote:
> On Wed, Jul 27, 2016 at 01:31:29AM +0800, XinZheng Zhang wrote:
>> On Wed, Jul 27, 2016 at 1:12 AM, Michael Niedermayer
>> <michael@niedermayer.cc> wrote:
>> > On Tue, Jul 26, 2016 at 08:17:46PM +0800, Xinzheng Zhang wrote:
> [...]
>> >> +
>> >> +    AVStream *streams[2] = {vstream, astream};
>> >> +    for (i = 0; i < 2; i++) {
>> >> +        current_stream = streams[i];
>> >> +        if (current_stream && current_stream->nb_index_entries==0) {
>> >> +            for (j = 0; j < flv->keyframe_count; j++) {
>> >> +                av_add_index_entry(current_stream, flv->keyframe_filepositions[j], flv->keyframe_times[j] * 1000,
>> >> +                                   0, 0, AVINDEX_KEYFRAME);
>> >> +            }
>> >> +        }
>> >> +    }
>> >> +
>> >> +    // free keyframe index only if all expected streams have been created
>> >> +    if (((vstream && vstream->nb_index_entries>0) || !flv->vhead_exists) &&
>> >> +        ((astream && astream->nb_index_entries>0) || !flv->ahead_exists)) {
>> >> +        av_freep(&flv->keyframe_times);
>> >> +        av_freep(&flv->keyframe_filepositions);
>> >> +        flv->keyframe_count = 0;
>> >> +    }
>> >> +}
>> >
>> > spliting add_keyframes_index() out must be in a seperate patch
>> >
>> > also i would not trust the *head_exists flags, IIRC they can be
>> > wrong and they are not needed
>> > the function should just take the table load it with
>> > av_add_index_entry() and free the table.
>> > The rest should not be needed
>> > should be much simpler unless iam missing something
>> >
>> >
>>
>> If I don't trust the head_exists flags, when should I free the index table?
>> Should I keep the index util both a\v stream have been loaded or keep
>> it util the flv_read_close().
>
> the table was freed after av_add_index_entry()
> that should still work fine unless i miss somethig
>

[meta]-[v]-[v]..........................[a]
In this case both video and audio stream share the same index table.
I am not know whether the audio stream exists until the first audio
packet parsed.
I thought that I should keep the index until all the streams have been loaded.

> some cleanup code at close might be needed to catch error conditions
> so theres never a memleak
>
> [...]
> --
> Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
>
> Dictatorship naturally arises out of democracy, and the most aggravated
> form of tyranny and slavery out of the most extreme liberty. -- Plato
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
Michael Niedermayer July 27, 2016, 2:17 a.m. UTC | #6
On Wed, Jul 27, 2016 at 09:56:02AM +0800, XinZheng Zhang wrote:
> On Wed, Jul 27, 2016 at 7:25 AM, Michael Niedermayer
> <michael@niedermayer.cc> wrote:
> > On Wed, Jul 27, 2016 at 01:31:29AM +0800, XinZheng Zhang wrote:
> >> On Wed, Jul 27, 2016 at 1:12 AM, Michael Niedermayer
> >> <michael@niedermayer.cc> wrote:
> >> > On Tue, Jul 26, 2016 at 08:17:46PM +0800, Xinzheng Zhang wrote:
> > [...]
> >> >> +
> >> >> +    AVStream *streams[2] = {vstream, astream};
> >> >> +    for (i = 0; i < 2; i++) {
> >> >> +        current_stream = streams[i];
> >> >> +        if (current_stream && current_stream->nb_index_entries==0) {
> >> >> +            for (j = 0; j < flv->keyframe_count; j++) {
> >> >> +                av_add_index_entry(current_stream, flv->keyframe_filepositions[j], flv->keyframe_times[j] * 1000,
> >> >> +                                   0, 0, AVINDEX_KEYFRAME);
> >> >> +            }
> >> >> +        }
> >> >> +    }
> >> >> +
> >> >> +    // free keyframe index only if all expected streams have been created
> >> >> +    if (((vstream && vstream->nb_index_entries>0) || !flv->vhead_exists) &&
> >> >> +        ((astream && astream->nb_index_entries>0) || !flv->ahead_exists)) {
> >> >> +        av_freep(&flv->keyframe_times);
> >> >> +        av_freep(&flv->keyframe_filepositions);
> >> >> +        flv->keyframe_count = 0;
> >> >> +    }
> >> >> +}
> >> >
> >> > spliting add_keyframes_index() out must be in a seperate patch
> >> >
> >> > also i would not trust the *head_exists flags, IIRC they can be
> >> > wrong and they are not needed
> >> > the function should just take the table load it with
> >> > av_add_index_entry() and free the table.
> >> > The rest should not be needed
> >> > should be much simpler unless iam missing something
> >> >
> >> >
> >>
> >> If I don't trust the head_exists flags, when should I free the index table?
> >> Should I keep the index util both a\v stream have been loaded or keep
> >> it util the flv_read_close().
> >
> > the table was freed after av_add_index_entry()
> > that should still work fine unless i miss somethig
> >
> 
> [meta]-[v]-[v]..........................[a]
> In this case both video and audio stream share the same index table.
> I am not know whether the audio stream exists until the first audio
> packet parsed.
> I thought that I should keep the index until all the streams have been loaded.

in the example above the video key frame table would be loaded
and added into the video stream once it has been created, and
freed afterwards
nothing is done with audio (currently or after the change)

if the audio table is prior the video one its loaded and freed once
the video table is encountered

do i miss something ?

[...]
Xinzheng Zhang July 27, 2016, 2:33 a.m. UTC | #7
On Wed, Jul 27, 2016 at 10:17 AM, Michael Niedermayer
<michael@niedermayer.cc> wrote:
> On Wed, Jul 27, 2016 at 09:56:02AM +0800, XinZheng Zhang wrote:
>> On Wed, Jul 27, 2016 at 7:25 AM, Michael Niedermayer
>> <michael@niedermayer.cc> wrote:
>> > On Wed, Jul 27, 2016 at 01:31:29AM +0800, XinZheng Zhang wrote:
>> >> On Wed, Jul 27, 2016 at 1:12 AM, Michael Niedermayer
>> >> <michael@niedermayer.cc> wrote:
>> >> > On Tue, Jul 26, 2016 at 08:17:46PM +0800, Xinzheng Zhang wrote:
>> > [...]
>> >> >> +
>> >> >> +    AVStream *streams[2] = {vstream, astream};
>> >> >> +    for (i = 0; i < 2; i++) {
>> >> >> +        current_stream = streams[i];
>> >> >> +        if (current_stream && current_stream->nb_index_entries==0) {
>> >> >> +            for (j = 0; j < flv->keyframe_count; j++) {
>> >> >> +                av_add_index_entry(current_stream, flv->keyframe_filepositions[j], flv->keyframe_times[j] * 1000,
>> >> >> +                                   0, 0, AVINDEX_KEYFRAME);
>> >> >> +            }
>> >> >> +        }
>> >> >> +    }
>> >> >> +
>> >> >> +    // free keyframe index only if all expected streams have been created
>> >> >> +    if (((vstream && vstream->nb_index_entries>0) || !flv->vhead_exists) &&
>> >> >> +        ((astream && astream->nb_index_entries>0) || !flv->ahead_exists)) {
>> >> >> +        av_freep(&flv->keyframe_times);
>> >> >> +        av_freep(&flv->keyframe_filepositions);
>> >> >> +        flv->keyframe_count = 0;
>> >> >> +    }
>> >> >> +}
>> >> >
>> >> > spliting add_keyframes_index() out must be in a seperate patch
>> >> >
>> >> > also i would not trust the *head_exists flags, IIRC they can be
>> >> > wrong and they are not needed
>> >> > the function should just take the table load it with
>> >> > av_add_index_entry() and free the table.
>> >> > The rest should not be needed
>> >> > should be much simpler unless iam missing something
>> >> >
>> >> >
>> >>
>> >> If I don't trust the head_exists flags, when should I free the index table?
>> >> Should I keep the index util both a\v stream have been loaded or keep
>> >> it util the flv_read_close().
>> >
>> > the table was freed after av_add_index_entry()
>> > that should still work fine unless i miss somethig
>> >
>>
>> [meta]-[v]-[v]..........................[a]
>> In this case both video and audio stream share the same index table.
>> I am not know whether the audio stream exists until the first audio
>> packet parsed.
>> I thought that I should keep the index until all the streams have been loaded.
>
> in the example above the video key frame table would be loaded
> and added into the video stream once it has been created, and
> freed afterwards
> nothing is done with audio (currently or after the change)
>
> if the audio table is prior the video one its loaded and freed once
> the video table is encountered
>
> do i miss something ?
>

Now I understand it.
Before that I thought that both streams have to install the index table.

> [...]
> --
> Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
>
> There will always be a question for which you do not know the correct answer.
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>

Patch

diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
index 2bf1e05..82b9f83 100644
--- a/libavformat/flvdec.c
+++ b/libavformat/flvdec.c
@@ -61,6 +61,12 @@  typedef struct FLVContext {
 
     int broken_sizes;
     int sum_flv_tag_size;
+
+    int vhead_exists;
+    int ahead_exists;
+    int keyframe_count;
+    int64_t *keyframe_times;
+    int64_t *keyframe_filepositions;
 } FLVContext;
 
 static int probe(AVProbeData *p, int live)
@@ -92,6 +98,42 @@  static int live_flv_probe(AVProbeData *p)
     return probe(p, 1);
 }
 
+static void add_keyframes_index(AVFormatContext *s)
+{
+    FLVContext *flv           = s->priv_data;
+    AVStream *current_stream  = NULL;
+    AVStream *vstream         = NULL;
+    AVStream *astream         = NULL;
+    unsigned int i,j                ;
+
+    for (i = 0; i< s->nb_streams; i++) {
+        if (s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
+            vstream = s->streams[i];
+        } else if (s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
+            astream = s->streams[i];
+        }
+    }
+
+    AVStream *streams[2] = {vstream, astream};
+    for (i = 0; i < 2; i++) {
+        current_stream = streams[i];
+        if (current_stream && current_stream->nb_index_entries==0) {
+            for (j = 0; j < flv->keyframe_count; j++) {
+                av_add_index_entry(current_stream, flv->keyframe_filepositions[j], flv->keyframe_times[j] * 1000,
+                                   0, 0, AVINDEX_KEYFRAME);
+            }
+        }
+    }
+
+    // free keyframe index only if all expected streams have been created
+    if (((vstream && vstream->nb_index_entries>0) || !flv->vhead_exists) &&
+        ((astream && astream->nb_index_entries>0) || !flv->ahead_exists)) {
+        av_freep(&flv->keyframe_times);
+        av_freep(&flv->keyframe_filepositions);
+        flv->keyframe_count = 0;
+    }
+}
+
 static AVStream *create_stream(AVFormatContext *s, int codec_type)
 {
     AVStream *st = avformat_new_stream(s, NULL);
@@ -104,6 +146,7 @@  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 */
+    add_keyframes_index(s);
     return st;
 }
 
@@ -305,8 +348,7 @@  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)
+static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, int64_t max_pos)
 {
     FLVContext *flv       = s->priv_data;
     unsigned int timeslen = 0, fileposlen = 0, i;
@@ -316,7 +358,7 @@  static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc,
     int ret                = AVERROR(ENOSYS);
     int64_t initial_pos    = avio_tell(ioc);
 
-    if (vstream->nb_index_entries>0) {
+    if (flv->keyframe_count > 0) {
         av_log(s, AV_LOG_WARNING, "Skipping duplicate index\n");
         return 0;
     }
@@ -324,6 +366,10 @@  static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc,
     if (s->flags & AVFMT_FLAG_IGNIDX)
         return 0;
 
+    av_freep(&flv->keyframe_times);
+    av_freep(&flv->keyframe_filepositions);
+    flv->keyframe_count = 0;
+
     while (avio_tell(ioc) < max_pos - 2 &&
            amf_get_string(ioc, str_val, sizeof(str_val)) > 0) {
         int64_t **current_array;
@@ -366,17 +412,17 @@  static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc,
             break;
         }
     }
-
     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 (i < 2) {
-                flv->validate_index[i].pos = filepositions[i];
-                flv->validate_index[i].dts = times[i] * 1000;
-                flv->validate_count        = i + 1;
-            }
+        for (i = 0; i < FFMIN(2,fileposlen); i++) {
+            flv->validate_index[i].pos = filepositions[i];
+            flv->validate_index[i].dts = times[i] * 1000;
+            flv->validate_count        = i + 1;
         }
+        flv->keyframe_times = times;
+        flv->keyframe_filepositions = filepositions;
+        flv->keyframe_count = timeslen;
+        times = NULL;
+        filepositions = NULL;
     } else {
 invalid:
         av_log(s, AV_LOG_WARNING, "Invalid keyframes object, skipping.\n");
@@ -418,12 +464,14 @@  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,
                                       max_pos) < 0)
                 av_log(s, AV_LOG_ERROR, "Keyframe index parsing failed\n");
+            else
+                add_keyframes_index(s);
 
         while (avio_tell(ioc) < max_pos - 2 &&
                amf_get_string(ioc, str_val, sizeof(str_val)) > 0)
@@ -631,9 +679,13 @@  static int flv_read_header(AVFormatContext *s)
 {
     FLVContext *flv = s->priv_data;
     int offset;
+    int flags;
 
     avio_skip(s->pb, 4);
-    avio_r8(s->pb); // flags
+    flags = avio_r8(s->pb); // flags
+
+    flv->vhead_exists = flags & FLV_HEADER_FLAG_HASVIDEO;
+    flv->ahead_exists = flags & FLV_HEADER_FLAG_HASAUDIO;
 
     s->ctx_flags |= AVFMTCTX_NOHEADER;
 
@@ -653,6 +705,8 @@  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->keyframe_times);
+    av_freep(&flv->keyframe_filepositions);
     return 0;
 }