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