00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00030 #include "libavutil/intreadwrite.h"
00031 #include "avformat.h"
00032 #include "libavcodec/bethsoftvideo.h"
00033
00034 typedef struct BVID_DemuxContext
00035 {
00036 int nframes;
00040 int bethsoft_global_delay;
00041
00044 int video_pts;
00045
00046 int is_finished;
00047
00048 } BVID_DemuxContext;
00049
00050 static int vid_probe(AVProbeData *p)
00051 {
00052
00053 if (AV_RL32(p->buf) != MKTAG('V', 'I', 'D', 0))
00054 return 0;
00055
00056 return AVPROBE_SCORE_MAX;
00057 }
00058
00059 static int vid_read_header(AVFormatContext *s,
00060 AVFormatParameters *ap)
00061 {
00062 BVID_DemuxContext *vid = s->priv_data;
00063 AVIOContext *pb = s->pb;
00064 AVStream *stream;
00065
00066
00067
00068
00069
00070 avio_skip(pb, 5);
00071 vid->nframes = avio_rl16(pb);
00072
00073 stream = av_new_stream(s, 0);
00074 if (!stream)
00075 return AVERROR(ENOMEM);
00076 av_set_pts_info(stream, 32, 1, 60);
00077 stream->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00078 stream->codec->codec_id = CODEC_ID_BETHSOFTVID;
00079 stream->codec->width = avio_rl16(pb);
00080 stream->codec->height = avio_rl16(pb);
00081 stream->codec->pix_fmt = PIX_FMT_PAL8;
00082 vid->bethsoft_global_delay = avio_rl16(pb);
00083 avio_rl16(pb);
00084
00085
00086 stream = av_new_stream(s, 0);
00087 if (!stream)
00088 return AVERROR(ENOMEM);
00089 stream->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00090 stream->codec->codec_id = CODEC_ID_PCM_U8;
00091 stream->codec->channels = 1;
00092 stream->codec->sample_rate = 11025;
00093 stream->codec->bits_per_coded_sample = 8;
00094 stream->codec->bit_rate = stream->codec->channels * stream->codec->sample_rate * stream->codec->bits_per_coded_sample;
00095
00096 return 0;
00097 }
00098
00099 #define BUFFER_PADDING_SIZE 1000
00100 static int read_frame(BVID_DemuxContext *vid, AVIOContext *pb, AVPacket *pkt,
00101 uint8_t block_type, AVFormatContext *s, int npixels)
00102 {
00103 uint8_t * vidbuf_start = NULL;
00104 int vidbuf_nbytes = 0;
00105 int code;
00106 int bytes_copied = 0;
00107 int position;
00108 unsigned int vidbuf_capacity;
00109
00110 vidbuf_start = av_malloc(vidbuf_capacity = BUFFER_PADDING_SIZE);
00111 if(!vidbuf_start)
00112 return AVERROR(ENOMEM);
00113
00114
00115 position = avio_tell(pb) - 1;
00116
00117 vidbuf_start[vidbuf_nbytes++] = block_type;
00118
00119
00120 vid->video_pts += vid->bethsoft_global_delay + avio_rl16(pb);
00121
00122
00123 if(block_type == VIDEO_YOFF_P_FRAME){
00124 if(avio_read(pb, &vidbuf_start[vidbuf_nbytes], 2) != 2)
00125 goto fail;
00126 vidbuf_nbytes += 2;
00127 }
00128
00129 do{
00130 vidbuf_start = av_fast_realloc(vidbuf_start, &vidbuf_capacity, vidbuf_nbytes + BUFFER_PADDING_SIZE);
00131 if(!vidbuf_start)
00132 return AVERROR(ENOMEM);
00133
00134 code = avio_r8(pb);
00135 vidbuf_start[vidbuf_nbytes++] = code;
00136
00137 if(code >= 0x80){
00138 if(block_type == VIDEO_I_FRAME)
00139 vidbuf_start[vidbuf_nbytes++] = avio_r8(pb);
00140 } else if(code){
00141 if(avio_read(pb, &vidbuf_start[vidbuf_nbytes], code) != code)
00142 goto fail;
00143 vidbuf_nbytes += code;
00144 }
00145 bytes_copied += code & 0x7F;
00146 if(bytes_copied == npixels){
00147
00148 if(avio_r8(pb))
00149 avio_seek(pb, -1, SEEK_CUR);
00150 break;
00151 }
00152 if(bytes_copied > npixels)
00153 goto fail;
00154 } while(code);
00155
00156
00157 if(av_new_packet(pkt, vidbuf_nbytes) < 0)
00158 goto fail;
00159 memcpy(pkt->data, vidbuf_start, vidbuf_nbytes);
00160 av_free(vidbuf_start);
00161
00162 pkt->pos = position;
00163 pkt->stream_index = 0;
00164 pkt->pts = vid->video_pts;
00165
00166 vid->nframes--;
00167 return vidbuf_nbytes;
00168 fail:
00169 av_free(vidbuf_start);
00170 return -1;
00171 }
00172
00173 static int vid_read_packet(AVFormatContext *s,
00174 AVPacket *pkt)
00175 {
00176 BVID_DemuxContext *vid = s->priv_data;
00177 AVIOContext *pb = s->pb;
00178 unsigned char block_type;
00179 int audio_length;
00180 int ret_value;
00181
00182 if(vid->is_finished || url_feof(pb))
00183 return AVERROR(EIO);
00184
00185 block_type = avio_r8(pb);
00186 switch(block_type){
00187 case PALETTE_BLOCK:
00188 avio_seek(pb, -1, SEEK_CUR);
00189 ret_value = av_get_packet(pb, pkt, 3 * 256 + 1);
00190 if(ret_value != 3 * 256 + 1){
00191 av_free_packet(pkt);
00192 return AVERROR(EIO);
00193 }
00194 pkt->stream_index = 0;
00195 return ret_value;
00196
00197 case FIRST_AUDIO_BLOCK:
00198 avio_rl16(pb);
00199
00200 s->streams[1]->codec->sample_rate = 1000000 / (256 - avio_r8(pb));
00201 s->streams[1]->codec->bit_rate = s->streams[1]->codec->channels * s->streams[1]->codec->sample_rate * s->streams[1]->codec->bits_per_coded_sample;
00202 case AUDIO_BLOCK:
00203 audio_length = avio_rl16(pb);
00204 ret_value = av_get_packet(pb, pkt, audio_length);
00205 pkt->stream_index = 1;
00206 return ret_value != audio_length ? AVERROR(EIO) : ret_value;
00207
00208 case VIDEO_P_FRAME:
00209 case VIDEO_YOFF_P_FRAME:
00210 case VIDEO_I_FRAME:
00211 return read_frame(vid, pb, pkt, block_type, s,
00212 s->streams[0]->codec->width * s->streams[0]->codec->height);
00213
00214 case EOF_BLOCK:
00215 if(vid->nframes != 0)
00216 av_log(s, AV_LOG_VERBOSE, "reached terminating character but not all frames read.\n");
00217 vid->is_finished = 1;
00218 return AVERROR(EIO);
00219 default:
00220 av_log(s, AV_LOG_ERROR, "unknown block (character = %c, decimal = %d, hex = %x)!!!\n",
00221 block_type, block_type, block_type); return -1;
00222 }
00223
00224 return 0;
00225 }
00226
00227 AVInputFormat ff_bethsoftvid_demuxer = {
00228 "bethsoftvid",
00229 NULL_IF_CONFIG_SMALL("Bethesda Softworks VID format"),
00230 sizeof(BVID_DemuxContext),
00231 vid_probe,
00232 vid_read_header,
00233 vid_read_packet,
00234 };