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