[FFmpeg-devel] [PATCH v3 3/3] aadec: fix seeking in mp3 content

Karsten Otto ottoka at posteo.de
Thu Jun 21 19:58:26 EEST 2018


MP3 frames may not be aligned to aa chunk boundaries. After seeking,
scan for the next valid frame header. Then truncate the packet, and
also adjust timestamp information accordingly.
---
 libavformat/aadec.c | 33 ++++++++++++++++++++++++++++-----
 1 file changed, 28 insertions(+), 5 deletions(-)

diff --git a/libavformat/aadec.c b/libavformat/aadec.c
index b009c9deca..3bb8cd0768 100644
--- a/libavformat/aadec.c
+++ b/libavformat/aadec.c
@@ -50,6 +50,7 @@ typedef struct AADemuxContext {
     int64_t current_chapter_size;
     int64_t content_start;
     int64_t content_end;
+    int did_seek;
 } AADemuxContext;
 
 static int get_second_size(char *codec_name)
@@ -205,6 +206,7 @@ static int aa_read_header(AVFormatContext *s)
     }
     start = TOC[largest_idx].offset;
     avio_seek(pb, start, SEEK_SET);
+    c->did_seek = 0;
 
     // extract chapter positions. since all formats have constant bit rate, use it
     // as time base in bytes/s, for easy stream position <-> timestamp conversion
@@ -242,7 +244,7 @@ static int aa_read_packet(AVFormatContext *s, AVPacket *pkt)
     int trailing_bytes;
     int blocks;
     uint8_t buf[MAX_CODEC_SECOND_SIZE * 2];
-    int written = 0;
+    int written = 0, offset = 0;
     int ret;
     AADemuxContext *c = s->priv_data;
     uint64_t pos = avio_tell(s->pb);
@@ -295,10 +297,32 @@ static int aa_read_packet(AVFormatContext *s, AVPacket *pkt)
     if (c->current_chapter_size <= 0)
         c->current_chapter_size = 0;
 
-    ret = av_new_packet(pkt, written);
+    // re-init timestamps after seeking
+    if (c->did_seek) {
+        c->did_seek = 0;
+
+        if (s->streams[0]->codecpar->codec_id == AV_CODEC_ID_MP3) {
+            for (; offset < written - 2; ++offset) {
+                // find mp3 header: sync, v2, layer3, 32kbps, non-reserved sample rate
+                if ((buf[offset + 0] & 0xff) == 0xff &&
+                    (buf[offset + 1] & 0xfe) == 0xf2 &&
+                    (buf[offset + 2] & 0xf0) == 0x40 &&
+                    (buf[offset + 2] & 0x0c) != 0x0c)
+                        break;
+            }
+            if (offset == written - 2)
+                offset = 0; // not found, e.g. chapter end chunk; just use as is
+        }
+        ff_update_cur_dts(s, s->streams[0],
+            (pos + offset - c->content_start - CHAPTER_HEADER_SIZE * (c->chapter_idx - 1))
+            * TIMEPREC);
+    }
+
+    // create packet
+    ret = av_new_packet(pkt, written - offset);
     if (ret < 0)
         return ret;
-    memcpy(pkt->data, buf, written);
+    memcpy(pkt->data, buf + offset, written - offset);
     pkt->pos = pos;
 
     return 0;
@@ -343,8 +367,7 @@ static int aa_read_seek(AVFormatContext *s,
     c->current_codec_second_size = c->codec_second_size;
     c->current_chapter_size = chapter_size - chapter_pos;
     c->chapter_idx = 1 + chapter_idx;
-
-    ff_update_cur_dts(s, s->streams[0], ch->start + chapter_pos * TIMEPREC);
+    c->did_seek = 1;
 
     return 1;
 }
-- 
2.14.3 (Apple Git-98)



More information about the ffmpeg-devel mailing list