Browse code

Bink demuxer

Originally committed as revision 21569 to svn://svn.ffmpeg.org/ffmpeg/trunk

Peter Ross authored on 2010/01/31 21:35:09
Showing 5 changed files
... ...
@@ -51,6 +51,7 @@ version <next>:
51 51
 - SIPR decoder
52 52
 - Adobe Filmstrip muxer and demuxer
53 53
 - RTP depacketization of H.263
54
+- Bink demuxer
54 55
 
55 56
 
56 57
 
... ...
@@ -58,6 +58,8 @@ library:
58 58
     @tab Audio and video format used in some games by Beam Software.
59 59
 @item Bethesda Softworks VID    @tab   @tab X
60 60
     @tab Used in some games from Bethesda Softworks.
61
+@item Bink                      @tab   @tab X
62
+    @tab Multimedia format used by many games.
61 63
 @item Brute Force & Ignorance   @tab   @tab X
62 64
     @tab Used in the game Flash Traffic: City of Angels.
63 65
 @item Interplay C93             @tab   @tab X
... ...
@@ -42,6 +42,7 @@ OBJS-$(CONFIG_AVM2_MUXER)                += swfenc.o
42 42
 OBJS-$(CONFIG_AVS_DEMUXER)               += avs.o vocdec.o voc.o
43 43
 OBJS-$(CONFIG_BETHSOFTVID_DEMUXER)       += bethsoftvid.o
44 44
 OBJS-$(CONFIG_BFI_DEMUXER)               += bfi.o
45
+OBJS-$(CONFIG_BINK_DEMUXER)              += bink.o
45 46
 OBJS-$(CONFIG_C93_DEMUXER)               += c93.o vocdec.o voc.o
46 47
 OBJS-$(CONFIG_CAF_DEMUXER)               += cafdec.o caf.o mov.o riff.o isom.o
47 48
 OBJS-$(CONFIG_CAVSVIDEO_DEMUXER)         += raw.o
... ...
@@ -66,6 +66,7 @@ void av_register_all(void)
66 66
     REGISTER_DEMUXER  (AVS, avs);
67 67
     REGISTER_DEMUXER  (BETHSOFTVID, bethsoftvid);
68 68
     REGISTER_DEMUXER  (BFI, bfi);
69
+    REGISTER_DEMUXER  (BINK, bink);
69 70
     REGISTER_DEMUXER  (C93, c93);
70 71
     REGISTER_DEMUXER  (CAF, caf);
71 72
     REGISTER_DEMUXER  (CAVSVIDEO, cavsvideo);
72 73
new file mode 100644
... ...
@@ -0,0 +1,247 @@
0
+/*
1
+ * Bink demuxer
2
+ * Copyright (c) 2008-2010 Peter Ross (pross@xvid.org)
3
+ * Copyright (c) 2009 Daniel Verkamp (daniel@drv.nu)
4
+ *
5
+ * This file is part of FFmpeg.
6
+ *
7
+ * FFmpeg is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * FFmpeg is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with FFmpeg; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ */
21
+
22
+/**
23
+ * @file libavformat/bink.c
24
+ * Bink demuxer
25
+ *
26
+ * Technical details here:
27
+ *  http://wiki.multimedia.cx/index.php?title=Bink_Container
28
+ */
29
+
30
+#include "libavutil/intreadwrite.h"
31
+#include "avformat.h"
32
+
33
+enum BinkAudFlags {
34
+    BINK_AUD_16BITS = 0x4000, ///< prefer 16-bit output
35
+    BINK_AUD_STEREO = 0x2000,
36
+    BINK_AUD_USEDCT = 0x1000,
37
+};
38
+
39
+#define BINK_EXTRADATA_SIZE     1
40
+#define BINK_MAX_AUDIO_TRACKS   256
41
+#define BINK_MAX_WIDTH          7680
42
+#define BINK_MAX_HEIGHT         4800
43
+
44
+typedef struct {
45
+    uint32_t file_size;
46
+    uint32_t total_frames;
47
+
48
+    uint32_t num_audio_tracks;
49
+    int current_track;      ///< audio track to return in next packet
50
+    int64_t video_pts;
51
+    int64_t audio_pts[BINK_MAX_AUDIO_TRACKS];
52
+
53
+    uint32_t remain_packet_size;
54
+} BinkDemuxContext;
55
+
56
+static int probe(AVProbeData *p)
57
+{
58
+    const uint8_t *b = p->buf;
59
+
60
+    if ( b[0] == 'B' && b[1] == 'I' && b[2] == 'K' &&
61
+        (b[3] == 'b' || b[3] == 'f' || b[3] == 'g' || b[3] == 'h' || b[3] == 'i') &&
62
+        AV_RL32(b+8) > 0 &&  // num_frames
63
+        AV_RL32(b+20) > 0 && AV_RL32(b+20) <= BINK_MAX_WIDTH &&
64
+        AV_RL32(b+24) > 0 && AV_RL32(b+24) <= BINK_MAX_HEIGHT &&
65
+        AV_RL32(b+28) > 0 && AV_RL32(b+32) > 0)  // fps num,den
66
+        return AVPROBE_SCORE_MAX;
67
+    return 0;
68
+}
69
+
70
+static int read_header(AVFormatContext *s, AVFormatParameters *ap)
71
+{
72
+    BinkDemuxContext *bink = s->priv_data;
73
+    ByteIOContext *pb = s->pb;
74
+    uint32_t fps_num, fps_den;
75
+    AVStream *vst, *ast;
76
+    unsigned int i;
77
+    uint32_t pos, prev_pos;
78
+    uint16_t flags;
79
+    int keyframe;
80
+
81
+    vst = av_new_stream(s, 0);
82
+    if (!vst)
83
+        return AVERROR(ENOMEM);
84
+
85
+    vst->codec->codec_tag = get_le32(pb);
86
+
87
+    bink->file_size = get_le32(pb) + 8;
88
+    bink->total_frames = get_le32(pb);
89
+
90
+    if (bink->total_frames > 1000000) {
91
+        av_log(s, AV_LOG_ERROR, "invalid header: more than 1000000 frames\n");
92
+        return AVERROR(EIO);
93
+    }
94
+
95
+    if (get_le32(pb) > bink->file_size) {
96
+        av_log(s, AV_LOG_ERROR,
97
+               "invalid header: largest frame size greater than file size\n");
98
+        return AVERROR(EIO);
99
+    }
100
+
101
+    url_fskip(pb, 4);
102
+
103
+    vst->codec->width  = get_le32(pb);
104
+    vst->codec->height = get_le32(pb);
105
+
106
+    fps_num = get_le32(pb);
107
+    fps_den = get_le32(pb);
108
+    if (fps_num == 0 || fps_den == 0) {
109
+        av_log(s, AV_LOG_ERROR, "invalid header: invalid fps (%d/%d)\n", fps_num, fps_den);
110
+        return AVERROR(EIO);
111
+    }
112
+    av_set_pts_info(vst, 64, fps_den, fps_num);
113
+
114
+    url_fskip(pb, 4);
115
+
116
+    vst->codec->codec_type = CODEC_TYPE_VIDEO;
117
+    vst->codec->codec_id   = 0; /* FIXME: CODEC_ID_BINKVIDEO */
118
+    bink->num_audio_tracks = get_le32(pb);
119
+
120
+    if (bink->num_audio_tracks > BINK_MAX_AUDIO_TRACKS) {
121
+        av_log(s, AV_LOG_ERROR,
122
+               "invalid header: more than "AV_STRINGIFY(BINK_MAX_AUDIO_TRACKS)" audio tracks (%d)\n",
123
+               bink->num_audio_tracks);
124
+        return AVERROR(EIO);
125
+    }
126
+
127
+    if (bink->num_audio_tracks) {
128
+        url_fskip(pb, 4 * bink->num_audio_tracks);
129
+
130
+        for (i = 0; i < bink->num_audio_tracks; i++) {
131
+            ast = av_new_stream(s, 1);
132
+            if (!ast)
133
+                return AVERROR(ENOMEM);
134
+            ast->codec->codec_type  = CODEC_TYPE_AUDIO;
135
+            ast->codec->codec_tag   = 0;
136
+            ast->codec->sample_rate = get_le16(pb);
137
+            av_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
138
+            flags = get_le16(pb);
139
+            ast->codec->codec_id = flags & BINK_AUD_USEDCT ?
140
+                                   CODEC_ID_BINKAUDIO_DCT : CODEC_ID_BINKAUDIO_RDFT;
141
+            ast->codec->channels = flags & BINK_AUD_STEREO ? 2 : 1;
142
+        }
143
+
144
+        url_fskip(pb, 4 * bink->num_audio_tracks);
145
+    }
146
+
147
+    /* frame index table */
148
+    pos = get_le32(pb) & ~1;
149
+    for (i = 0; i < bink->total_frames; i++) {
150
+        prev_pos = pos;
151
+        if (i == bink->total_frames - 1) {
152
+            pos = bink->file_size;
153
+            keyframe = 0;
154
+        } else {
155
+            pos = get_le32(pb);
156
+            keyframe = pos & 1;
157
+            pos &= ~1;
158
+        }
159
+        if (pos <= prev_pos) {
160
+            av_log(s, AV_LOG_ERROR, "invalid frame index table\n");
161
+            return AVERROR(EIO);
162
+        }
163
+        av_add_index_entry(vst, pos, i, pos - prev_pos, 0,
164
+                           keyframe ? AVINDEX_KEYFRAME : 0);
165
+    }
166
+
167
+    url_fskip(pb, 4);
168
+
169
+    bink->current_track = -1;
170
+    return 0;
171
+}
172
+
173
+static int read_packet(AVFormatContext *s, AVPacket *pkt)
174
+{
175
+    BinkDemuxContext *bink = s->priv_data;
176
+    ByteIOContext *pb = s->pb;
177
+    int ret;
178
+
179
+    if (bink->current_track < 0) {
180
+        int index_entry;
181
+        AVStream *st = s->streams[0]; // stream 0 is video stream with index
182
+
183
+        if (bink->video_pts >= bink->total_frames)
184
+            return AVERROR(EIO);
185
+
186
+        index_entry = av_index_search_timestamp(st, bink->video_pts,
187
+                                                AVSEEK_FLAG_ANY);
188
+        if (index_entry < 0) {
189
+            av_log(s, AV_LOG_ERROR,
190
+                   "could not find index entry for frame %"PRId64"\n",
191
+                   bink->video_pts);
192
+            return AVERROR(EIO);
193
+        }
194
+
195
+        bink->remain_packet_size = st->index_entries[index_entry].size;
196
+        bink->current_track = 0;
197
+    }
198
+
199
+    if (bink->current_track < bink->num_audio_tracks) {
200
+        uint32_t audio_size = get_le32(pb);
201
+        if (audio_size > bink->remain_packet_size - 4) {
202
+            av_log(s, AV_LOG_ERROR,
203
+                   "frame %"PRId64": audio size in header (%u) > size of packet left (%u)\n",
204
+                   bink->video_pts, audio_size, bink->remain_packet_size);
205
+            return AVERROR(EIO);
206
+        }
207
+        bink->remain_packet_size -= 4 + audio_size;
208
+        bink->current_track++;
209
+        if (audio_size > 0) {
210
+            /* Each audio packet reports the number of decompressed samples
211
+               (in bytes). We use this value to calcuate the audio PTS */
212
+            int reported_size = get_le32(pb) / (2 * s->streams[bink->current_track]->codec->channels);
213
+            url_fseek(pb, -4, SEEK_CUR);
214
+
215
+            /* get one audio packet per track */
216
+            if ((ret = av_get_packet(pb, pkt, audio_size))
217
+                                           != audio_size)
218
+                return ret;
219
+            pkt->stream_index = bink->current_track;
220
+            pkt->pts = bink->audio_pts[bink->current_track - 1] += reported_size;
221
+            return 0;
222
+        }
223
+    }
224
+
225
+    /* get video packet */
226
+    if ((ret = av_get_packet(pb, pkt, bink->remain_packet_size))
227
+                                   != bink->remain_packet_size)
228
+        return ret;
229
+    pkt->stream_index = 0;
230
+    pkt->pts = bink->video_pts++;
231
+    pkt->flags |= PKT_FLAG_KEY;
232
+
233
+    /* -1 instructs the next call to read_packet() to read the next frame */
234
+    bink->current_track = -1;
235
+
236
+    return 0;
237
+}
238
+
239
+AVInputFormat bink_demuxer = {
240
+    "bink",
241
+    NULL_IF_CONFIG_SMALL("Bink"),
242
+    sizeof(BinkDemuxContext),
243
+    probe,
244
+    read_header,
245
+    read_packet,
246
+};