00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "avformat.h"
00023 #include "internal.h"
00024
00025 enum BMVFlags {
00026 BMV_NOP = 0,
00027 BMV_END,
00028 BMV_DELTA,
00029 BMV_INTRA,
00030
00031 BMV_AUDIO = 0x20,
00032 };
00033
00034 typedef struct BMVContext {
00035 uint8_t *packet;
00036 int size;
00037 int get_next;
00038 int64_t audio_pos;
00039 } BMVContext;
00040
00041 static int bmv_read_header(AVFormatContext *s)
00042 {
00043 AVStream *st, *ast;
00044 BMVContext *c = s->priv_data;
00045
00046 st = avformat_new_stream(s, 0);
00047 if (!st)
00048 return AVERROR(ENOMEM);
00049 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00050 st->codec->codec_id = CODEC_ID_BMV_VIDEO;
00051 st->codec->width = 640;
00052 st->codec->height = 429;
00053 st->codec->pix_fmt = PIX_FMT_PAL8;
00054 avpriv_set_pts_info(st, 16, 1, 12);
00055 ast = avformat_new_stream(s, 0);
00056 if (!ast)
00057 return AVERROR(ENOMEM);
00058 ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00059 ast->codec->codec_id = CODEC_ID_BMV_AUDIO;
00060 ast->codec->channels = 2;
00061 ast->codec->sample_rate = 22050;
00062 avpriv_set_pts_info(ast, 16, 1, 22050);
00063
00064 c->get_next = 1;
00065 c->audio_pos = 0;
00066 return 0;
00067 }
00068
00069 static int bmv_read_packet(AVFormatContext *s, AVPacket *pkt)
00070 {
00071 BMVContext *c = s->priv_data;
00072 int type;
00073 void *tmp;
00074
00075 while (c->get_next) {
00076 if (s->pb->eof_reached)
00077 return AVERROR_EOF;
00078 type = avio_r8(s->pb);
00079 if (type == BMV_NOP)
00080 continue;
00081 if (type == BMV_END)
00082 return AVERROR_EOF;
00083 c->size = avio_rl24(s->pb);
00084 if (!c->size)
00085 return AVERROR_INVALIDDATA;
00086 tmp = av_realloc(c->packet, c->size + 1);
00087 if (!tmp)
00088 return AVERROR(ENOMEM);
00089 c->packet = tmp;
00090 c->packet[0] = type;
00091 if (avio_read(s->pb, c->packet + 1, c->size) != c->size)
00092 return AVERROR(EIO);
00093 if (type & BMV_AUDIO) {
00094 int audio_size = c->packet[1] * 65 + 1;
00095 if (audio_size >= c->size) {
00096 av_log(s, AV_LOG_ERROR, "Reported audio size %d is bigger than packet size (%d)\n",
00097 audio_size, c->size);
00098 return AVERROR_INVALIDDATA;
00099 }
00100 if (av_new_packet(pkt, audio_size) < 0)
00101 return AVERROR(ENOMEM);
00102 memcpy(pkt->data, c->packet + 1, pkt->size);
00103 pkt->stream_index = 1;
00104 pkt->pts = c->audio_pos;
00105 pkt->duration = c->packet[1] * 32;
00106 c->audio_pos += pkt->duration;
00107 c->get_next = 0;
00108 return pkt->size;
00109 } else
00110 break;
00111 }
00112 if (av_new_packet(pkt, c->size + 1) < 0)
00113 return AVERROR(ENOMEM);
00114 pkt->stream_index = 0;
00115 c->get_next = 1;
00116 memcpy(pkt->data, c->packet, pkt->size);
00117 return pkt->size;
00118 }
00119
00120 static int bmv_read_close(AVFormatContext *s)
00121 {
00122 BMVContext *c = s->priv_data;
00123
00124 av_freep(&c->packet);
00125
00126 return 0;
00127 }
00128
00129 AVInputFormat ff_bmv_demuxer = {
00130 .name = "bmv",
00131 .long_name = NULL_IF_CONFIG_SMALL("Discworld II BMV"),
00132 .priv_data_size = sizeof(BMVContext),
00133 .read_header = bmv_read_header,
00134 .read_packet = bmv_read_packet,
00135 .read_close = bmv_read_close,
00136 .extensions = "bmv",
00137 };