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