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