Libav 0.7.1
|
00001 /* 00002 * Bethsoft VID format Demuxer 00003 * Copyright (c) 2007 Nicholas Tung 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with Libav; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 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 // little endian VID tag, file starts with "VID\0" 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 /* load main header. Contents: 00067 * bytes: 'V' 'I' 'D' 00068 * int16s: always_512, nframes, width, height, delay, always_14 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); // 16 ms increments, i.e. 60 fps 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 // done with video codec, set up audio codec 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 // save the file position for the packet, include block type 00115 position = avio_tell(pb) - 1; 00116 00117 vidbuf_start[vidbuf_nbytes++] = block_type; 00118 00119 // get the video delay (next int16), and set the presentation time 00120 vid->video_pts += vid->bethsoft_global_delay + avio_rl16(pb); 00121 00122 // set the y offset if it exists (decoder header data should be in data section) 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){ // rle sequence 00138 if(block_type == VIDEO_I_FRAME) 00139 vidbuf_start[vidbuf_nbytes++] = avio_r8(pb); 00140 } else if(code){ // plain sequence 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){ // sometimes no stop character is given, need to keep track of bytes copied 00147 // may contain a 0 byte even if read all pixels 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 // copy data into packet 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; // use the video decoder, which was initialized as the first stream 00164 pkt->pts = vid->video_pts; 00165 00166 vid->nframes--; // used to check if all the frames were read 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 || pb->eof_reached) 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); // include block type 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 // soundblaster DAC used for sample rate, as on specification page (link above) 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 };