Merge pull request #4562 from FernetMenta/flac
authorTrent Nelson <trent.a.b.nelson@gmail.com>
Tue, 15 Apr 2014 17:55:01 +0000 (11:55 -0600)
committerTrent Nelson <trent.a.b.nelson@gmail.com>
Tue, 15 Apr 2014 18:16:35 +0000 (12:16 -0600)
ffmpeg backport: improve seeking in flac files

lib/ffmpeg/libavcodec/flac_parser.c
lib/ffmpeg/libavformat/flacdec.c
lib/ffmpeg/patches/0072-flac-demuxer-improve-seeking.patch [new file with mode: 0644]

index e2c6744..0b7bf9b 100644 (file)
@@ -468,6 +468,14 @@ static int get_best_header(FLACParseContext* fpc, const uint8_t **poutbuf,
                                         &fpc->wrap_buf,
                                         &fpc->wrap_buf_allocated_size);
 
+
+    if (fpc->pc->flags & PARSER_FLAG_USE_CODEC_TS){
+        if (header->fi.is_var_size)
+          fpc->pc->pts = header->fi.frame_or_sample_num;
+        else if (header->best_child)
+          fpc->pc->pts = header->fi.frame_or_sample_num * header->fi.blocksize;
+    }
+
     fpc->best_header_valid = 0;
     /* Return the negative overread index so the client can compute pos.
        This should be the amount overread to the beginning of the child */
index ecc47e6..66c8809 100644 (file)
@@ -284,12 +284,57 @@ static int flac_probe(AVProbeData *p)
     else                                            return AVPROBE_SCORE_MAX/2;
 }
 
+static av_unused int64_t flac_read_timestamp(AVFormatContext *s, int stream_index,
+                                             int64_t *ppos, int64_t pos_limit)
+{
+    AVPacket pkt, out_pkt;
+    AVStream *st = s->streams[stream_index];
+    int ret;
+
+    if (avio_seek(s->pb, *ppos, SEEK_SET) < 0)
+        return AV_NOPTS_VALUE;
+
+    av_init_packet(&pkt);
+    st->parser = av_parser_init(st->codec->codec_id);
+    if (!st->parser){
+        return AV_NOPTS_VALUE;
+    }
+    st->parser->flags |= PARSER_FLAG_USE_CODEC_TS;
+
+    for (;;){
+        ret = ff_raw_read_partial_packet(s, &pkt);
+        if (ret < 0){
+            if (ret == AVERROR(EAGAIN))
+                continue;
+            else
+                return AV_NOPTS_VALUE;
+        }
+        av_init_packet(&out_pkt);
+        ret = av_parser_parse2(st->parser, st->codec,
+                               &out_pkt.data, &out_pkt.size, pkt.data, pkt.size,
+                               pkt.pts, pkt.dts, *ppos);
+
+        if (out_pkt.size){
+            int size = out_pkt.size;
+            av_free_packet(&out_pkt);
+            if (st->parser->pts != AV_NOPTS_VALUE){
+                // seeking may not have started from beginning of a frame
+                // calculate frame start position from next frame backwards
+                *ppos = st->parser->next_frame_offset - size;
+                return st->parser->pts;
+            }
+        }
+    }
+    return AV_NOPTS_VALUE;
+}
+
 AVInputFormat ff_flac_demuxer = {
     .name           = "flac",
     .long_name      = NULL_IF_CONFIG_SMALL("raw FLAC"),
     .read_probe     = flac_probe,
     .read_header    = flac_read_header,
     .read_packet    = ff_raw_read_partial_packet,
+    .read_timestamp = flac_read_timestamp,
     .flags          = AVFMT_GENERIC_INDEX,
     .extensions     = "flac",
     .raw_codec_id   = AV_CODEC_ID_FLAC,
diff --git a/lib/ffmpeg/patches/0072-flac-demuxer-improve-seeking.patch b/lib/ffmpeg/patches/0072-flac-demuxer-improve-seeking.patch
new file mode 100644 (file)
index 0000000..a6b6488
--- /dev/null
@@ -0,0 +1,94 @@
+From 0c510ff6acea4a9afc049006ad8a173256aa8290 Mon Sep 17 00:00:00 2001
+From: Rainer Hochecker <fernetmenta@online.de>
+Date: Sat, 12 Apr 2014 18:13:32 +0200
+Subject: [PATCH] flac demuxer: improve seeking
+
+---
+ lib/ffmpeg/libavcodec/flac_parser.c |  8 +++++++
+ lib/ffmpeg/libavformat/flacdec.c    | 45 +++++++++++++++++++++++++++++++++++++
+ 2 files changed, 53 insertions(+)
+
+diff --git a/lib/ffmpeg/libavcodec/flac_parser.c b/lib/ffmpeg/libavcodec/flac_parser.c
+index e2c6744..0b7bf9b 100644
+--- a/lib/ffmpeg/libavcodec/flac_parser.c
++++ b/lib/ffmpeg/libavcodec/flac_parser.c
+@@ -468,6 +468,14 @@ static int get_best_header(FLACParseContext* fpc, const uint8_t **poutbuf,
+                                         &fpc->wrap_buf,
+                                         &fpc->wrap_buf_allocated_size);
++
++    if (fpc->pc->flags & PARSER_FLAG_USE_CODEC_TS){
++        if (header->fi.is_var_size)
++          fpc->pc->pts = header->fi.frame_or_sample_num;
++        else if (header->best_child)
++          fpc->pc->pts = header->fi.frame_or_sample_num * header->fi.blocksize;
++    }
++
+     fpc->best_header_valid = 0;
+     /* Return the negative overread index so the client can compute pos.
+        This should be the amount overread to the beginning of the child */
+diff --git a/lib/ffmpeg/libavformat/flacdec.c b/lib/ffmpeg/libavformat/flacdec.c
+index ecc47e6..66c8809 100644
+--- a/lib/ffmpeg/libavformat/flacdec.c
++++ b/lib/ffmpeg/libavformat/flacdec.c
+@@ -284,12 +284,57 @@ static int flac_probe(AVProbeData *p)
+     else                                            return AVPROBE_SCORE_MAX/2;
+ }
++static av_unused int64_t flac_read_timestamp(AVFormatContext *s, int stream_index,
++                                             int64_t *ppos, int64_t pos_limit)
++{
++    AVPacket pkt, out_pkt;
++    AVStream *st = s->streams[stream_index];
++    int ret;
++
++    if (avio_seek(s->pb, *ppos, SEEK_SET) < 0)
++        return AV_NOPTS_VALUE;
++
++    av_init_packet(&pkt);
++    st->parser = av_parser_init(st->codec->codec_id);
++    if (!st->parser){
++        return AV_NOPTS_VALUE;
++    }
++    st->parser->flags |= PARSER_FLAG_USE_CODEC_TS;
++
++    for (;;){
++        ret = ff_raw_read_partial_packet(s, &pkt);
++        if (ret < 0){
++            if (ret == AVERROR(EAGAIN))
++                continue;
++            else
++                return AV_NOPTS_VALUE;
++        }
++        av_init_packet(&out_pkt);
++        ret = av_parser_parse2(st->parser, st->codec,
++                               &out_pkt.data, &out_pkt.size, pkt.data, pkt.size,
++                               pkt.pts, pkt.dts, *ppos);
++
++        if (out_pkt.size){
++            int size = out_pkt.size;
++            av_free_packet(&out_pkt);
++            if (st->parser->pts != AV_NOPTS_VALUE){
++                // seeking may not have started from beginning of a frame
++                // calculate frame start position from next frame backwards
++                *ppos = st->parser->next_frame_offset - size;
++                return st->parser->pts;
++            }
++        }
++    }
++    return AV_NOPTS_VALUE;
++}
++
+ AVInputFormat ff_flac_demuxer = {
+     .name           = "flac",
+     .long_name      = NULL_IF_CONFIG_SMALL("raw FLAC"),
+     .read_probe     = flac_probe,
+     .read_header    = flac_read_header,
+     .read_packet    = ff_raw_read_partial_packet,
++    .read_timestamp = flac_read_timestamp,
+     .flags          = AVFMT_GENERIC_INDEX,
+     .extensions     = "flac",
+     .raw_codec_id   = AV_CODEC_ID_FLAC,
+-- 
+1.9.1
+