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