ffmpeg / libavformat / bink.c @ 70b462cc
History | View | Annotate | Download (8.2 KB)
1 |
/*
|
---|---|
2 |
* Bink demuxer
|
3 |
* Copyright (c) 2008-2010 Peter Ross (pross@xvid.org)
|
4 |
* Copyright (c) 2009 Daniel Verkamp (daniel@drv.nu)
|
5 |
*
|
6 |
* This file is part of FFmpeg.
|
7 |
*
|
8 |
* FFmpeg is free software; you can redistribute it and/or
|
9 |
* 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 |
* FFmpeg is distributed in the hope that it will be useful,
|
14 |
* 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 |
* License along with FFmpeg; if not, write to the Free Software
|
20 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
21 |
*/
|
22 |
|
23 |
/**
|
24 |
* @file libavformat/bink.c
|
25 |
* 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 |
ByteIOContext *pb = s->pb; |
74 |
uint32_t fps_num, fps_den; |
75 |
AVStream *vst, *ast; |
76 |
unsigned int i; |
77 |
uint32_t pos, next_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 |
vst->duration = get_le32(pb); |
89 |
|
90 |
if (vst->duration > 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 |
vst->codec->codec_type = CODEC_TYPE_VIDEO; |
115 |
vst->codec->codec_id = CODEC_ID_BINKVIDEO; |
116 |
vst->codec->extradata = av_mallocz(4 + FF_INPUT_BUFFER_PADDING_SIZE);
|
117 |
vst->codec->extradata_size = 4;
|
118 |
get_buffer(pb, vst->codec->extradata, 4);
|
119 |
|
120 |
bink->num_audio_tracks = get_le32(pb); |
121 |
|
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 |
url_fskip(pb, 4 * bink->num_audio_tracks);
|
131 |
|
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 |
ast->codec->codec_type = CODEC_TYPE_AUDIO; |
137 |
ast->codec->codec_tag = 0;
|
138 |
ast->codec->sample_rate = get_le16(pb); |
139 |
av_set_pts_info(ast, 64, 1, ast->codec->sample_rate); |
140 |
flags = get_le16(pb); |
141 |
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 |
url_fskip(pb, 4 * bink->num_audio_tracks);
|
147 |
} |
148 |
|
149 |
/* frame index table */
|
150 |
next_pos = get_le32(pb); |
151 |
for (i = 0; i < vst->duration; i++) { |
152 |
pos = next_pos; |
153 |
if (i == vst->duration - 1) { |
154 |
next_pos = bink->file_size; |
155 |
keyframe = 0;
|
156 |
} else {
|
157 |
next_pos = get_le32(pb); |
158 |
keyframe = pos & 1;
|
159 |
} |
160 |
pos &= ~1;
|
161 |
next_pos &= ~1;
|
162 |
|
163 |
if (next_pos <= pos) {
|
164 |
av_log(s, AV_LOG_ERROR, "invalid frame index table\n");
|
165 |
return AVERROR(EIO);
|
166 |
} |
167 |
av_add_index_entry(vst, pos, i, next_pos - pos, 0,
|
168 |
keyframe ? AVINDEX_KEYFRAME : 0);
|
169 |
} |
170 |
|
171 |
url_fskip(pb, 4);
|
172 |
|
173 |
bink->current_track = -1;
|
174 |
return 0; |
175 |
} |
176 |
|
177 |
static int read_packet(AVFormatContext *s, AVPacket *pkt) |
178 |
{ |
179 |
BinkDemuxContext *bink = s->priv_data; |
180 |
ByteIOContext *pb = s->pb; |
181 |
int ret;
|
182 |
|
183 |
if (bink->current_track < 0) { |
184 |
int index_entry;
|
185 |
AVStream *st = s->streams[0]; // stream 0 is video stream with index |
186 |
|
187 |
if (bink->video_pts >= st->duration)
|
188 |
return AVERROR(EIO);
|
189 |
|
190 |
index_entry = av_index_search_timestamp(st, bink->video_pts, |
191 |
AVSEEK_FLAG_ANY); |
192 |
if (index_entry < 0) { |
193 |
av_log(s, AV_LOG_ERROR, |
194 |
"could not find index entry for frame %"PRId64"\n", |
195 |
bink->video_pts); |
196 |
return AVERROR(EIO);
|
197 |
} |
198 |
|
199 |
bink->remain_packet_size = st->index_entries[index_entry].size; |
200 |
bink->current_track = 0;
|
201 |
} |
202 |
|
203 |
while (bink->current_track < bink->num_audio_tracks) {
|
204 |
uint32_t audio_size = get_le32(pb); |
205 |
if (audio_size > bink->remain_packet_size - 4) { |
206 |
av_log(s, AV_LOG_ERROR, |
207 |
"frame %"PRId64": audio size in header (%u) > size of packet left (%u)\n", |
208 |
bink->video_pts, audio_size, bink->remain_packet_size); |
209 |
return AVERROR(EIO);
|
210 |
} |
211 |
bink->remain_packet_size -= 4 + audio_size;
|
212 |
bink->current_track++; |
213 |
if (audio_size >= 4) { |
214 |
/* get one audio packet per track */
|
215 |
if ((ret = av_get_packet(pb, pkt, audio_size)) < 0) |
216 |
return ret;
|
217 |
pkt->stream_index = bink->current_track; |
218 |
pkt->pts = bink->audio_pts[bink->current_track - 1];
|
219 |
|
220 |
/* Each audio packet reports the number of decompressed samples
|
221 |
(in bytes). We use this value to calcuate the audio PTS */
|
222 |
if (pkt->size >= 4) |
223 |
bink->audio_pts[bink->current_track -1] +=
|
224 |
AV_RL32(pkt->data) / (2 * s->streams[bink->current_track]->codec->channels);
|
225 |
return 0; |
226 |
} else {
|
227 |
url_fseek(pb, audio_size, SEEK_CUR); |
228 |
} |
229 |
} |
230 |
|
231 |
/* get video packet */
|
232 |
if ((ret = av_get_packet(pb, pkt, bink->remain_packet_size)) < 0) |
233 |
return ret;
|
234 |
pkt->stream_index = 0;
|
235 |
pkt->pts = bink->video_pts++; |
236 |
pkt->flags |= PKT_FLAG_KEY; |
237 |
|
238 |
/* -1 instructs the next call to read_packet() to read the next frame */
|
239 |
bink->current_track = -1;
|
240 |
|
241 |
return 0; |
242 |
} |
243 |
|
244 |
static int read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) |
245 |
{ |
246 |
BinkDemuxContext *bink = s->priv_data; |
247 |
AVStream *vst = s->streams[0];
|
248 |
|
249 |
if (url_is_streamed(s->pb))
|
250 |
return -1; |
251 |
|
252 |
/* seek to the first frame */
|
253 |
url_fseek(s->pb, vst->index_entries[0].pos, SEEK_SET);
|
254 |
bink->video_pts = 0;
|
255 |
memset(bink->audio_pts, 0, sizeof(bink->audio_pts)); |
256 |
bink->current_track = -1;
|
257 |
return 0; |
258 |
} |
259 |
|
260 |
AVInputFormat bink_demuxer = { |
261 |
"bink",
|
262 |
NULL_IF_CONFIG_SMALL("Bink"),
|
263 |
sizeof(BinkDemuxContext),
|
264 |
probe, |
265 |
read_header, |
266 |
read_packet, |
267 |
NULL,
|
268 |
read_seek, |
269 |
}; |