ffmpeg / libavformat / bink.c @ 56a10009
History | View | Annotate | Download (8.25 KB)
1 | 2e375df5 | Peter Ross | /*
|
---|---|---|---|
2 | * Bink demuxer
|
||
3 | * Copyright (c) 2008-2010 Peter Ross (pross@xvid.org)
|
||
4 | * Copyright (c) 2009 Daniel Verkamp (daniel@drv.nu)
|
||
5 | *
|
||
6 | 2912e87a | Mans Rullgard | * This file is part of Libav.
|
7 | 2e375df5 | Peter Ross | *
|
8 | 2912e87a | Mans Rullgard | * Libav is free software; you can redistribute it and/or
|
9 | 2e375df5 | Peter Ross | * modify it under the terms of the GNU Lesser General Public
|
10 | * License as published by the Free Software Foundation; either
|
||
11 | * version 2.1 of the License, or (at your option) any later version.
|
||
12 | *
|
||
13 | 2912e87a | Mans Rullgard | * Libav is distributed in the hope that it will be useful,
|
14 | 2e375df5 | Peter Ross | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
16 | * Lesser General Public License for more details.
|
||
17 | *
|
||
18 | * You should have received a copy of the GNU Lesser General Public
|
||
19 | 2912e87a | Mans Rullgard | * License along with Libav; if not, write to the Free Software
|
20 | 2e375df5 | Peter Ross | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
21 | */
|
||
22 | |||
23 | /**
|
||
24 | ba87f080 | Diego Biurrun | * @file
|
25 | 2e375df5 | Peter Ross | * Bink demuxer
|
26 | *
|
||
27 | * Technical details here:
|
||
28 | * http://wiki.multimedia.cx/index.php?title=Bink_Container
|
||
29 | */
|
||
30 | |||
31 | #include "libavutil/intreadwrite.h" |
||
32 | #include "avformat.h" |
||
33 | |||
34 | enum BinkAudFlags {
|
||
35 | BINK_AUD_16BITS = 0x4000, ///< prefer 16-bit output |
||
36 | BINK_AUD_STEREO = 0x2000,
|
||
37 | BINK_AUD_USEDCT = 0x1000,
|
||
38 | }; |
||
39 | |||
40 | #define BINK_EXTRADATA_SIZE 1 |
||
41 | #define BINK_MAX_AUDIO_TRACKS 256 |
||
42 | #define BINK_MAX_WIDTH 7680 |
||
43 | #define BINK_MAX_HEIGHT 4800 |
||
44 | |||
45 | typedef struct { |
||
46 | uint32_t file_size; |
||
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 | ae628ec1 | Anton Khirnov | AVIOContext *pb = s->pb; |
74 | 2e375df5 | Peter Ross | uint32_t fps_num, fps_den; |
75 | AVStream *vst, *ast; |
||
76 | unsigned int i; |
||
77 | 7e276c85 | Peter Ross | uint32_t pos, next_pos; |
78 | 2e375df5 | Peter Ross | uint16_t flags; |
79 | int keyframe;
|
||
80 | |||
81 | vst = av_new_stream(s, 0);
|
||
82 | if (!vst)
|
||
83 | return AVERROR(ENOMEM);
|
||
84 | |||
85 | b7effd4e | Anton Khirnov | vst->codec->codec_tag = avio_rl32(pb); |
86 | 2e375df5 | Peter Ross | |
87 | b7effd4e | Anton Khirnov | bink->file_size = avio_rl32(pb) + 8;
|
88 | vst->duration = avio_rl32(pb); |
||
89 | 2e375df5 | Peter Ross | |
90 | 02cd6f54 | Peter Ross | if (vst->duration > 1000000) { |
91 | 2e375df5 | Peter Ross | av_log(s, AV_LOG_ERROR, "invalid header: more than 1000000 frames\n");
|
92 | return AVERROR(EIO);
|
||
93 | } |
||
94 | |||
95 | b7effd4e | Anton Khirnov | if (avio_rl32(pb) > bink->file_size) {
|
96 | 2e375df5 | Peter Ross | av_log(s, AV_LOG_ERROR, |
97 | "invalid header: largest frame size greater than file size\n");
|
||
98 | return AVERROR(EIO);
|
||
99 | } |
||
100 | |||
101 | 45a8a02a | Anton Khirnov | avio_skip(pb, 4);
|
102 | 2e375df5 | Peter Ross | |
103 | b7effd4e | Anton Khirnov | vst->codec->width = avio_rl32(pb); |
104 | vst->codec->height = avio_rl32(pb); |
||
105 | 2e375df5 | Peter Ross | |
106 | b7effd4e | Anton Khirnov | fps_num = avio_rl32(pb); |
107 | fps_den = avio_rl32(pb); |
||
108 | 2e375df5 | Peter Ross | 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 | 72415b2a | Stefano Sabatini | vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; |
115 | 971c55f1 | Kostya Shishkov | vst->codec->codec_id = CODEC_ID_BINKVIDEO; |
116 | a45972a8 | Kostya Shishkov | vst->codec->extradata = av_mallocz(4 + FF_INPUT_BUFFER_PADDING_SIZE);
|
117 | vst->codec->extradata_size = 4;
|
||
118 | b7effd4e | Anton Khirnov | avio_read(pb, vst->codec->extradata, 4);
|
119 | a45972a8 | Kostya Shishkov | |
120 | b7effd4e | Anton Khirnov | bink->num_audio_tracks = avio_rl32(pb); |
121 | 2e375df5 | Peter Ross | |
122 | if (bink->num_audio_tracks > BINK_MAX_AUDIO_TRACKS) {
|
||
123 | av_log(s, AV_LOG_ERROR, |
||
124 | "invalid header: more than "AV_STRINGIFY(BINK_MAX_AUDIO_TRACKS)" audio tracks (%d)\n", |
||
125 | bink->num_audio_tracks); |
||
126 | return AVERROR(EIO);
|
||
127 | } |
||
128 | |||
129 | if (bink->num_audio_tracks) {
|
||
130 | 45a8a02a | Anton Khirnov | avio_skip(pb, 4 * bink->num_audio_tracks);
|
131 | 2e375df5 | Peter Ross | |
132 | for (i = 0; i < bink->num_audio_tracks; i++) { |
||
133 | ast = av_new_stream(s, 1);
|
||
134 | if (!ast)
|
||
135 | return AVERROR(ENOMEM);
|
||
136 | 72415b2a | Stefano Sabatini | ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; |
137 | f0ca29eb | Peter Ross | ast->codec->codec_tag = vst->codec->codec_tag; |
138 | b7effd4e | Anton Khirnov | ast->codec->sample_rate = avio_rl16(pb); |
139 | 2e375df5 | Peter Ross | av_set_pts_info(ast, 64, 1, ast->codec->sample_rate); |
140 | b7effd4e | Anton Khirnov | flags = avio_rl16(pb); |
141 | 2e375df5 | Peter Ross | ast->codec->codec_id = flags & BINK_AUD_USEDCT ? |
142 | CODEC_ID_BINKAUDIO_DCT : CODEC_ID_BINKAUDIO_RDFT; |
||
143 | ast->codec->channels = flags & BINK_AUD_STEREO ? 2 : 1; |
||
144 | } |
||
145 | |||
146 | 588a3ffd | Peter Ross | for (i = 0; i < bink->num_audio_tracks; i++) |
147 | s->streams[i + 1]->id = avio_rl32(pb);
|
||
148 | 2e375df5 | Peter Ross | } |
149 | |||
150 | /* frame index table */
|
||
151 | b7effd4e | Anton Khirnov | next_pos = avio_rl32(pb); |
152 | 02cd6f54 | Peter Ross | for (i = 0; i < vst->duration; i++) { |
153 | 7e276c85 | Peter Ross | pos = next_pos; |
154 | 02cd6f54 | Peter Ross | if (i == vst->duration - 1) { |
155 | 7e276c85 | Peter Ross | next_pos = bink->file_size; |
156 | 2e375df5 | Peter Ross | keyframe = 0;
|
157 | } else {
|
||
158 | b7effd4e | Anton Khirnov | next_pos = avio_rl32(pb); |
159 | 2e375df5 | Peter Ross | keyframe = pos & 1;
|
160 | } |
||
161 | 7e276c85 | Peter Ross | pos &= ~1;
|
162 | next_pos &= ~1;
|
||
163 | |||
164 | if (next_pos <= pos) {
|
||
165 | 2e375df5 | Peter Ross | av_log(s, AV_LOG_ERROR, "invalid frame index table\n");
|
166 | return AVERROR(EIO);
|
||
167 | } |
||
168 | 7e276c85 | Peter Ross | av_add_index_entry(vst, pos, i, next_pos - pos, 0,
|
169 | 2e375df5 | Peter Ross | keyframe ? AVINDEX_KEYFRAME : 0);
|
170 | } |
||
171 | |||
172 | 45a8a02a | Anton Khirnov | avio_skip(pb, 4);
|
173 | 2e375df5 | Peter Ross | |
174 | bink->current_track = -1;
|
||
175 | return 0; |
||
176 | } |
||
177 | |||
178 | static int read_packet(AVFormatContext *s, AVPacket *pkt) |
||
179 | { |
||
180 | BinkDemuxContext *bink = s->priv_data; |
||
181 | ae628ec1 | Anton Khirnov | AVIOContext *pb = s->pb; |
182 | 2e375df5 | Peter Ross | int ret;
|
183 | |||
184 | if (bink->current_track < 0) { |
||
185 | int index_entry;
|
||
186 | AVStream *st = s->streams[0]; // stream 0 is video stream with index |
||
187 | |||
188 | 02cd6f54 | Peter Ross | if (bink->video_pts >= st->duration)
|
189 | 2e375df5 | Peter Ross | return AVERROR(EIO);
|
190 | |||
191 | index_entry = av_index_search_timestamp(st, bink->video_pts, |
||
192 | AVSEEK_FLAG_ANY); |
||
193 | if (index_entry < 0) { |
||
194 | av_log(s, AV_LOG_ERROR, |
||
195 | "could not find index entry for frame %"PRId64"\n", |
||
196 | bink->video_pts); |
||
197 | return AVERROR(EIO);
|
||
198 | } |
||
199 | |||
200 | bink->remain_packet_size = st->index_entries[index_entry].size; |
||
201 | bink->current_track = 0;
|
||
202 | } |
||
203 | |||
204 | 8cdfa474 | Kostya Shishkov | while (bink->current_track < bink->num_audio_tracks) {
|
205 | b7effd4e | Anton Khirnov | uint32_t audio_size = avio_rl32(pb); |
206 | 2e375df5 | Peter Ross | if (audio_size > bink->remain_packet_size - 4) { |
207 | av_log(s, AV_LOG_ERROR, |
||
208 | "frame %"PRId64": audio size in header (%u) > size of packet left (%u)\n", |
||
209 | bink->video_pts, audio_size, bink->remain_packet_size); |
||
210 | return AVERROR(EIO);
|
||
211 | } |
||
212 | bink->remain_packet_size -= 4 + audio_size;
|
||
213 | bink->current_track++; |
||
214 | 4ffa6e78 | Peter Ross | if (audio_size >= 4) { |
215 | 2e375df5 | Peter Ross | /* get one audio packet per track */
|
216 | 70b462cc | Peter Ross | if ((ret = av_get_packet(pb, pkt, audio_size)) < 0) |
217 | return ret;
|
||
218 | 2e375df5 | Peter Ross | pkt->stream_index = bink->current_track; |
219 | b62c65f2 | Peter Ross | pkt->pts = bink->audio_pts[bink->current_track - 1];
|
220 | a2799801 | Peter Ross | |
221 | /* Each audio packet reports the number of decompressed samples
|
||
222 | (in bytes). We use this value to calcuate the audio PTS */
|
||
223 | 70b462cc | Peter Ross | if (pkt->size >= 4) |
224 | bink->audio_pts[bink->current_track -1] +=
|
||
225 | AV_RL32(pkt->data) / (2 * s->streams[bink->current_track]->codec->channels);
|
||
226 | 2e375df5 | Peter Ross | return 0; |
227 | 4ffa6e78 | Peter Ross | } else {
|
228 | 45a8a02a | Anton Khirnov | avio_skip(pb, audio_size); |
229 | 2e375df5 | Peter Ross | } |
230 | } |
||
231 | |||
232 | /* get video packet */
|
||
233 | 70b462cc | Peter Ross | if ((ret = av_get_packet(pb, pkt, bink->remain_packet_size)) < 0) |
234 | return ret;
|
||
235 | 2e375df5 | Peter Ross | pkt->stream_index = 0;
|
236 | pkt->pts = bink->video_pts++; |
||
237 | cc947f04 | Jean-Daniel Dupas | pkt->flags |= AV_PKT_FLAG_KEY; |
238 | 2e375df5 | Peter Ross | |
239 | /* -1 instructs the next call to read_packet() to read the next frame */
|
||
240 | bink->current_track = -1;
|
||
241 | |||
242 | return 0; |
||
243 | } |
||
244 | |||
245 | dd80be5b | Peter Ross | static int read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) |
246 | { |
||
247 | BinkDemuxContext *bink = s->priv_data; |
||
248 | AVStream *vst = s->streams[0];
|
||
249 | |||
250 | 8978feda | Anton Khirnov | if (!s->pb->seekable)
|
251 | a2799801 | Peter Ross | return -1; |
252 | |||
253 | dd80be5b | Peter Ross | /* seek to the first frame */
|
254 | 6b4aa5da | Anton Khirnov | avio_seek(s->pb, vst->index_entries[0].pos, SEEK_SET);
|
255 | dd80be5b | Peter Ross | bink->video_pts = 0;
|
256 | memset(bink->audio_pts, 0, sizeof(bink->audio_pts)); |
||
257 | bink->current_track = -1;
|
||
258 | return 0; |
||
259 | } |
||
260 | |||
261 | c6610a21 | Diego Elio Pettenò | AVInputFormat ff_bink_demuxer = { |
262 | 2e375df5 | Peter Ross | "bink",
|
263 | NULL_IF_CONFIG_SMALL("Bink"),
|
||
264 | sizeof(BinkDemuxContext),
|
||
265 | probe, |
||
266 | read_header, |
||
267 | read_packet, |
||
268 | dd80be5b | Peter Ross | NULL,
|
269 | read_seek, |
||
270 | 2e375df5 | Peter Ross | }; |