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