00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00035 #include "libavutil/intreadwrite.h"
00036 #include "avformat.h"
00037 #include "internal.h"
00038
00039 #define CHUNK_PREAMBLE_SIZE 4
00040 #define OPCODE_PREAMBLE_SIZE 4
00041
00042 #define CHUNK_INIT_AUDIO 0x0000
00043 #define CHUNK_AUDIO_ONLY 0x0001
00044 #define CHUNK_INIT_VIDEO 0x0002
00045 #define CHUNK_VIDEO 0x0003
00046 #define CHUNK_SHUTDOWN 0x0004
00047 #define CHUNK_END 0x0005
00048
00049 #define CHUNK_DONE 0xFFFC
00050 #define CHUNK_NOMEM 0xFFFD
00051 #define CHUNK_EOF 0xFFFE
00052 #define CHUNK_BAD 0xFFFF
00053
00054 #define OPCODE_END_OF_STREAM 0x00
00055 #define OPCODE_END_OF_CHUNK 0x01
00056 #define OPCODE_CREATE_TIMER 0x02
00057 #define OPCODE_INIT_AUDIO_BUFFERS 0x03
00058 #define OPCODE_START_STOP_AUDIO 0x04
00059 #define OPCODE_INIT_VIDEO_BUFFERS 0x05
00060 #define OPCODE_UNKNOWN_06 0x06
00061 #define OPCODE_SEND_BUFFER 0x07
00062 #define OPCODE_AUDIO_FRAME 0x08
00063 #define OPCODE_SILENCE_FRAME 0x09
00064 #define OPCODE_INIT_VIDEO_MODE 0x0A
00065 #define OPCODE_CREATE_GRADIENT 0x0B
00066 #define OPCODE_SET_PALETTE 0x0C
00067 #define OPCODE_SET_PALETTE_COMPRESSED 0x0D
00068 #define OPCODE_UNKNOWN_0E 0x0E
00069 #define OPCODE_SET_DECODING_MAP 0x0F
00070 #define OPCODE_UNKNOWN_10 0x10
00071 #define OPCODE_VIDEO_DATA 0x11
00072 #define OPCODE_UNKNOWN_12 0x12
00073 #define OPCODE_UNKNOWN_13 0x13
00074 #define OPCODE_UNKNOWN_14 0x14
00075 #define OPCODE_UNKNOWN_15 0x15
00076
00077 #define PALETTE_COUNT 256
00078
00079 typedef struct IPMVEContext {
00080
00081 unsigned char *buf;
00082 int buf_size;
00083
00084 uint64_t frame_pts_inc;
00085
00086 unsigned int video_bpp;
00087 unsigned int video_width;
00088 unsigned int video_height;
00089 int64_t video_pts;
00090 uint32_t palette[256];
00091 int has_palette;
00092 int changed;
00093
00094 unsigned int audio_bits;
00095 unsigned int audio_channels;
00096 unsigned int audio_sample_rate;
00097 enum CodecID audio_type;
00098 unsigned int audio_frame_count;
00099
00100 int video_stream_index;
00101 int audio_stream_index;
00102
00103 int64_t audio_chunk_offset;
00104 int audio_chunk_size;
00105 int64_t video_chunk_offset;
00106 int video_chunk_size;
00107 int64_t decode_map_chunk_offset;
00108 int decode_map_chunk_size;
00109
00110 int64_t next_chunk_offset;
00111
00112 } IPMVEContext;
00113
00114 static int load_ipmovie_packet(IPMVEContext *s, AVIOContext *pb,
00115 AVPacket *pkt) {
00116
00117 int chunk_type;
00118
00119 if (s->audio_chunk_offset && s->audio_channels && s->audio_bits) {
00120 if (s->audio_type == CODEC_ID_NONE) {
00121 av_log(NULL, AV_LOG_ERROR, "Can not read audio packet before"
00122 "audio codec is known\n");
00123 return CHUNK_BAD;
00124 }
00125
00126
00127 if (s->audio_type != CODEC_ID_INTERPLAY_DPCM) {
00128 s->audio_chunk_offset += 6;
00129 s->audio_chunk_size -= 6;
00130 }
00131
00132 avio_seek(pb, s->audio_chunk_offset, SEEK_SET);
00133 s->audio_chunk_offset = 0;
00134
00135 if (s->audio_chunk_size != av_get_packet(pb, pkt, s->audio_chunk_size))
00136 return CHUNK_EOF;
00137
00138 pkt->stream_index = s->audio_stream_index;
00139 pkt->pts = s->audio_frame_count;
00140
00141
00142 if (s->audio_type != CODEC_ID_INTERPLAY_DPCM)
00143 s->audio_frame_count +=
00144 (s->audio_chunk_size / s->audio_channels / (s->audio_bits / 8));
00145 else
00146 s->audio_frame_count +=
00147 (s->audio_chunk_size - 6 - s->audio_channels) / s->audio_channels;
00148
00149 av_dlog(NULL, "sending audio frame with pts %"PRId64" (%d audio frames)\n",
00150 pkt->pts, s->audio_frame_count);
00151
00152 chunk_type = CHUNK_VIDEO;
00153
00154 } else if (s->decode_map_chunk_offset) {
00155
00156
00157
00158 if (av_new_packet(pkt, s->decode_map_chunk_size + s->video_chunk_size))
00159 return CHUNK_NOMEM;
00160
00161 if (s->has_palette) {
00162 uint8_t *pal;
00163
00164 pal = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE,
00165 AVPALETTE_SIZE);
00166 if (pal) {
00167 memcpy(pal, s->palette, AVPALETTE_SIZE);
00168 s->has_palette = 0;
00169 }
00170 }
00171
00172 if (s->changed) {
00173 ff_add_param_change(pkt, 0, 0, 0, s->video_width, s->video_height);
00174 s->changed = 0;
00175 }
00176 pkt->pos= s->decode_map_chunk_offset;
00177 avio_seek(pb, s->decode_map_chunk_offset, SEEK_SET);
00178 s->decode_map_chunk_offset = 0;
00179
00180 if (avio_read(pb, pkt->data, s->decode_map_chunk_size) !=
00181 s->decode_map_chunk_size) {
00182 av_free_packet(pkt);
00183 return CHUNK_EOF;
00184 }
00185
00186 avio_seek(pb, s->video_chunk_offset, SEEK_SET);
00187 s->video_chunk_offset = 0;
00188
00189 if (avio_read(pb, pkt->data + s->decode_map_chunk_size,
00190 s->video_chunk_size) != s->video_chunk_size) {
00191 av_free_packet(pkt);
00192 return CHUNK_EOF;
00193 }
00194
00195 pkt->stream_index = s->video_stream_index;
00196 pkt->pts = s->video_pts;
00197
00198 av_dlog(NULL, "sending video frame with pts %"PRId64"\n", pkt->pts);
00199
00200 s->video_pts += s->frame_pts_inc;
00201
00202 chunk_type = CHUNK_VIDEO;
00203
00204 } else {
00205
00206 avio_seek(pb, s->next_chunk_offset, SEEK_SET);
00207 chunk_type = CHUNK_DONE;
00208
00209 }
00210
00211 return chunk_type;
00212 }
00213
00214
00215
00216 static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb,
00217 AVPacket *pkt)
00218 {
00219 unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE];
00220 int chunk_type;
00221 int chunk_size;
00222 unsigned char opcode_preamble[OPCODE_PREAMBLE_SIZE];
00223 unsigned char opcode_type;
00224 unsigned char opcode_version;
00225 int opcode_size;
00226 unsigned char scratch[1024];
00227 int i, j;
00228 int first_color, last_color;
00229 int audio_flags;
00230 unsigned char r, g, b;
00231 unsigned int width, height;
00232
00233
00234 chunk_type = load_ipmovie_packet(s, pb, pkt);
00235 if (chunk_type != CHUNK_DONE)
00236 return chunk_type;
00237
00238
00239 if (url_feof(pb))
00240 return CHUNK_EOF;
00241 if (avio_read(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) !=
00242 CHUNK_PREAMBLE_SIZE)
00243 return CHUNK_BAD;
00244 chunk_size = AV_RL16(&chunk_preamble[0]);
00245 chunk_type = AV_RL16(&chunk_preamble[2]);
00246
00247 av_dlog(NULL, "chunk type 0x%04X, 0x%04X bytes: ", chunk_type, chunk_size);
00248
00249 switch (chunk_type) {
00250
00251 case CHUNK_INIT_AUDIO:
00252 av_dlog(NULL, "initialize audio\n");
00253 break;
00254
00255 case CHUNK_AUDIO_ONLY:
00256 av_dlog(NULL, "audio only\n");
00257 break;
00258
00259 case CHUNK_INIT_VIDEO:
00260 av_dlog(NULL, "initialize video\n");
00261 break;
00262
00263 case CHUNK_VIDEO:
00264 av_dlog(NULL, "video (and audio)\n");
00265 break;
00266
00267 case CHUNK_SHUTDOWN:
00268 av_dlog(NULL, "shutdown\n");
00269 break;
00270
00271 case CHUNK_END:
00272 av_dlog(NULL, "end\n");
00273 break;
00274
00275 default:
00276 av_dlog(NULL, "invalid chunk\n");
00277 chunk_type = CHUNK_BAD;
00278 break;
00279
00280 }
00281
00282 while ((chunk_size > 0) && (chunk_type != CHUNK_BAD)) {
00283
00284
00285 if (url_feof(pb)) {
00286 chunk_type = CHUNK_EOF;
00287 break;
00288 }
00289 if (avio_read(pb, opcode_preamble, CHUNK_PREAMBLE_SIZE) !=
00290 CHUNK_PREAMBLE_SIZE) {
00291 chunk_type = CHUNK_BAD;
00292 break;
00293 }
00294
00295 opcode_size = AV_RL16(&opcode_preamble[0]);
00296 opcode_type = opcode_preamble[2];
00297 opcode_version = opcode_preamble[3];
00298
00299 chunk_size -= OPCODE_PREAMBLE_SIZE;
00300 chunk_size -= opcode_size;
00301 if (chunk_size < 0) {
00302 av_dlog(NULL, "chunk_size countdown just went negative\n");
00303 chunk_type = CHUNK_BAD;
00304 break;
00305 }
00306
00307 av_dlog(NULL, " opcode type %02X, version %d, 0x%04X bytes: ",
00308 opcode_type, opcode_version, opcode_size);
00309 switch (opcode_type) {
00310
00311 case OPCODE_END_OF_STREAM:
00312 av_dlog(NULL, "end of stream\n");
00313 avio_skip(pb, opcode_size);
00314 break;
00315
00316 case OPCODE_END_OF_CHUNK:
00317 av_dlog(NULL, "end of chunk\n");
00318 avio_skip(pb, opcode_size);
00319 break;
00320
00321 case OPCODE_CREATE_TIMER:
00322 av_dlog(NULL, "create timer\n");
00323 if ((opcode_version > 0) || (opcode_size > 6)) {
00324 av_dlog(NULL, "bad create_timer opcode\n");
00325 chunk_type = CHUNK_BAD;
00326 break;
00327 }
00328 if (avio_read(pb, scratch, opcode_size) !=
00329 opcode_size) {
00330 chunk_type = CHUNK_BAD;
00331 break;
00332 }
00333 s->frame_pts_inc = ((uint64_t)AV_RL32(&scratch[0])) * AV_RL16(&scratch[4]);
00334 av_dlog(NULL, " %.2f frames/second (timer div = %d, subdiv = %d)\n",
00335 1000000.0 / s->frame_pts_inc, AV_RL32(&scratch[0]),
00336 AV_RL16(&scratch[4]));
00337 break;
00338
00339 case OPCODE_INIT_AUDIO_BUFFERS:
00340 av_dlog(NULL, "initialize audio buffers\n");
00341 if ((opcode_version > 1) || (opcode_size > 10)) {
00342 av_dlog(NULL, "bad init_audio_buffers opcode\n");
00343 chunk_type = CHUNK_BAD;
00344 break;
00345 }
00346 if (avio_read(pb, scratch, opcode_size) !=
00347 opcode_size) {
00348 chunk_type = CHUNK_BAD;
00349 break;
00350 }
00351 s->audio_sample_rate = AV_RL16(&scratch[4]);
00352 audio_flags = AV_RL16(&scratch[2]);
00353
00354 s->audio_channels = (audio_flags & 1) + 1;
00355
00356 s->audio_bits = (((audio_flags >> 1) & 1) + 1) * 8;
00357
00358 if ((opcode_version == 1) && (audio_flags & 0x4))
00359 s->audio_type = CODEC_ID_INTERPLAY_DPCM;
00360 else if (s->audio_bits == 16)
00361 s->audio_type = CODEC_ID_PCM_S16LE;
00362 else
00363 s->audio_type = CODEC_ID_PCM_U8;
00364 av_dlog(NULL, "audio: %d bits, %d Hz, %s, %s format\n",
00365 s->audio_bits, s->audio_sample_rate,
00366 (s->audio_channels == 2) ? "stereo" : "mono",
00367 (s->audio_type == CODEC_ID_INTERPLAY_DPCM) ?
00368 "Interplay audio" : "PCM");
00369 break;
00370
00371 case OPCODE_START_STOP_AUDIO:
00372 av_dlog(NULL, "start/stop audio\n");
00373 avio_skip(pb, opcode_size);
00374 break;
00375
00376 case OPCODE_INIT_VIDEO_BUFFERS:
00377 av_dlog(NULL, "initialize video buffers\n");
00378 if ((opcode_version > 2) || (opcode_size > 8)) {
00379 av_dlog(NULL, "bad init_video_buffers opcode\n");
00380 chunk_type = CHUNK_BAD;
00381 break;
00382 }
00383 if (avio_read(pb, scratch, opcode_size) !=
00384 opcode_size) {
00385 chunk_type = CHUNK_BAD;
00386 break;
00387 }
00388 width = AV_RL16(&scratch[0]) * 8;
00389 height = AV_RL16(&scratch[2]) * 8;
00390 if (width != s->video_width) {
00391 s->video_width = width;
00392 s->changed++;
00393 }
00394 if (height != s->video_height) {
00395 s->video_height = height;
00396 s->changed++;
00397 }
00398 if (opcode_version < 2 || !AV_RL16(&scratch[6])) {
00399 s->video_bpp = 8;
00400 } else {
00401 s->video_bpp = 16;
00402 }
00403 av_dlog(NULL, "video resolution: %d x %d\n",
00404 s->video_width, s->video_height);
00405 break;
00406
00407 case OPCODE_UNKNOWN_06:
00408 case OPCODE_UNKNOWN_0E:
00409 case OPCODE_UNKNOWN_10:
00410 case OPCODE_UNKNOWN_12:
00411 case OPCODE_UNKNOWN_13:
00412 case OPCODE_UNKNOWN_14:
00413 case OPCODE_UNKNOWN_15:
00414 av_dlog(NULL, "unknown (but documented) opcode %02X\n", opcode_type);
00415 avio_skip(pb, opcode_size);
00416 break;
00417
00418 case OPCODE_SEND_BUFFER:
00419 av_dlog(NULL, "send buffer\n");
00420 avio_skip(pb, opcode_size);
00421 break;
00422
00423 case OPCODE_AUDIO_FRAME:
00424 av_dlog(NULL, "audio frame\n");
00425
00426
00427 s->audio_chunk_offset = avio_tell(pb);
00428 s->audio_chunk_size = opcode_size;
00429 avio_skip(pb, opcode_size);
00430 break;
00431
00432 case OPCODE_SILENCE_FRAME:
00433 av_dlog(NULL, "silence frame\n");
00434 avio_skip(pb, opcode_size);
00435 break;
00436
00437 case OPCODE_INIT_VIDEO_MODE:
00438 av_dlog(NULL, "initialize video mode\n");
00439 avio_skip(pb, opcode_size);
00440 break;
00441
00442 case OPCODE_CREATE_GRADIENT:
00443 av_dlog(NULL, "create gradient\n");
00444 avio_skip(pb, opcode_size);
00445 break;
00446
00447 case OPCODE_SET_PALETTE:
00448 av_dlog(NULL, "set palette\n");
00449
00450
00451 if (opcode_size > 0x304) {
00452 av_dlog(NULL, "demux_ipmovie: set_palette opcode too large\n");
00453 chunk_type = CHUNK_BAD;
00454 break;
00455 }
00456 if (avio_read(pb, scratch, opcode_size) != opcode_size) {
00457 chunk_type = CHUNK_BAD;
00458 break;
00459 }
00460
00461
00462 first_color = AV_RL16(&scratch[0]);
00463 last_color = first_color + AV_RL16(&scratch[2]) - 1;
00464
00465 if ((first_color > 0xFF) || (last_color > 0xFF)) {
00466 av_dlog(NULL, "demux_ipmovie: set_palette indexes out of range (%d -> %d)\n",
00467 first_color, last_color);
00468 chunk_type = CHUNK_BAD;
00469 break;
00470 }
00471 j = 4;
00472 for (i = first_color; i <= last_color; i++) {
00473
00474
00475 r = scratch[j++] * 4;
00476 g = scratch[j++] * 4;
00477 b = scratch[j++] * 4;
00478 s->palette[i] = (0xFFU << 24) | (r << 16) | (g << 8) | (b);
00479 s->palette[i] |= s->palette[i] >> 6 & 0x30303;
00480 }
00481 s->has_palette = 1;
00482 break;
00483
00484 case OPCODE_SET_PALETTE_COMPRESSED:
00485 av_dlog(NULL, "set palette compressed\n");
00486 avio_skip(pb, opcode_size);
00487 break;
00488
00489 case OPCODE_SET_DECODING_MAP:
00490 av_dlog(NULL, "set decoding map\n");
00491
00492
00493 s->decode_map_chunk_offset = avio_tell(pb);
00494 s->decode_map_chunk_size = opcode_size;
00495 avio_skip(pb, opcode_size);
00496 break;
00497
00498 case OPCODE_VIDEO_DATA:
00499 av_dlog(NULL, "set video data\n");
00500
00501
00502 s->video_chunk_offset = avio_tell(pb);
00503 s->video_chunk_size = opcode_size;
00504 avio_skip(pb, opcode_size);
00505 break;
00506
00507 default:
00508 av_dlog(NULL, "*** unknown opcode type\n");
00509 chunk_type = CHUNK_BAD;
00510 break;
00511
00512 }
00513 }
00514
00515
00516 s->next_chunk_offset = avio_tell(pb);
00517
00518
00519 if ((chunk_type == CHUNK_VIDEO) || (chunk_type == CHUNK_AUDIO_ONLY))
00520 chunk_type = load_ipmovie_packet(s, pb, pkt);
00521
00522 return chunk_type;
00523 }
00524
00525 static const char signature[] = "Interplay MVE File\x1A\0\x1A";
00526
00527 static int ipmovie_probe(AVProbeData *p)
00528 {
00529 uint8_t *b = p->buf;
00530 uint8_t *b_end = p->buf + p->buf_size - sizeof(signature);
00531 do {
00532 if (memcmp(b++, signature, sizeof(signature)) == 0)
00533 return AVPROBE_SCORE_MAX;
00534 } while (b < b_end);
00535
00536 return 0;
00537 }
00538
00539 static int ipmovie_read_header(AVFormatContext *s,
00540 AVFormatParameters *ap)
00541 {
00542 IPMVEContext *ipmovie = s->priv_data;
00543 AVIOContext *pb = s->pb;
00544 AVPacket pkt;
00545 AVStream *st;
00546 unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE];
00547 int chunk_type, i;
00548 uint8_t signature_buffer[sizeof(signature)];
00549
00550 avio_read(pb, signature_buffer, sizeof(signature_buffer));
00551 while (memcmp(signature_buffer, signature, sizeof(signature))) {
00552 memmove(signature_buffer, signature_buffer + 1, sizeof(signature_buffer) - 1);
00553 signature_buffer[sizeof(signature_buffer) - 1] = avio_r8(pb);
00554 if (url_feof(pb))
00555 return AVERROR_EOF;
00556 }
00557
00558 ipmovie->video_pts = ipmovie->audio_frame_count = 0;
00559 ipmovie->audio_chunk_offset = ipmovie->video_chunk_offset =
00560 ipmovie->decode_map_chunk_offset = 0;
00561
00562
00563 ipmovie->next_chunk_offset = avio_tell(pb) + 4;
00564
00565 for (i = 0; i < 256; i++)
00566 ipmovie->palette[i] = 0xFFU << 24;
00567
00568
00569 if (process_ipmovie_chunk(ipmovie, pb, &pkt) != CHUNK_INIT_VIDEO)
00570 return AVERROR_INVALIDDATA;
00571
00572
00573
00574 if (avio_read(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) !=
00575 CHUNK_PREAMBLE_SIZE)
00576 return AVERROR(EIO);
00577 chunk_type = AV_RL16(&chunk_preamble[2]);
00578 avio_seek(pb, -CHUNK_PREAMBLE_SIZE, SEEK_CUR);
00579
00580 if (chunk_type == CHUNK_VIDEO)
00581 ipmovie->audio_type = CODEC_ID_NONE;
00582 else if (process_ipmovie_chunk(ipmovie, pb, &pkt) != CHUNK_INIT_AUDIO)
00583 return AVERROR_INVALIDDATA;
00584
00585
00586 st = avformat_new_stream(s, NULL);
00587 if (!st)
00588 return AVERROR(ENOMEM);
00589 avpriv_set_pts_info(st, 63, 1, 1000000);
00590 ipmovie->video_stream_index = st->index;
00591 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00592 st->codec->codec_id = CODEC_ID_INTERPLAY_VIDEO;
00593 st->codec->codec_tag = 0;
00594 st->codec->width = ipmovie->video_width;
00595 st->codec->height = ipmovie->video_height;
00596 st->codec->bits_per_coded_sample = ipmovie->video_bpp;
00597
00598 if (ipmovie->audio_type) {
00599 st = avformat_new_stream(s, NULL);
00600 if (!st)
00601 return AVERROR(ENOMEM);
00602 avpriv_set_pts_info(st, 32, 1, ipmovie->audio_sample_rate);
00603 ipmovie->audio_stream_index = st->index;
00604 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00605 st->codec->codec_id = ipmovie->audio_type;
00606 st->codec->codec_tag = 0;
00607 st->codec->channels = ipmovie->audio_channels;
00608 st->codec->sample_rate = ipmovie->audio_sample_rate;
00609 st->codec->bits_per_coded_sample = ipmovie->audio_bits;
00610 st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
00611 st->codec->bits_per_coded_sample;
00612 if (st->codec->codec_id == CODEC_ID_INTERPLAY_DPCM)
00613 st->codec->bit_rate /= 2;
00614 st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample;
00615 }
00616
00617 return 0;
00618 }
00619
00620 static int ipmovie_read_packet(AVFormatContext *s,
00621 AVPacket *pkt)
00622 {
00623 IPMVEContext *ipmovie = s->priv_data;
00624 AVIOContext *pb = s->pb;
00625 int ret;
00626
00627 for (;;) {
00628 ret = process_ipmovie_chunk(ipmovie, pb, pkt);
00629 if (ret == CHUNK_BAD)
00630 ret = AVERROR_INVALIDDATA;
00631 else if (ret == CHUNK_EOF)
00632 ret = AVERROR(EIO);
00633 else if (ret == CHUNK_NOMEM)
00634 ret = AVERROR(ENOMEM);
00635 else if (ret == CHUNK_VIDEO)
00636 ret = 0;
00637 else if (ret == CHUNK_INIT_VIDEO || ret == CHUNK_INIT_AUDIO)
00638 continue;
00639 else
00640 ret = -1;
00641
00642 return ret;
00643 }
00644 }
00645
00646 AVInputFormat ff_ipmovie_demuxer = {
00647 .name = "ipmovie",
00648 .long_name = NULL_IF_CONFIG_SMALL("Interplay MVE format"),
00649 .priv_data_size = sizeof(IPMVEContext),
00650 .read_probe = ipmovie_probe,
00651 .read_header = ipmovie_read_header,
00652 .read_packet = ipmovie_read_packet,
00653 };