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