annotate ffmpeg/libavformat/smacker.c @ 13:844d341cf643 tip

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