[FFmpeg-devel] [PATCH] avformat/mp3dec: improve junk skipping heuristic

wm4 nfxjfg at googlemail.com
Fri Oct 16 20:04:08 CEST 2015


Commit 2b3e9bbfb529e6bde238aeb511b55ebe461664c8 caused problems for a
certain API user:

https://code.google.com/p/chromium/issues/detail?id=537725
https://code.google.com/p/chromium/issues/detail?id=542032

The problem seems rather arbitrary, because if there's junk, anything
can happen. In this case, the imperfect junk skipping just caused it to
read different junk, from what I can see.

We can improve the accuracy of junk detection by a lot by checking if 2
consecutive frames use the same configuration. While in theory it might
be completely fine for the 1st frame to have a different format than the
2nd frame, it's exceedingly unlikely, and I can't think of a legitimate
use-case.

This is approximately the same mpg123 does for junk skipping, and the
set of compared header bits is exactly the same.
---
The reason Chromium had so much problems with this is that they don't
allow mid-stream format changes at all, and the junk triggered format
changes.

(Would be nice if Google paid me for this.)
---
 libavformat/mp3dec.c | 25 ++++++++++++++++++-------
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/libavformat/mp3dec.c b/libavformat/mp3dec.c
index d3080d7..e7b6234 100644
--- a/libavformat/mp3dec.c
+++ b/libavformat/mp3dec.c
@@ -54,7 +54,7 @@ typedef struct {
     int is_cbr;
 } MP3DecContext;
 
-static int check(AVIOContext *pb, int64_t pos);
+static int check(AVIOContext *pb, int64_t pos, uint32_t *header);
 
 /* mp3 read */
 
@@ -374,12 +374,21 @@ static int mp3_read_header(AVFormatContext *s)
 
     off = avio_tell(s->pb);
     for (i = 0; i < 64 * 1024; i++) {
+        uint32_t header, header2;
+        int frame_size;
         if (!(i&1023))
             ffio_ensure_seekback(s->pb, i + 1024 + 4);
-        if (check(s->pb, off + i) >= 0) {
-            av_log(s, AV_LOG_INFO, "Skipping %d bytes of junk at %"PRId64".\n", i, off);
-            avio_seek(s->pb, off + i, SEEK_SET);
-            break;
+        frame_size = check(s->pb, off + i, &header);
+        if (frame_size > 0) {
+            avio_seek(s->pb, off, SEEK_SET);
+            ffio_ensure_seekback(s->pb, i + 1024 + frame_size + 4);
+            if (check(s->pb, off + i + frame_size, &header2) >= 0 &&
+                (header & 0xFFFEFCF0) == (header2 & 0xFFFEFCF0))
+            {
+                av_log(s, AV_LOG_INFO, "Skipping %d bytes of junk at %"PRId64".\n", i, off);
+                avio_seek(s->pb, off + i, SEEK_SET);
+                break;
+            }
         }
         avio_seek(s->pb, off, SEEK_SET);
     }
@@ -420,7 +429,7 @@ static int mp3_read_packet(AVFormatContext *s, AVPacket *pkt)
 
 #define SEEK_WINDOW 4096
 
-static int check(AVIOContext *pb, int64_t pos)
+static int check(AVIOContext *pb, int64_t pos, uint32_t *ret_header)
 {
     int64_t ret = avio_seek(pb, pos, SEEK_SET);
     unsigned header;
@@ -434,6 +443,8 @@ static int check(AVIOContext *pb, int64_t pos)
     if (avpriv_mpegaudio_decode_header(&sd, header) == 1)
         return -1;
 
+    if (ret_header)
+        *ret_header = header;
     return sd.frame_size;
 }
 
@@ -461,7 +472,7 @@ static int64_t mp3_sync(AVFormatContext *s, int64_t target_pos, int flags)
             continue;
 
         for(j=0; j<MIN_VALID; j++) {
-            ret = check(s->pb, pos);
+            ret = check(s->pb, pos, NULL);
             if(ret < 0)
                 break;
             if ((target_pos - pos)*dir <= 0 && abs(MIN_VALID/2-j) < score) {
-- 
2.5.1



More information about the ffmpeg-devel mailing list