blob: 8a21cc0767e400e4dd5f9cdf659f44310ee05d71
1 | /* |
2 | * Smacker demuxer |
3 | * Copyright (c) 2006 Konstantin Shishkov |
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 | * Based on http://wiki.multimedia.cx/index.php?title=Smacker |
24 | */ |
25 | |
26 | #include <inttypes.h> |
27 | |
28 | #include "libavutil/bswap.h" |
29 | #include "libavutil/channel_layout.h" |
30 | #include "libavutil/intreadwrite.h" |
31 | #include "avformat.h" |
32 | #include "internal.h" |
33 | |
34 | #define SMACKER_PAL 0x01 |
35 | #define SMACKER_FLAG_RING_FRAME 0x01 |
36 | |
37 | enum SAudFlags { |
38 | SMK_AUD_PACKED = 0x80, |
39 | SMK_AUD_16BITS = 0x20, |
40 | SMK_AUD_STEREO = 0x10, |
41 | SMK_AUD_BINKAUD = 0x08, |
42 | SMK_AUD_USEDCT = 0x04 |
43 | }; |
44 | |
45 | typedef struct SmackerContext { |
46 | /* Smacker file header */ |
47 | uint32_t magic; |
48 | uint32_t width, height; |
49 | uint32_t frames; |
50 | int pts_inc; |
51 | uint32_t flags; |
52 | uint32_t audio[7]; |
53 | uint32_t treesize; |
54 | uint32_t mmap_size, mclr_size, full_size, type_size; |
55 | uint8_t aflags[7]; |
56 | uint32_t rates[7]; |
57 | uint32_t pad; |
58 | /* frame info */ |
59 | uint32_t *frm_size; |
60 | uint8_t *frm_flags; |
61 | /* internal variables */ |
62 | int cur_frame; |
63 | int is_ver4; |
64 | int64_t cur_pts; |
65 | /* current frame for demuxing */ |
66 | uint8_t pal[768]; |
67 | int indexes[7]; |
68 | int videoindex; |
69 | uint8_t *bufs[7]; |
70 | int buf_sizes[7]; |
71 | int stream_id[7]; |
72 | int curstream; |
73 | int64_t nextpos; |
74 | int64_t aud_pts[7]; |
75 | } SmackerContext; |
76 | |
77 | typedef struct SmackerFrame { |
78 | int64_t pts; |
79 | int stream; |
80 | } SmackerFrame; |
81 | |
82 | /* palette used in Smacker */ |
83 | static const uint8_t smk_pal[64] = { |
84 | 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, |
85 | 0x20, 0x24, 0x28, 0x2C, 0x30, 0x34, 0x38, 0x3C, |
86 | 0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D, |
87 | 0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D, |
88 | 0x82, 0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9A, 0x9E, |
89 | 0xA2, 0xA6, 0xAA, 0xAE, 0xB2, 0xB6, 0xBA, 0xBE, |
90 | 0xC3, 0xC7, 0xCB, 0xCF, 0xD3, 0xD7, 0xDB, 0xDF, |
91 | 0xE3, 0xE7, 0xEB, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF |
92 | }; |
93 | |
94 | |
95 | static int smacker_probe(AVProbeData *p) |
96 | { |
97 | if ( AV_RL32(p->buf) != MKTAG('S', 'M', 'K', '2') |
98 | && AV_RL32(p->buf) != MKTAG('S', 'M', 'K', '4')) |
99 | return 0; |
100 | |
101 | if (AV_RL32(p->buf+4) > 32768U || AV_RL32(p->buf+8) > 32768U) |
102 | return AVPROBE_SCORE_MAX/4; |
103 | |
104 | return AVPROBE_SCORE_MAX; |
105 | } |
106 | |
107 | static int smacker_read_header(AVFormatContext *s) |
108 | { |
109 | AVIOContext *pb = s->pb; |
110 | SmackerContext *smk = s->priv_data; |
111 | AVStream *st, *ast[7]; |
112 | int i, ret; |
113 | int tbase; |
114 | |
115 | /* read and check header */ |
116 | smk->magic = avio_rl32(pb); |
117 | if (smk->magic != MKTAG('S', 'M', 'K', '2') && smk->magic != MKTAG('S', 'M', 'K', '4')) |
118 | return AVERROR_INVALIDDATA; |
119 | smk->width = avio_rl32(pb); |
120 | smk->height = avio_rl32(pb); |
121 | smk->frames = avio_rl32(pb); |
122 | smk->pts_inc = (int32_t)avio_rl32(pb); |
123 | if (smk->pts_inc > INT_MAX / 100) { |
124 | av_log(s, AV_LOG_ERROR, "pts_inc %d is too large\n", smk->pts_inc); |
125 | return AVERROR_INVALIDDATA; |
126 | } |
127 | |
128 | smk->flags = avio_rl32(pb); |
129 | if(smk->flags & SMACKER_FLAG_RING_FRAME) |
130 | smk->frames++; |
131 | for(i = 0; i < 7; i++) |
132 | smk->audio[i] = avio_rl32(pb); |
133 | smk->treesize = avio_rl32(pb); |
134 | |
135 | if(smk->treesize >= UINT_MAX/4){ // smk->treesize + 16 must not overflow (this check is probably redundant) |
136 | av_log(s, AV_LOG_ERROR, "treesize too large\n"); |
137 | return AVERROR_INVALIDDATA; |
138 | } |
139 | |
140 | //FIXME remove extradata "rebuilding" |
141 | smk->mmap_size = avio_rl32(pb); |
142 | smk->mclr_size = avio_rl32(pb); |
143 | smk->full_size = avio_rl32(pb); |
144 | smk->type_size = avio_rl32(pb); |
145 | for(i = 0; i < 7; i++) { |
146 | smk->rates[i] = avio_rl24(pb); |
147 | smk->aflags[i] = avio_r8(pb); |
148 | } |
149 | smk->pad = avio_rl32(pb); |
150 | /* setup data */ |
151 | if(smk->frames > 0xFFFFFF) { |
152 | av_log(s, AV_LOG_ERROR, "Too many frames: %"PRIu32"\n", smk->frames); |
153 | return AVERROR_INVALIDDATA; |
154 | } |
155 | smk->frm_size = av_malloc_array(smk->frames, sizeof(*smk->frm_size)); |
156 | smk->frm_flags = av_malloc(smk->frames); |
157 | if (!smk->frm_size || !smk->frm_flags) { |
158 | av_freep(&smk->frm_size); |
159 | av_freep(&smk->frm_flags); |
160 | return AVERROR(ENOMEM); |
161 | } |
162 | |
163 | smk->is_ver4 = (smk->magic != MKTAG('S', 'M', 'K', '2')); |
164 | |
165 | /* read frame info */ |
166 | for(i = 0; i < smk->frames; i++) { |
167 | smk->frm_size[i] = avio_rl32(pb); |
168 | } |
169 | for(i = 0; i < smk->frames; i++) { |
170 | smk->frm_flags[i] = avio_r8(pb); |
171 | } |
172 | |
173 | /* init video codec */ |
174 | st = avformat_new_stream(s, NULL); |
175 | if (!st) |
176 | return AVERROR(ENOMEM); |
177 | smk->videoindex = st->index; |
178 | st->codecpar->width = smk->width; |
179 | st->codecpar->height = smk->height; |
180 | st->codecpar->format = AV_PIX_FMT_PAL8; |
181 | st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; |
182 | st->codecpar->codec_id = AV_CODEC_ID_SMACKVIDEO; |
183 | st->codecpar->codec_tag = smk->magic; |
184 | /* Smacker uses 100000 as internal timebase */ |
185 | if(smk->pts_inc < 0) |
186 | smk->pts_inc = -smk->pts_inc; |
187 | else |
188 | smk->pts_inc *= 100; |
189 | tbase = 100000; |
190 | av_reduce(&tbase, &smk->pts_inc, tbase, smk->pts_inc, (1UL<<31)-1); |
191 | avpriv_set_pts_info(st, 33, smk->pts_inc, tbase); |
192 | st->duration = smk->frames; |
193 | /* handle possible audio streams */ |
194 | for(i = 0; i < 7; i++) { |
195 | smk->indexes[i] = -1; |
196 | if (smk->rates[i]) { |
197 | ast[i] = avformat_new_stream(s, NULL); |
198 | if (!ast[i]) |
199 | return AVERROR(ENOMEM); |
200 | smk->indexes[i] = ast[i]->index; |
201 | ast[i]->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; |
202 | if (smk->aflags[i] & SMK_AUD_BINKAUD) { |
203 | ast[i]->codecpar->codec_id = AV_CODEC_ID_BINKAUDIO_RDFT; |
204 | } else if (smk->aflags[i] & SMK_AUD_USEDCT) { |
205 | ast[i]->codecpar->codec_id = AV_CODEC_ID_BINKAUDIO_DCT; |
206 | } else if (smk->aflags[i] & SMK_AUD_PACKED){ |
207 | ast[i]->codecpar->codec_id = AV_CODEC_ID_SMACKAUDIO; |
208 | ast[i]->codecpar->codec_tag = MKTAG('S', 'M', 'K', 'A'); |
209 | } else { |
210 | ast[i]->codecpar->codec_id = AV_CODEC_ID_PCM_U8; |
211 | } |
212 | if (smk->aflags[i] & SMK_AUD_STEREO) { |
213 | ast[i]->codecpar->channels = 2; |
214 | ast[i]->codecpar->channel_layout = AV_CH_LAYOUT_STEREO; |
215 | } else { |
216 | ast[i]->codecpar->channels = 1; |
217 | ast[i]->codecpar->channel_layout = AV_CH_LAYOUT_MONO; |
218 | } |
219 | ast[i]->codecpar->sample_rate = smk->rates[i]; |
220 | ast[i]->codecpar->bits_per_coded_sample = (smk->aflags[i] & SMK_AUD_16BITS) ? 16 : 8; |
221 | if(ast[i]->codecpar->bits_per_coded_sample == 16 && ast[i]->codecpar->codec_id == AV_CODEC_ID_PCM_U8) |
222 | ast[i]->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; |
223 | avpriv_set_pts_info(ast[i], 64, 1, ast[i]->codecpar->sample_rate |
224 | * ast[i]->codecpar->channels * ast[i]->codecpar->bits_per_coded_sample / 8); |
225 | } |
226 | } |
227 | |
228 | |
229 | /* load trees to extradata, they will be unpacked by decoder */ |
230 | if(ff_alloc_extradata(st->codecpar, smk->treesize + 16)){ |
231 | av_log(s, AV_LOG_ERROR, |
232 | "Cannot allocate %"PRIu32" bytes of extradata\n", |
233 | smk->treesize + 16); |
234 | av_freep(&smk->frm_size); |
235 | av_freep(&smk->frm_flags); |
236 | return AVERROR(ENOMEM); |
237 | } |
238 | ret = avio_read(pb, st->codecpar->extradata + 16, st->codecpar->extradata_size - 16); |
239 | if(ret != st->codecpar->extradata_size - 16){ |
240 | av_freep(&smk->frm_size); |
241 | av_freep(&smk->frm_flags); |
242 | return AVERROR(EIO); |
243 | } |
244 | ((int32_t*)st->codecpar->extradata)[0] = av_le2ne32(smk->mmap_size); |
245 | ((int32_t*)st->codecpar->extradata)[1] = av_le2ne32(smk->mclr_size); |
246 | ((int32_t*)st->codecpar->extradata)[2] = av_le2ne32(smk->full_size); |
247 | ((int32_t*)st->codecpar->extradata)[3] = av_le2ne32(smk->type_size); |
248 | |
249 | smk->curstream = -1; |
250 | smk->nextpos = avio_tell(pb); |
251 | |
252 | return 0; |
253 | } |
254 | |
255 | |
256 | static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) |
257 | { |
258 | SmackerContext *smk = s->priv_data; |
259 | int flags; |
260 | int ret; |
261 | int i; |
262 | int frame_size = 0; |
263 | int palchange = 0; |
264 | |
265 | if (avio_feof(s->pb) || smk->cur_frame >= smk->frames) |
266 | return AVERROR_EOF; |
267 | |
268 | /* if we demuxed all streams, pass another frame */ |
269 | if(smk->curstream < 0) { |
270 | avio_seek(s->pb, smk->nextpos, 0); |
271 | frame_size = smk->frm_size[smk->cur_frame] & (~3); |
272 | flags = smk->frm_flags[smk->cur_frame]; |
273 | /* handle palette change event */ |
274 | if(flags & SMACKER_PAL){ |
275 | int size, sz, t, off, j, pos; |
276 | uint8_t *pal = smk->pal; |
277 | uint8_t oldpal[768]; |
278 | |
279 | memcpy(oldpal, pal, 768); |
280 | size = avio_r8(s->pb); |
281 | size = size * 4 - 1; |
282 | if(size + 1 > frame_size) |
283 | return AVERROR_INVALIDDATA; |
284 | frame_size -= size; |
285 | frame_size--; |
286 | sz = 0; |
287 | pos = avio_tell(s->pb) + size; |
288 | while(sz < 256){ |
289 | t = avio_r8(s->pb); |
290 | if(t & 0x80){ /* skip palette entries */ |
291 | sz += (t & 0x7F) + 1; |
292 | pal += ((t & 0x7F) + 1) * 3; |
293 | } else if(t & 0x40){ /* copy with offset */ |
294 | off = avio_r8(s->pb); |
295 | j = (t & 0x3F) + 1; |
296 | if (off + j > 0x100) { |
297 | av_log(s, AV_LOG_ERROR, |
298 | "Invalid palette update, offset=%d length=%d extends beyond palette size\n", |
299 | off, j); |
300 | return AVERROR_INVALIDDATA; |
301 | } |
302 | off *= 3; |
303 | while(j-- && sz < 256) { |
304 | *pal++ = oldpal[off + 0]; |
305 | *pal++ = oldpal[off + 1]; |
306 | *pal++ = oldpal[off + 2]; |
307 | sz++; |
308 | off += 3; |
309 | } |
310 | } else { /* new entries */ |
311 | *pal++ = smk_pal[t]; |
312 | *pal++ = smk_pal[avio_r8(s->pb) & 0x3F]; |
313 | *pal++ = smk_pal[avio_r8(s->pb) & 0x3F]; |
314 | sz++; |
315 | } |
316 | } |
317 | avio_seek(s->pb, pos, 0); |
318 | palchange |= 1; |
319 | } |
320 | flags >>= 1; |
321 | smk->curstream = -1; |
322 | /* if audio chunks are present, put them to stack and retrieve later */ |
323 | for(i = 0; i < 7; i++) { |
324 | if(flags & 1) { |
325 | uint32_t size; |
326 | int err; |
327 | |
328 | size = avio_rl32(s->pb) - 4; |
329 | if (!size || size + 4LL > frame_size) { |
330 | av_log(s, AV_LOG_ERROR, "Invalid audio part size\n"); |
331 | return AVERROR_INVALIDDATA; |
332 | } |
333 | frame_size -= size; |
334 | frame_size -= 4; |
335 | smk->curstream++; |
336 | if ((err = av_reallocp(&smk->bufs[smk->curstream], size)) < 0) { |
337 | smk->buf_sizes[smk->curstream] = 0; |
338 | return err; |
339 | } |
340 | smk->buf_sizes[smk->curstream] = size; |
341 | ret = avio_read(s->pb, smk->bufs[smk->curstream], size); |
342 | if(ret != size) |
343 | return AVERROR(EIO); |
344 | smk->stream_id[smk->curstream] = smk->indexes[i]; |
345 | } |
346 | flags >>= 1; |
347 | } |
348 | if (frame_size < 0 || frame_size >= INT_MAX/2) |
349 | return AVERROR_INVALIDDATA; |
350 | if (av_new_packet(pkt, frame_size + 769)) |
351 | return AVERROR(ENOMEM); |
352 | if(smk->frm_size[smk->cur_frame] & 1) |
353 | palchange |= 2; |
354 | pkt->data[0] = palchange; |
355 | memcpy(pkt->data + 1, smk->pal, 768); |
356 | ret = avio_read(s->pb, pkt->data + 769, frame_size); |
357 | if(ret != frame_size) |
358 | return AVERROR(EIO); |
359 | pkt->stream_index = smk->videoindex; |
360 | pkt->pts = smk->cur_frame; |
361 | pkt->size = ret + 769; |
362 | smk->cur_frame++; |
363 | smk->nextpos = avio_tell(s->pb); |
364 | } else { |
365 | if (smk->stream_id[smk->curstream] < 0 || !smk->bufs[smk->curstream]) |
366 | return AVERROR_INVALIDDATA; |
367 | if (av_new_packet(pkt, smk->buf_sizes[smk->curstream])) |
368 | return AVERROR(ENOMEM); |
369 | memcpy(pkt->data, smk->bufs[smk->curstream], smk->buf_sizes[smk->curstream]); |
370 | pkt->size = smk->buf_sizes[smk->curstream]; |
371 | pkt->stream_index = smk->stream_id[smk->curstream]; |
372 | pkt->pts = smk->aud_pts[smk->curstream]; |
373 | smk->aud_pts[smk->curstream] += AV_RL32(pkt->data); |
374 | smk->curstream--; |
375 | } |
376 | |
377 | return 0; |
378 | } |
379 | |
380 | static int smacker_read_close(AVFormatContext *s) |
381 | { |
382 | SmackerContext *smk = s->priv_data; |
383 | int i; |
384 | |
385 | for(i = 0; i < 7; i++) |
386 | av_freep(&smk->bufs[i]); |
387 | av_freep(&smk->frm_size); |
388 | av_freep(&smk->frm_flags); |
389 | |
390 | return 0; |
391 | } |
392 | |
393 | AVInputFormat ff_smacker_demuxer = { |
394 | .name = "smk", |
395 | .long_name = NULL_IF_CONFIG_SMALL("Smacker"), |
396 | .priv_data_size = sizeof(SmackerContext), |
397 | .read_probe = smacker_probe, |
398 | .read_header = smacker_read_header, |
399 | .read_packet = smacker_read_packet, |
400 | .read_close = smacker_read_close, |
401 | }; |
402 |