1/* 2 * Interplay MVE File Demuxer 3 * Copyright (c) 2003 The ffmpeg Project 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/ipmovie.c 24 * Interplay MVE file demuxer 25 * by Mike Melanson (melanson@pcisys.net) 26 * For more information regarding the Interplay MVE file format, visit: 27 * http://www.pcisys.net/~melanson/codecs/ 28 * The aforementioned site also contains a command line utility for parsing 29 * IP MVE files so that you can get a good idea of the typical structure of 30 * such files. This demuxer is not the best example to use if you are trying 31 * to write your own as it uses a rather roundabout approach for splitting 32 * up and sending out the chunks. 33 */ 34 35#include "libavutil/intreadwrite.h" 36#include "avformat.h" 37 38/* debugging support: #define DEBUG_IPMOVIE as non-zero to see extremely 39 * verbose information about the demux process */ 40#define DEBUG_IPMOVIE 0 41 42#if DEBUG_IPMOVIE 43#undef printf 44#define debug_ipmovie printf 45#else 46static inline void debug_ipmovie(const char *format, ...) { } 47#endif 48 49#define IPMOVIE_SIGNATURE "Interplay MVE File\x1A\0" 50#define IPMOVIE_SIGNATURE_SIZE 20 51#define CHUNK_PREAMBLE_SIZE 4 52#define OPCODE_PREAMBLE_SIZE 4 53 54#define CHUNK_INIT_AUDIO 0x0000 55#define CHUNK_AUDIO_ONLY 0x0001 56#define CHUNK_INIT_VIDEO 0x0002 57#define CHUNK_VIDEO 0x0003 58#define CHUNK_SHUTDOWN 0x0004 59#define CHUNK_END 0x0005 60/* these last types are used internally */ 61#define CHUNK_DONE 0xFFFC 62#define CHUNK_NOMEM 0xFFFD 63#define CHUNK_EOF 0xFFFE 64#define CHUNK_BAD 0xFFFF 65 66#define OPCODE_END_OF_STREAM 0x00 67#define OPCODE_END_OF_CHUNK 0x01 68#define OPCODE_CREATE_TIMER 0x02 69#define OPCODE_INIT_AUDIO_BUFFERS 0x03 70#define OPCODE_START_STOP_AUDIO 0x04 71#define OPCODE_INIT_VIDEO_BUFFERS 0x05 72#define OPCODE_UNKNOWN_06 0x06 73#define OPCODE_SEND_BUFFER 0x07 74#define OPCODE_AUDIO_FRAME 0x08 75#define OPCODE_SILENCE_FRAME 0x09 76#define OPCODE_INIT_VIDEO_MODE 0x0A 77#define OPCODE_CREATE_GRADIENT 0x0B 78#define OPCODE_SET_PALETTE 0x0C 79#define OPCODE_SET_PALETTE_COMPRESSED 0x0D 80#define OPCODE_UNKNOWN_0E 0x0E 81#define OPCODE_SET_DECODING_MAP 0x0F 82#define OPCODE_UNKNOWN_10 0x10 83#define OPCODE_VIDEO_DATA 0x11 84#define OPCODE_UNKNOWN_12 0x12 85#define OPCODE_UNKNOWN_13 0x13 86#define OPCODE_UNKNOWN_14 0x14 87#define OPCODE_UNKNOWN_15 0x15 88 89#define PALETTE_COUNT 256 90 91typedef struct IPMVEContext { 92 93 unsigned char *buf; 94 int buf_size; 95 96 uint64_t frame_pts_inc; 97 98 unsigned int video_width; 99 unsigned int video_height; 100 int64_t video_pts; 101 102 unsigned int audio_bits; 103 unsigned int audio_channels; 104 unsigned int audio_sample_rate; 105 enum CodecID audio_type; 106 unsigned int audio_frame_count; 107 108 int video_stream_index; 109 int audio_stream_index; 110 111 int64_t audio_chunk_offset; 112 int audio_chunk_size; 113 int64_t video_chunk_offset; 114 int video_chunk_size; 115 int64_t decode_map_chunk_offset; 116 int decode_map_chunk_size; 117 118 int64_t next_chunk_offset; 119 120 AVPaletteControl palette_control; 121 122} IPMVEContext; 123 124static int load_ipmovie_packet(IPMVEContext *s, ByteIOContext *pb, 125 AVPacket *pkt) { 126 127 int chunk_type; 128 129 if (s->audio_chunk_offset) { 130 131 /* adjust for PCM audio by skipping chunk header */ 132 if (s->audio_type != CODEC_ID_INTERPLAY_DPCM) { 133 s->audio_chunk_offset += 6; 134 s->audio_chunk_size -= 6; 135 } 136 137 url_fseek(pb, s->audio_chunk_offset, SEEK_SET); 138 s->audio_chunk_offset = 0; 139 140 if (s->audio_chunk_size != av_get_packet(pb, pkt, s->audio_chunk_size)) 141 return CHUNK_EOF; 142 143 pkt->stream_index = s->audio_stream_index; 144 pkt->pts = s->audio_frame_count; 145 146 /* audio frame maintenance */ 147 if (s->audio_type != CODEC_ID_INTERPLAY_DPCM) 148 s->audio_frame_count += 149 (s->audio_chunk_size / s->audio_channels / (s->audio_bits / 8)); 150 else 151 s->audio_frame_count += 152 (s->audio_chunk_size - 6) / s->audio_channels; 153 154 debug_ipmovie("sending audio frame with pts %"PRId64" (%d audio frames)\n", 155 pkt->pts, s->audio_frame_count); 156 157 chunk_type = CHUNK_VIDEO; 158 159 } else if (s->decode_map_chunk_offset) { 160 161 /* send both the decode map and the video data together */ 162 163 if (av_new_packet(pkt, s->decode_map_chunk_size + s->video_chunk_size)) 164 return CHUNK_NOMEM; 165 166 pkt->pos= s->decode_map_chunk_offset; 167 url_fseek(pb, s->decode_map_chunk_offset, SEEK_SET); 168 s->decode_map_chunk_offset = 0; 169 170 if (get_buffer(pb, pkt->data, s->decode_map_chunk_size) != 171 s->decode_map_chunk_size) { 172 av_free_packet(pkt); 173 return CHUNK_EOF; 174 } 175 176 url_fseek(pb, s->video_chunk_offset, SEEK_SET); 177 s->video_chunk_offset = 0; 178 179 if (get_buffer(pb, pkt->data + s->decode_map_chunk_size, 180 s->video_chunk_size) != s->video_chunk_size) { 181 av_free_packet(pkt); 182 return CHUNK_EOF; 183 } 184 185 pkt->stream_index = s->video_stream_index; 186 pkt->pts = s->video_pts; 187 188 debug_ipmovie("sending video frame with pts %"PRId64"\n", 189 pkt->pts); 190 191 s->video_pts += s->frame_pts_inc; 192 193 chunk_type = CHUNK_VIDEO; 194 195 } else { 196 197 url_fseek(pb, s->next_chunk_offset, SEEK_SET); 198 chunk_type = CHUNK_DONE; 199 200 } 201 202 return chunk_type; 203} 204 205/* This function loads and processes a single chunk in an IP movie file. 206 * It returns the type of chunk that was processed. */ 207static int process_ipmovie_chunk(IPMVEContext *s, ByteIOContext *pb, 208 AVPacket *pkt) 209{ 210 unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE]; 211 int chunk_type; 212 int chunk_size; 213 unsigned char opcode_preamble[OPCODE_PREAMBLE_SIZE]; 214 unsigned char opcode_type; 215 unsigned char opcode_version; 216 int opcode_size; 217 unsigned char scratch[1024]; 218 int i, j; 219 int first_color, last_color; 220 int audio_flags; 221 unsigned char r, g, b; 222 223 /* see if there are any pending packets */ 224 chunk_type = load_ipmovie_packet(s, pb, pkt); 225 if (chunk_type != CHUNK_DONE) 226 return chunk_type; 227 228 /* read the next chunk, wherever the file happens to be pointing */ 229 if (url_feof(pb)) 230 return CHUNK_EOF; 231 if (get_buffer(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) != 232 CHUNK_PREAMBLE_SIZE) 233 return CHUNK_BAD; 234 chunk_size = AV_RL16(&chunk_preamble[0]); 235 chunk_type = AV_RL16(&chunk_preamble[2]); 236 237 debug_ipmovie("chunk type 0x%04X, 0x%04X bytes: ", chunk_type, chunk_size); 238 239 switch (chunk_type) { 240 241 case CHUNK_INIT_AUDIO: 242 debug_ipmovie("initialize audio\n"); 243 break; 244 245 case CHUNK_AUDIO_ONLY: 246 debug_ipmovie("audio only\n"); 247 break; 248 249 case CHUNK_INIT_VIDEO: 250 debug_ipmovie("initialize video\n"); 251 break; 252 253 case CHUNK_VIDEO: 254 debug_ipmovie("video (and audio)\n"); 255 break; 256 257 case CHUNK_SHUTDOWN: 258 debug_ipmovie("shutdown\n"); 259 break; 260 261 case CHUNK_END: 262 debug_ipmovie("end\n"); 263 break; 264 265 default: 266 debug_ipmovie("invalid chunk\n"); 267 chunk_type = CHUNK_BAD; 268 break; 269 270 } 271 272 while ((chunk_size > 0) && (chunk_type != CHUNK_BAD)) { 273 274 /* read the next chunk, wherever the file happens to be pointing */ 275 if (url_feof(pb)) { 276 chunk_type = CHUNK_EOF; 277 break; 278 } 279 if (get_buffer(pb, opcode_preamble, CHUNK_PREAMBLE_SIZE) != 280 CHUNK_PREAMBLE_SIZE) { 281 chunk_type = CHUNK_BAD; 282 break; 283 } 284 285 opcode_size = AV_RL16(&opcode_preamble[0]); 286 opcode_type = opcode_preamble[2]; 287 opcode_version = opcode_preamble[3]; 288 289 chunk_size -= OPCODE_PREAMBLE_SIZE; 290 chunk_size -= opcode_size; 291 if (chunk_size < 0) { 292 debug_ipmovie("chunk_size countdown just went negative\n"); 293 chunk_type = CHUNK_BAD; 294 break; 295 } 296 297 debug_ipmovie(" opcode type %02X, version %d, 0x%04X bytes: ", 298 opcode_type, opcode_version, opcode_size); 299 switch (opcode_type) { 300 301 case OPCODE_END_OF_STREAM: 302 debug_ipmovie("end of stream\n"); 303 url_fseek(pb, opcode_size, SEEK_CUR); 304 break; 305 306 case OPCODE_END_OF_CHUNK: 307 debug_ipmovie("end of chunk\n"); 308 url_fseek(pb, opcode_size, SEEK_CUR); 309 break; 310 311 case OPCODE_CREATE_TIMER: 312 debug_ipmovie("create timer\n"); 313 if ((opcode_version > 0) || (opcode_size > 6)) { 314 debug_ipmovie("bad create_timer opcode\n"); 315 chunk_type = CHUNK_BAD; 316 break; 317 } 318 if (get_buffer(pb, scratch, opcode_size) != 319 opcode_size) { 320 chunk_type = CHUNK_BAD; 321 break; 322 } 323 s->frame_pts_inc = ((uint64_t)AV_RL32(&scratch[0])) * AV_RL16(&scratch[4]); 324 debug_ipmovie(" %.2f frames/second (timer div = %d, subdiv = %d)\n", 325 1000000.0/s->frame_pts_inc, AV_RL32(&scratch[0]), AV_RL16(&scratch[4])); 326 break; 327 328 case OPCODE_INIT_AUDIO_BUFFERS: 329 debug_ipmovie("initialize audio buffers\n"); 330 if ((opcode_version > 1) || (opcode_size > 10)) { 331 debug_ipmovie("bad init_audio_buffers opcode\n"); 332 chunk_type = CHUNK_BAD; 333 break; 334 } 335 if (get_buffer(pb, scratch, opcode_size) != 336 opcode_size) { 337 chunk_type = CHUNK_BAD; 338 break; 339 } 340 s->audio_sample_rate = AV_RL16(&scratch[4]); 341 audio_flags = AV_RL16(&scratch[2]); 342 /* bit 0 of the flags: 0 = mono, 1 = stereo */ 343 s->audio_channels = (audio_flags & 1) + 1; 344 /* bit 1 of the flags: 0 = 8 bit, 1 = 16 bit */ 345 s->audio_bits = (((audio_flags >> 1) & 1) + 1) * 8; 346 /* bit 2 indicates compressed audio in version 1 opcode */ 347 if ((opcode_version == 1) && (audio_flags & 0x4)) 348 s->audio_type = CODEC_ID_INTERPLAY_DPCM; 349 else if (s->audio_bits == 16) 350 s->audio_type = CODEC_ID_PCM_S16LE; 351 else 352 s->audio_type = CODEC_ID_PCM_U8; 353 debug_ipmovie("audio: %d bits, %d Hz, %s, %s format\n", 354 s->audio_bits, 355 s->audio_sample_rate, 356 (s->audio_channels == 2) ? "stereo" : "mono", 357 (s->audio_type == CODEC_ID_INTERPLAY_DPCM) ? 358 "Interplay audio" : "PCM"); 359 break; 360 361 case OPCODE_START_STOP_AUDIO: 362 debug_ipmovie("start/stop audio\n"); 363 url_fseek(pb, opcode_size, SEEK_CUR); 364 break; 365 366 case OPCODE_INIT_VIDEO_BUFFERS: 367 debug_ipmovie("initialize video buffers\n"); 368 if ((opcode_version > 2) || (opcode_size > 8)) { 369 debug_ipmovie("bad init_video_buffers opcode\n"); 370 chunk_type = CHUNK_BAD; 371 break; 372 } 373 if (get_buffer(pb, scratch, opcode_size) != 374 opcode_size) { 375 chunk_type = CHUNK_BAD; 376 break; 377 } 378 s->video_width = AV_RL16(&scratch[0]) * 8; 379 s->video_height = AV_RL16(&scratch[2]) * 8; 380 debug_ipmovie("video resolution: %d x %d\n", 381 s->video_width, s->video_height); 382 break; 383 384 case OPCODE_UNKNOWN_06: 385 case OPCODE_UNKNOWN_0E: 386 case OPCODE_UNKNOWN_10: 387 case OPCODE_UNKNOWN_12: 388 case OPCODE_UNKNOWN_13: 389 case OPCODE_UNKNOWN_14: 390 case OPCODE_UNKNOWN_15: 391 debug_ipmovie("unknown (but documented) opcode %02X\n", opcode_type); 392 url_fseek(pb, opcode_size, SEEK_CUR); 393 break; 394 395 case OPCODE_SEND_BUFFER: 396 debug_ipmovie("send buffer\n"); 397 url_fseek(pb, opcode_size, SEEK_CUR); 398 break; 399 400 case OPCODE_AUDIO_FRAME: 401 debug_ipmovie("audio frame\n"); 402 403 /* log position and move on for now */ 404 s->audio_chunk_offset = url_ftell(pb); 405 s->audio_chunk_size = opcode_size; 406 url_fseek(pb, opcode_size, SEEK_CUR); 407 break; 408 409 case OPCODE_SILENCE_FRAME: 410 debug_ipmovie("silence frame\n"); 411 url_fseek(pb, opcode_size, SEEK_CUR); 412 break; 413 414 case OPCODE_INIT_VIDEO_MODE: 415 debug_ipmovie("initialize video mode\n"); 416 url_fseek(pb, opcode_size, SEEK_CUR); 417 break; 418 419 case OPCODE_CREATE_GRADIENT: 420 debug_ipmovie("create gradient\n"); 421 url_fseek(pb, opcode_size, SEEK_CUR); 422 break; 423 424 case OPCODE_SET_PALETTE: 425 debug_ipmovie("set palette\n"); 426 /* check for the logical maximum palette size 427 * (3 * 256 + 4 bytes) */ 428 if (opcode_size > 0x304) { 429 debug_ipmovie("demux_ipmovie: set_palette opcode too large\n"); 430 chunk_type = CHUNK_BAD; 431 break; 432 } 433 if (get_buffer(pb, scratch, opcode_size) != opcode_size) { 434 chunk_type = CHUNK_BAD; 435 break; 436 } 437 438 /* load the palette into internal data structure */ 439 first_color = AV_RL16(&scratch[0]); 440 last_color = first_color + AV_RL16(&scratch[2]) - 1; 441 /* sanity check (since they are 16 bit values) */ 442 if ((first_color > 0xFF) || (last_color > 0xFF)) { 443 debug_ipmovie("demux_ipmovie: set_palette indexes out of range (%d -> %d)\n", 444 first_color, last_color); 445 chunk_type = CHUNK_BAD; 446 break; 447 } 448 j = 4; /* offset of first palette data */ 449 for (i = first_color; i <= last_color; i++) { 450 /* the palette is stored as a 6-bit VGA palette, thus each 451 * component is shifted up to a 8-bit range */ 452 r = scratch[j++] * 4; 453 g = scratch[j++] * 4; 454 b = scratch[j++] * 4; 455 s->palette_control.palette[i] = (r << 16) | (g << 8) | (b); 456 } 457 /* indicate a palette change */ 458 s->palette_control.palette_changed = 1; 459 break; 460 461 case OPCODE_SET_PALETTE_COMPRESSED: 462 debug_ipmovie("set palette compressed\n"); 463 url_fseek(pb, opcode_size, SEEK_CUR); 464 break; 465 466 case OPCODE_SET_DECODING_MAP: 467 debug_ipmovie("set decoding map\n"); 468 469 /* log position and move on for now */ 470 s->decode_map_chunk_offset = url_ftell(pb); 471 s->decode_map_chunk_size = opcode_size; 472 url_fseek(pb, opcode_size, SEEK_CUR); 473 break; 474 475 case OPCODE_VIDEO_DATA: 476 debug_ipmovie("set video data\n"); 477 478 /* log position and move on for now */ 479 s->video_chunk_offset = url_ftell(pb); 480 s->video_chunk_size = opcode_size; 481 url_fseek(pb, opcode_size, SEEK_CUR); 482 break; 483 484 default: 485 debug_ipmovie("*** unknown opcode type\n"); 486 chunk_type = CHUNK_BAD; 487 break; 488 489 } 490 } 491 492 /* make a note of where the stream is sitting */ 493 s->next_chunk_offset = url_ftell(pb); 494 495 /* dispatch the first of any pending packets */ 496 if ((chunk_type == CHUNK_VIDEO) || (chunk_type == CHUNK_AUDIO_ONLY)) 497 chunk_type = load_ipmovie_packet(s, pb, pkt); 498 499 return chunk_type; 500} 501 502static int ipmovie_probe(AVProbeData *p) 503{ 504 if (strncmp(p->buf, IPMOVIE_SIGNATURE, IPMOVIE_SIGNATURE_SIZE) != 0) 505 return 0; 506 507 return AVPROBE_SCORE_MAX; 508} 509 510static int ipmovie_read_header(AVFormatContext *s, 511 AVFormatParameters *ap) 512{ 513 IPMVEContext *ipmovie = s->priv_data; 514 ByteIOContext *pb = s->pb; 515 AVPacket pkt; 516 AVStream *st; 517 unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE]; 518 int chunk_type; 519 520 /* initialize private context members */ 521 ipmovie->video_pts = ipmovie->audio_frame_count = 0; 522 ipmovie->audio_chunk_offset = ipmovie->video_chunk_offset = 523 ipmovie->decode_map_chunk_offset = 0; 524 525 /* on the first read, this will position the stream at the first chunk */ 526 ipmovie->next_chunk_offset = IPMOVIE_SIGNATURE_SIZE + 6; 527 528 /* process the first chunk which should be CHUNK_INIT_VIDEO */ 529 if (process_ipmovie_chunk(ipmovie, pb, &pkt) != CHUNK_INIT_VIDEO) 530 return AVERROR_INVALIDDATA; 531 532 /* peek ahead to the next chunk-- if it is an init audio chunk, process 533 * it; if it is the first video chunk, this is a silent file */ 534 if (get_buffer(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) != 535 CHUNK_PREAMBLE_SIZE) 536 return AVERROR(EIO); 537 chunk_type = AV_RL16(&chunk_preamble[2]); 538 url_fseek(pb, -CHUNK_PREAMBLE_SIZE, SEEK_CUR); 539 540 if (chunk_type == CHUNK_VIDEO) 541 ipmovie->audio_type = CODEC_ID_NONE; /* no audio */ 542 else if (process_ipmovie_chunk(ipmovie, pb, &pkt) != CHUNK_INIT_AUDIO) 543 return AVERROR_INVALIDDATA; 544 545 /* initialize the stream decoders */ 546 st = av_new_stream(s, 0); 547 if (!st) 548 return AVERROR(ENOMEM); 549 av_set_pts_info(st, 63, 1, 1000000); 550 ipmovie->video_stream_index = st->index; 551 st->codec->codec_type = CODEC_TYPE_VIDEO; 552 st->codec->codec_id = CODEC_ID_INTERPLAY_VIDEO; 553 st->codec->codec_tag = 0; /* no fourcc */ 554 st->codec->width = ipmovie->video_width; 555 st->codec->height = ipmovie->video_height; 556 557 /* palette considerations */ 558 st->codec->palctrl = &ipmovie->palette_control; 559 560 if (ipmovie->audio_type) { 561 st = av_new_stream(s, 0); 562 if (!st) 563 return AVERROR(ENOMEM); 564 av_set_pts_info(st, 32, 1, ipmovie->audio_sample_rate); 565 ipmovie->audio_stream_index = st->index; 566 st->codec->codec_type = CODEC_TYPE_AUDIO; 567 st->codec->codec_id = ipmovie->audio_type; 568 st->codec->codec_tag = 0; /* no tag */ 569 st->codec->channels = ipmovie->audio_channels; 570 st->codec->sample_rate = ipmovie->audio_sample_rate; 571 st->codec->bits_per_coded_sample = ipmovie->audio_bits; 572 st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * 573 st->codec->bits_per_coded_sample; 574 if (st->codec->codec_id == CODEC_ID_INTERPLAY_DPCM) 575 st->codec->bit_rate /= 2; 576 st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample; 577 } 578 579 return 0; 580} 581 582static int ipmovie_read_packet(AVFormatContext *s, 583 AVPacket *pkt) 584{ 585 IPMVEContext *ipmovie = s->priv_data; 586 ByteIOContext *pb = s->pb; 587 int ret; 588 589 ret = process_ipmovie_chunk(ipmovie, pb, pkt); 590 if (ret == CHUNK_BAD) 591 ret = AVERROR_INVALIDDATA; 592 else if (ret == CHUNK_EOF) 593 ret = AVERROR(EIO); 594 else if (ret == CHUNK_NOMEM) 595 ret = AVERROR(ENOMEM); 596 else if (ret == CHUNK_VIDEO) 597 ret = 0; 598 else 599 ret = -1; 600 601 return ret; 602} 603 604AVInputFormat ipmovie_demuxer = { 605 "ipmovie", 606 NULL_IF_CONFIG_SMALL("Interplay MVE format"), 607 sizeof(IPMVEContext), 608 ipmovie_probe, 609 ipmovie_read_header, 610 ipmovie_read_packet, 611}; 612