[2/7] flvdec: Export new AAC/H.264 extradata as side data on the next packet

Message ID 1324038961-51634-2-git-send-email-martin@martin.st
State Committed
Headers show

Commit Message

Martin Storsjö Dec. 16, 2011, 12:35 p.m.
Compared to just overwriting the old extradata, this has the
advantage of letting the decoder know exactly when the
extradata changed (otherwise it is changed immediately when the
new extradata packet is demuxed, even if there's old queued packets
awaiting to be decoded). This makes it easier for decoders to
actually react to the change, so they won't have to inspect
the extradata for each packet to see if it might have changed.

This works when sequentially playing a file with sample rate
changes, but if seeking past a new extradata packet in the
file, it obviously doesn't work properly. That case doesn't
work in flash player either, so it's probably ok not to handle
it.
---
 libavformat/flvdec.c |   39 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 39 insertions(+), 0 deletions(-)

Patch

diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
index 4fc5a49..28a45a9 100644
--- a/libavformat/flvdec.c
+++ b/libavformat/flvdec.c
@@ -41,6 +41,8 @@ 
 
 typedef struct {
     int wrong_dts; ///< wrong dts due to negative cts
+    uint8_t *new_extradata[2];
+    int      new_extradata_size[2];
 } FLVContext;
 
 static int flv_probe(AVProbeData *p)
@@ -401,6 +403,14 @@  static int flv_read_header(AVFormatContext *s,
     return 0;
 }
 
+static int flv_read_close(AVFormatContext *s)
+{
+    FLVContext *flv = s->priv_data;
+    av_freep(&flv->new_extradata[0]);
+    av_freep(&flv->new_extradata[1]);
+    return 0;
+}
+
 static int flv_get_extradata(AVFormatContext *s, AVStream *st, int size)
 {
     av_free(st->codec->extradata);
@@ -412,6 +422,18 @@  static int flv_get_extradata(AVFormatContext *s, AVStream *st, int size)
     return 0;
 }
 
+static int flv_queue_extradata(FLVContext *flv, AVIOContext *pb, int stream,
+                               int size)
+{
+    av_free(flv->new_extradata[stream]);
+    flv->new_extradata[stream] = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
+    if (!flv->new_extradata[stream])
+        return AVERROR(ENOMEM);
+    flv->new_extradata_size[stream] = size;
+    avio_read(pb, flv->new_extradata[stream], size);
+    return 0;
+}
+
 static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
 {
     FLVContext *flv = s->priv_data;
@@ -529,6 +551,12 @@  static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
                 dts = AV_NOPTS_VALUE;
         }
         if (type == 0) {
+            if (st->codec->extradata) {
+                if ((ret = flv_queue_extradata(flv, s->pb, is_audio, size)) < 0)
+                    return ret;
+                ret = AVERROR(EAGAIN);
+                goto leave;
+            }
             if ((ret = flv_get_extradata(s, st, size)) < 0)
                 return ret;
             if (st->codec->codec_id == CODEC_ID_AAC) {
@@ -565,6 +593,16 @@  static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
     pkt->dts = dts;
     pkt->pts = pts == AV_NOPTS_VALUE ? dts : pts;
     pkt->stream_index = st->index;
+    if (flv->new_extradata[is_audio]) {
+        uint8_t *side = av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
+                                                flv->new_extradata_size[is_audio]);
+        if (side) {
+            memcpy(side, flv->new_extradata[is_audio],
+                   flv->new_extradata_size[is_audio]);
+            av_freep(&flv->new_extradata[is_audio]);
+            flv->new_extradata_size[is_audio] = 0;
+        }
+    }
 
     if (is_audio || ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY))
         pkt->flags |= AV_PKT_FLAG_KEY;
@@ -618,6 +656,7 @@  AVInputFormat ff_flv_demuxer = {
 #if 0
     .read_seek2 = flv_read_seek2,
 #endif
+    .read_close     = flv_read_close,
     .extensions = "flv",
     .value = CODEC_ID_FLV1,
 };