FFmpeg
Loading...
Searching...
No Matches
westwood_vqa.c
Go to the documentation of this file.
1/*
2 * Westwood Studios VQA Format Demuxer
3 * Copyright (c) 2003 Mike Melanson <melanson@pcisys.net>
4 * Copyright (c) 2021 Pekka Väänänen <pekka.vaananen@iki.fi>
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23/**
24 * @file
25 * Westwood Studios VQA file demuxer
26 * by Mike Melanson (melanson@pcisys.net)
27 * for more information on the Westwood file formats, visit:
28 * http://www.pcisys.net/~melanson/codecs/
29 * http://www.geocities.com/SiliconValley/8682/aud3.txt
30 */
31
33#include "avformat.h"
34#include "avio_internal.h"
35#include "demux.h"
36#include "internal.h"
37
38#define FORM_TAG MKBETAG('F', 'O', 'R', 'M')
39#define WVQA_TAG MKBETAG('W', 'V', 'Q', 'A')
40#define VQHD_TAG MKBETAG('V', 'Q', 'H', 'D')
41#define FINF_TAG MKBETAG('F', 'I', 'N', 'F')
42#define SND0_TAG MKBETAG('S', 'N', 'D', '0')
43#define SND1_TAG MKBETAG('S', 'N', 'D', '1')
44#define SND2_TAG MKBETAG('S', 'N', 'D', '2')
45#define VQFR_TAG MKBETAG('V', 'Q', 'F', 'R')
46#define VQFL_TAG MKBETAG('V', 'Q', 'F', 'L')
47
48/* don't know what these tags are for, but acknowledge their existence */
49#define CINF_TAG MKBETAG('C', 'I', 'N', 'F')
50#define CINH_TAG MKBETAG('C', 'I', 'N', 'H')
51#define CIND_TAG MKBETAG('C', 'I', 'N', 'D')
52#define LINF_TAG MKBETAG('L', 'I', 'N', 'F')
53#define PINF_TAG MKBETAG('P', 'I', 'N', 'F')
54#define PINH_TAG MKBETAG('P', 'I', 'N', 'H')
55#define PIND_TAG MKBETAG('P', 'I', 'N', 'D')
56#define CMDS_TAG MKBETAG('C', 'M', 'D', 'S')
57#define SN2J_TAG MKBETAG('S', 'N', '2', 'J')
58#define VIEW_TAG MKBETAG('V', 'I', 'E', 'W')
59#define ZBUF_TAG MKBETAG('Z', 'B', 'U', 'F')
60
61#define VQA_HEADER_SIZE 0x2A
62#define VQA_PREAMBLE_SIZE 8
63
74
75static int wsvqa_probe(const AVProbeData *p)
76{
77 /* need 12 bytes to qualify */
78 if (p->buf_size < 12)
79 return 0;
80
81 /* check for the VQA signatures */
82 if ((AV_RB32(&p->buf[0]) != FORM_TAG) ||
83 (AV_RB32(&p->buf[8]) != WVQA_TAG))
84 return 0;
85
86 return AVPROBE_SCORE_MAX;
87}
88
90{
91 WsVqaDemuxContext *wsvqa = s->priv_data;
92 AVIOContext *pb = s->pb;
93 AVStream *st;
94 uint8_t *header;
95 uint8_t scratch[VQA_PREAMBLE_SIZE];
96 uint32_t chunk_tag;
97 uint32_t chunk_size;
98 int fps, ret;
99
100 /* initialize the video decoder stream */
102 if (!st)
103 return AVERROR(ENOMEM);
104 st->start_time = 0;
105 wsvqa->video_stream_index = st->index;
108 st->codecpar->codec_tag = 0; /* no fourcc */
109
110 /* skip to the start of the VQA header */
111 avio_seek(pb, 20, SEEK_SET);
112
113 /* the VQA header needs to go to the decoder */
114 if ((ret = ff_get_extradata(s, st->codecpar, pb, VQA_HEADER_SIZE)) < 0)
115 return ret;
117 st->codecpar->width = AV_RL16(&header[6]);
118 st->codecpar->height = AV_RL16(&header[8]);
119 fps = header[12];
120 st->nb_frames =
121 st->duration = AV_RL16(&header[4]);
122 if (fps < 1 || fps > 30) {
123 av_log(s, AV_LOG_ERROR, "invalid fps: %d\n", fps);
124 return AVERROR_INVALIDDATA;
125 }
126 avpriv_set_pts_info(st, 64, 1, fps);
127
128 wsvqa->version = AV_RL16(&header[ 0]);
129 wsvqa->sample_rate = AV_RL16(&header[24]);
130 wsvqa->channels = header[26];
131 wsvqa->bps = header[27];
132 wsvqa->audio_stream_index = -1;
133 wsvqa->vqfl_chunk_pos = 0;
134 wsvqa->vqfl_chunk_size = 0;
135
136 s->ctx_flags |= AVFMTCTX_NOHEADER;
137
138 /* there are 0 or more chunks before the FINF chunk; iterate until
139 * FINF has been skipped and the file will be ready to be demuxed */
140 do {
141 if ((ret = ffio_read_size(pb, scratch, VQA_PREAMBLE_SIZE)) < 0)
142 return ret;
143 chunk_tag = AV_RB32(&scratch[0]);
144 chunk_size = AV_RB32(&scratch[4]);
145
146 /* catch any unknown header tags, for curiosity */
147 switch (chunk_tag) {
148 case CINF_TAG:
149 case CINH_TAG:
150 case CIND_TAG:
151 case LINF_TAG:
152 case PINF_TAG:
153 case PINH_TAG:
154 case PIND_TAG:
155 case FINF_TAG:
156 case CMDS_TAG:
157 case VIEW_TAG:
158 case ZBUF_TAG:
159 break;
160
161 default:
162 av_log(s, AV_LOG_ERROR, " note: unknown chunk seen (%s)\n",
163 av_fourcc2str(chunk_tag));
164 break;
165 }
166
167 avio_skip(pb, chunk_size);
168 } while (chunk_tag != FINF_TAG);
169
170 return 0;
171}
172
174 AVPacket *pkt)
175{
176 WsVqaDemuxContext *wsvqa = s->priv_data;
177 AVIOContext *pb = s->pb;
178 int ret = -1;
179 uint8_t preamble[VQA_PREAMBLE_SIZE];
180 uint32_t chunk_type;
181 int chunk_size;
182 unsigned skip_byte;
183
184 while (avio_read(pb, preamble, VQA_PREAMBLE_SIZE) == VQA_PREAMBLE_SIZE) {
185 chunk_type = AV_RB32(&preamble[0]);
186 chunk_size = AV_RB32(&preamble[4]);
187
188 if (chunk_size < 0)
189 return AVERROR_INVALIDDATA;
190 skip_byte = chunk_size & 0x01;
191
192 if (chunk_type == VQFL_TAG) {
193 /* Each VQFL chunk carries only a codebook update inside which must be applied
194 * before the next VQFR is rendered. That's why we stash the VQFL offset here
195 * so it can be combined with the next VQFR packet. This way each packet
196 * includes a whole frame as expected. */
197 wsvqa->vqfl_chunk_pos = avio_tell(pb);
198 if (chunk_size > 3 * (1 << 20))
199 return AVERROR_INVALIDDATA;
200 wsvqa->vqfl_chunk_size = chunk_size;
201 /* We need a big seekback buffer because there can be SNxx, VIEW and ZBUF
202 * chunks (<512 KiB total) in the stream before we read VQFR (<256 KiB) and
203 * seek back here. */
204 ret = ffio_ensure_seekback(pb, wsvqa->vqfl_chunk_size + (512 + 256) * 1024);
205 avio_skip(pb, chunk_size + skip_byte);
206 if (ret < 0)
207 return ret;
208 continue;
209 } else if ((chunk_type == SND0_TAG) || (chunk_type == SND1_TAG) ||
210 (chunk_type == SND2_TAG) || (chunk_type == VQFR_TAG)) {
211
212 ret= av_get_packet(pb, pkt, chunk_size);
213 if (ret<0)
214 return AVERROR_INVALIDDATA;
215
216 switch (chunk_type) {
217 case SND0_TAG:
218 case SND1_TAG:
219 case SND2_TAG:
220 if (wsvqa->audio_stream_index == -1) {
222 if (!st)
223 return AVERROR(ENOMEM);
224
225 wsvqa->audio_stream_index = st->index;
226 if (!wsvqa->sample_rate)
227 wsvqa->sample_rate = 22050;
228 if (!wsvqa->channels)
229 wsvqa->channels = 1;
230 if (!wsvqa->bps)
231 wsvqa->bps = 8;
232 st->codecpar->sample_rate = wsvqa->sample_rate;
233 st->codecpar->bits_per_coded_sample = wsvqa->bps;
236
238
239 switch (chunk_type) {
240 case SND0_TAG:
241 if (wsvqa->bps == 16)
243 else
245 break;
246 case SND1_TAG:
248 break;
249 case SND2_TAG:
251 if ((ret = ff_alloc_extradata(st->codecpar, 2)) < 0)
252 return ret;
253 AV_WL16(st->codecpar->extradata, wsvqa->version);
254 break;
255 }
256 }
257
258 pkt->stream_index = wsvqa->audio_stream_index;
259 switch (chunk_type) {
260 case SND1_TAG:
261 /* unpacked size is stored in header */
262 if(pkt->data)
263 pkt->duration = AV_RL16(pkt->data) / wsvqa->channels;
264 break;
265 case SND2_TAG:
266 /* 2 samples/byte, 1 or 2 samples per frame depending on stereo */
267 pkt->duration = (chunk_size * 2LL) / wsvqa->channels;
268 break;
269 }
270 break;
271 case VQFR_TAG:
272 /* if a new codebook is available inside an earlier a VQFL chunk then
273 * append it to 'pkt' */
274 if (wsvqa->vqfl_chunk_size > 0) {
275 int64_t ret64, current_pos = pkt->pos;
276
277 if ((ret64 = avio_seek(pb, wsvqa->vqfl_chunk_pos, SEEK_SET)) < 0)
278 return (int)ret64;
279
280 /* the decoder expects chunks to be 16-bit aligned */
281 if (wsvqa->vqfl_chunk_size % 2 == 1)
282 wsvqa->vqfl_chunk_size++;
283
284 if (av_append_packet(pb, pkt, wsvqa->vqfl_chunk_size) < 0)
285 return AVERROR_INVALIDDATA;
286
287 if ((ret64 = avio_seek(pb, current_pos, SEEK_SET)) < 0)
288 return (int)ret64;
289
290 wsvqa->vqfl_chunk_pos = 0;
291 wsvqa->vqfl_chunk_size = 0;
292 }
293
294 pkt->stream_index = wsvqa->video_stream_index;
295 pkt->duration = 1;
296 break;
297 }
298
299 /* stay on 16-bit alignment */
300 if (skip_byte)
301 avio_skip(pb, 1);
302
303 return ret;
304 } else {
305 switch(chunk_type){
306 case CMDS_TAG:
307 case SN2J_TAG:
308 case VIEW_TAG:
309 case ZBUF_TAG:
310 break;
311 default:
312 av_log(s, AV_LOG_INFO, "Skipping unknown chunk %s\n",
313 av_fourcc2str(av_bswap32(chunk_type)));
314 }
315 avio_skip(pb, chunk_size + skip_byte);
316 }
317 }
318
319 return ret;
320}
321
323 .p.name = "wsvqa",
324 .p.long_name = NULL_IF_CONFIG_SMALL("Westwood Studios VQA"),
325 .priv_data_size = sizeof(WsVqaDemuxContext),
329};
const FFInputFormat ff_wsvqa_demuxer
void avpriv_set_pts_info(AVStream *st, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition avformat.c:834
Main libavformat public API header.
int av_append_packet(AVIOContext *s, AVPacket *pkt, int size)
Read data and append it to the current content of the AVPacket.
Definition utils.c:114
#define AVPROBE_SCORE_MAX
maximum score
Definition avformat.h:483
#define AVFMTCTX_NOHEADER
signal that no header is present (streams are added dynamically)
Definition avformat.h:1284
int av_get_packet(AVIOContext *s, AVPacket *pkt, int size)
Allocate and read the payload of a packet and initialize its fields with default values.
Definition utils.c:98
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition aviobuf.c:236
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition avio.h:494
int64_t avio_skip(AVIOContext *s, int64_t offset)
Skip given number of bytes forward.
Definition aviobuf.c:321
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition aviobuf.c:615
int ffio_ensure_seekback(AVIOContext *s, int64_t buf_size)
Ensures that the requested seekback buffer size will be available.
Definition aviobuf.c:1026
int ffio_read_size(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition aviobuf.c:665
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
#define s(width, name)
Definition cbs_vp9.c:198
static int read_probe(const AVProbeData *p)
Definition cdg.c:30
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
int ff_get_extradata(void *logctx, AVCodecParameters *par, AVIOContext *pb, int size)
Allocate extradata with additional AV_INPUT_BUFFER_PADDING_SIZE at end which is always set to 0 and f...
static AVPacket * pkt
static int read_header(FFV1Context *f, RangeCoder *c)
Definition ffv1dec.c:578
@ AV_CODEC_ID_ADPCM_IMA_WS
Definition codec_id.h:374
@ AV_CODEC_ID_PCM_U8
Definition codec_id.h:335
@ AV_CODEC_ID_PCM_S16LE
Definition codec_id.h:330
@ AV_CODEC_ID_WS_VQA
Definition codec_id.h:94
@ AV_CODEC_ID_WESTWOOD_SND1
Definition codec_id.h:470
AVStream * avformat_new_stream(AVFormatContext *s, const struct AVCodec *c)
Add a new stream to a media file.
void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels)
Get the default channel layout for a given number of channels.
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_INFO
Standard information.
Definition log.h:221
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
#define av_fourcc2str(fourcc)
Definition avutil.h:323
@ AVMEDIA_TYPE_AUDIO
Definition avutil.h:201
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
#define AV_RB32(p)
#define AV_RL16(p)
#define AV_WL16(p, v)
int ff_alloc_extradata(AVCodecParameters *par, int size)
Allocate extradata with additional AV_INPUT_BUFFER_PADDING_SIZE at end which is always set to 0.
Definition utils.c:237
#define FORM_TAG
Definition rl2.c:46
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
#define av_bswap32
Definition bswap.h:47
static const uint8_t header[24]
Definition sdr2.c:68
int height
The height of the video frame in pixels.
Definition codec_par.h:150
int bits_per_coded_sample
The number of bits per sample in the codedwords.
Definition codec_par.h:113
AVChannelLayout ch_layout
The channel layout and number of channels.
Definition codec_par.h:207
int width
The width of the video frame in pixels.
Definition codec_par.h:143
enum AVMediaType codec_type
General type of the encoded data.
Definition codec_par.h:53
uint32_t codec_tag
Additional information about the codec (corresponds to the AVI FOURCC).
Definition codec_par.h:61
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition codec_par.h:71
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition codec_par.h:57
int sample_rate
The number of audio samples per second.
Definition codec_par.h:213
Format I/O context.
Definition avformat.h:1333
Bytestream IO Context.
Definition avio.h:160
This structure stores compressed data.
Definition packet.h:580
This structure contains the data a format has to probe a file.
Definition avformat.h:471
Stream structure.
Definition avformat.h:766
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition avformat.h:789
int64_t nb_frames
number of frames in this stream if known or 0
Definition avformat.h:827
int64_t duration
Decoding: duration of the stream, in stream time base.
Definition avformat.h:825
int index
stream index in AVFormatContext
Definition avformat.h:772
int64_t start_time
Decoding: pts of the first frame of the stream in presentation order, in stream time base.
Definition avformat.h:815
#define av_log(a,...)
#define VQA_HEADER_SIZE
Definition vqavideo.c:83
#define SND1_TAG
#define VQFL_TAG
#define CINH_TAG
#define SND0_TAG
static int wsvqa_probe(const AVProbeData *p)
static int wsvqa_read_header(AVFormatContext *s)
#define SND2_TAG
#define ZBUF_TAG
#define VIEW_TAG
#define VQFR_TAG
#define FINF_TAG
#define PIND_TAG
#define CMDS_TAG
#define LINF_TAG
#define VQA_PREAMBLE_SIZE
#define CINF_TAG
#define PINF_TAG
#define PINH_TAG
#define SN2J_TAG
#define WVQA_TAG
#define CIND_TAG
static int wsvqa_read_packet(AVFormatContext *s, AVPacket *pkt)