1/* 2 * Bethsoft VID format Demuxer 3 * Copyright (c) 2007 Nicholas Tung 4 * 5 * This file is part of Libav. 6 * 7 * Libav is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * Libav is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with Libav; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22/** 23 * @file 24 * @brief Bethesda Softworks VID (.vid) file demuxer 25 * @author Nicholas Tung [ntung (at. ntung com] (2007-03) 26 * @see http://wiki.multimedia.cx/index.php?title=Bethsoft_VID 27 * @see http://www.svatopluk.com/andux/docs/dfvid.html 28 */ 29 30#include "libavutil/intreadwrite.h" 31#include "avformat.h" 32#include "internal.h" 33#include "libavcodec/bethsoftvideo.h" 34 35typedef struct BVID_DemuxContext 36{ 37 int nframes; 38 /** delay value between frames, added to individual frame delay. 39 * custom units, which will be added to other custom units (~=16ms according 40 * to free, unofficial documentation) */ 41 int bethsoft_global_delay; 42 43 /** video presentation time stamp. 44 * delay = 16 milliseconds * (global_delay + per_frame_delay) */ 45 int video_pts; 46 47 int is_finished; 48 49} BVID_DemuxContext; 50 51static int vid_probe(AVProbeData *p) 52{ 53 // little endian VID tag, file starts with "VID\0" 54 if (AV_RL32(p->buf) != MKTAG('V', 'I', 'D', 0)) 55 return 0; 56 57 return AVPROBE_SCORE_MAX; 58} 59 60static int vid_read_header(AVFormatContext *s, 61 AVFormatParameters *ap) 62{ 63 BVID_DemuxContext *vid = s->priv_data; 64 AVIOContext *pb = s->pb; 65 AVStream *stream; 66 67 /* load main header. Contents: 68 * bytes: 'V' 'I' 'D' 69 * int16s: always_512, nframes, width, height, delay, always_14 70 */ 71 avio_skip(pb, 5); 72 vid->nframes = avio_rl16(pb); 73 74 stream = avformat_new_stream(s, NULL); 75 if (!stream) 76 return AVERROR(ENOMEM); 77 avpriv_set_pts_info(stream, 32, 1, 60); // 16 ms increments, i.e. 60 fps 78 stream->codec->codec_type = AVMEDIA_TYPE_VIDEO; 79 stream->codec->codec_id = CODEC_ID_BETHSOFTVID; 80 stream->codec->width = avio_rl16(pb); 81 stream->codec->height = avio_rl16(pb); 82 stream->codec->pix_fmt = PIX_FMT_PAL8; 83 vid->bethsoft_global_delay = avio_rl16(pb); 84 avio_rl16(pb); 85 86 // done with video codec, set up audio codec 87 stream = avformat_new_stream(s, NULL); 88 if (!stream) 89 return AVERROR(ENOMEM); 90 stream->codec->codec_type = AVMEDIA_TYPE_AUDIO; 91 stream->codec->codec_id = CODEC_ID_PCM_U8; 92 stream->codec->channels = 1; 93 stream->codec->sample_rate = 11025; 94 stream->codec->bits_per_coded_sample = 8; 95 stream->codec->bit_rate = stream->codec->channels * stream->codec->sample_rate * stream->codec->bits_per_coded_sample; 96 97 return 0; 98} 99 100#define BUFFER_PADDING_SIZE 1000 101static int read_frame(BVID_DemuxContext *vid, AVIOContext *pb, AVPacket *pkt, 102 uint8_t block_type, AVFormatContext *s, int npixels) 103{ 104 uint8_t * vidbuf_start = NULL; 105 int vidbuf_nbytes = 0; 106 int code; 107 int bytes_copied = 0; 108 int position; 109 unsigned int vidbuf_capacity; 110 111 vidbuf_start = av_malloc(vidbuf_capacity = BUFFER_PADDING_SIZE); 112 if(!vidbuf_start) 113 return AVERROR(ENOMEM); 114 115 // save the file position for the packet, include block type 116 position = avio_tell(pb) - 1; 117 118 vidbuf_start[vidbuf_nbytes++] = block_type; 119 120 // get the video delay (next int16), and set the presentation time 121 vid->video_pts += vid->bethsoft_global_delay + avio_rl16(pb); 122 123 // set the y offset if it exists (decoder header data should be in data section) 124 if(block_type == VIDEO_YOFF_P_FRAME){ 125 if(avio_read(pb, &vidbuf_start[vidbuf_nbytes], 2) != 2) 126 goto fail; 127 vidbuf_nbytes += 2; 128 } 129 130 do{ 131 vidbuf_start = av_fast_realloc(vidbuf_start, &vidbuf_capacity, vidbuf_nbytes + BUFFER_PADDING_SIZE); 132 if(!vidbuf_start) 133 return AVERROR(ENOMEM); 134 135 code = avio_r8(pb); 136 vidbuf_start[vidbuf_nbytes++] = code; 137 138 if(code >= 0x80){ // rle sequence 139 if(block_type == VIDEO_I_FRAME) 140 vidbuf_start[vidbuf_nbytes++] = avio_r8(pb); 141 } else if(code){ // plain sequence 142 if(avio_read(pb, &vidbuf_start[vidbuf_nbytes], code) != code) 143 goto fail; 144 vidbuf_nbytes += code; 145 } 146 bytes_copied += code & 0x7F; 147 if(bytes_copied == npixels){ // sometimes no stop character is given, need to keep track of bytes copied 148 // may contain a 0 byte even if read all pixels 149 if(avio_r8(pb)) 150 avio_seek(pb, -1, SEEK_CUR); 151 break; 152 } 153 if(bytes_copied > npixels) 154 goto fail; 155 } while(code); 156 157 // copy data into packet 158 if(av_new_packet(pkt, vidbuf_nbytes) < 0) 159 goto fail; 160 memcpy(pkt->data, vidbuf_start, vidbuf_nbytes); 161 av_free(vidbuf_start); 162 163 pkt->pos = position; 164 pkt->stream_index = 0; // use the video decoder, which was initialized as the first stream 165 pkt->pts = vid->video_pts; 166 167 vid->nframes--; // used to check if all the frames were read 168 return vidbuf_nbytes; 169fail: 170 av_free(vidbuf_start); 171 return -1; 172} 173 174static int vid_read_packet(AVFormatContext *s, 175 AVPacket *pkt) 176{ 177 BVID_DemuxContext *vid = s->priv_data; 178 AVIOContext *pb = s->pb; 179 unsigned char block_type; 180 int audio_length; 181 int ret_value; 182 183 if(vid->is_finished || pb->eof_reached) 184 return AVERROR(EIO); 185 186 block_type = avio_r8(pb); 187 switch(block_type){ 188 case PALETTE_BLOCK: 189 avio_seek(pb, -1, SEEK_CUR); // include block type 190 ret_value = av_get_packet(pb, pkt, 3 * 256 + 1); 191 if(ret_value != 3 * 256 + 1){ 192 av_free_packet(pkt); 193 return AVERROR(EIO); 194 } 195 pkt->stream_index = 0; 196 return ret_value; 197 198 case FIRST_AUDIO_BLOCK: 199 avio_rl16(pb); 200 // soundblaster DAC used for sample rate, as on specification page (link above) 201 s->streams[1]->codec->sample_rate = 1000000 / (256 - avio_r8(pb)); 202 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; 203 case AUDIO_BLOCK: 204 audio_length = avio_rl16(pb); 205 ret_value = av_get_packet(pb, pkt, audio_length); 206 pkt->stream_index = 1; 207 return ret_value != audio_length ? AVERROR(EIO) : ret_value; 208 209 case VIDEO_P_FRAME: 210 case VIDEO_YOFF_P_FRAME: 211 case VIDEO_I_FRAME: 212 return read_frame(vid, pb, pkt, block_type, s, 213 s->streams[0]->codec->width * s->streams[0]->codec->height); 214 215 case EOF_BLOCK: 216 if(vid->nframes != 0) 217 av_log(s, AV_LOG_VERBOSE, "reached terminating character but not all frames read.\n"); 218 vid->is_finished = 1; 219 return AVERROR(EIO); 220 default: 221 av_log(s, AV_LOG_ERROR, "unknown block (character = %c, decimal = %d, hex = %x)!!!\n", 222 block_type, block_type, block_type); return -1; 223 } 224} 225 226AVInputFormat ff_bethsoftvid_demuxer = { 227 .name = "bethsoftvid", 228 .long_name = NULL_IF_CONFIG_SMALL("Bethesda Softworks VID format"), 229 .priv_data_size = sizeof(BVID_DemuxContext), 230 .read_probe = vid_probe, 231 .read_header = vid_read_header, 232 .read_packet = vid_read_packet, 233}; 234