]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/bink.c
lavf/bink: Support Monkey Island 4 (SMUSH) files.
[ffmpeg] / libavformat / bink.c
index b95c83d97ded8585a654dded59b2429fe49e0d8b..646d874461131ff26ece459a90e98bb9366bb1cc 100644 (file)
@@ -45,6 +45,7 @@ enum BinkAudFlags {
 #define BINK_MAX_AUDIO_TRACKS   256
 #define BINK_MAX_WIDTH          7680
 #define BINK_MAX_HEIGHT         4800
+#define SMUSH_BLOCK_SIZE        512
 
 typedef struct BinkDemuxContext {
     uint32_t file_size;
@@ -55,12 +56,15 @@ typedef struct BinkDemuxContext {
     int64_t audio_pts[BINK_MAX_AUDIO_TRACKS];
 
     uint32_t remain_packet_size;
+    int smush_size;
 } BinkDemuxContext;
 
 static int probe(AVProbeData *p)
 {
     const uint8_t *b = p->buf;
+    int smush = AV_RN32(p->buf) == AV_RN32("SMUS");
 
+    do {
     if (((b[0] == 'B' && b[1] == 'I' && b[2] == 'K' &&
          (b[3] == 'b' || b[3] == 'f' || b[3] == 'g' || b[3] == 'h' || b[3] == 'i')) ||
          (b[0] == 'K' && b[1] == 'B' && b[2] == '2' && /* Bink 2 */
@@ -70,6 +74,8 @@ static int probe(AVProbeData *p)
         AV_RL32(b+24) > 0 && AV_RL32(b+24) <= BINK_MAX_HEIGHT &&
         AV_RL32(b+28) > 0 && AV_RL32(b+32) > 0)  // fps num,den
         return AVPROBE_SCORE_MAX;
+        b += SMUSH_BLOCK_SIZE;
+    } while (smush && b < p->buf + p->buf_size - 32);
     return 0;
 }
 
@@ -90,6 +96,17 @@ static int read_header(AVFormatContext *s)
         return AVERROR(ENOMEM);
 
     vst->codecpar->codec_tag = avio_rl32(pb);
+    if (vst->codecpar->codec_tag == AV_RL32("SMUS")) {
+        do {
+            bink->smush_size += SMUSH_BLOCK_SIZE;
+            avio_skip(pb, SMUSH_BLOCK_SIZE - 4);
+            vst->codecpar->codec_tag = avio_rl32(pb);
+        } while (!avio_feof(pb) && (vst->codecpar->codec_tag & 0xFFFFFF) != AV_RL32("BIK"));
+        if (avio_feof(pb)) {
+            av_log(s, AV_LOG_ERROR, "invalid SMUSH header: BIK not found\n");
+            return AVERROR_INVALIDDATA;
+        }
+    }
 
     bink->file_size = avio_rl32(pb) + 8;
     vst->duration   = avio_rl32(pb);
@@ -195,7 +212,7 @@ static int read_header(AVFormatContext *s)
     }
 
     if (vst->index_entries)
-        avio_seek(pb, vst->index_entries[0].pos, SEEK_SET);
+        avio_seek(pb, vst->index_entries[0].pos + bink->smush_size, SEEK_SET);
     else
         avio_skip(pb, 4);
 
@@ -279,7 +296,7 @@ static int read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, in
         return -1;
 
     /* seek to the first frame */
-    if (avio_seek(s->pb, vst->index_entries[0].pos, SEEK_SET) < 0)
+    if (avio_seek(s->pb, vst->index_entries[0].pos + bink->smush_size, SEEK_SET) < 0)
         return -1;
 
     bink->video_pts = 0;