• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
32 #include "libavutil/intreadwrite.h"
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 
64 typedef struct WsVqaDemuxContext {
65     int version;
66     int bps;
67     int channels;
68     int sample_rate;
69     int audio_stream_index;
70     int video_stream_index;
71     int64_t vqfl_chunk_pos;
72     int vqfl_chunk_size;
73 } WsVqaDemuxContext;
74 
wsvqa_probe(const AVProbeData * p)75 static 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 
wsvqa_read_header(AVFormatContext * s)89 static int wsvqa_read_header(AVFormatContext *s)
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 */
101     st = avformat_new_stream(s, NULL);
102     if (!st)
103         return AVERROR(ENOMEM);
104     st->start_time = 0;
105     wsvqa->video_stream_index = st->index;
106     st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
107     st->codecpar->codec_id = AV_CODEC_ID_WS_VQA;
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;
116     header = st->codecpar->extradata;
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 (avio_read(pb, scratch, VQA_PREAMBLE_SIZE) != VQA_PREAMBLE_SIZE)
142             return AVERROR(EIO);
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 
wsvqa_read_packet(AVFormatContext * s,AVPacket * pkt)173 static int wsvqa_read_packet(AVFormatContext *s,
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             ffio_ensure_seekback(pb, wsvqa->vqfl_chunk_size + (512 + 256) * 1024);
205             avio_skip(pb, chunk_size + skip_byte);
206             continue;
207         } else if ((chunk_type == SND0_TAG) || (chunk_type == SND1_TAG) ||
208             (chunk_type == SND2_TAG) || (chunk_type == VQFR_TAG)) {
209 
210             ret= av_get_packet(pb, pkt, chunk_size);
211             if (ret<0)
212                 return AVERROR(EIO);
213 
214             switch (chunk_type) {
215             case SND0_TAG:
216             case SND1_TAG:
217             case SND2_TAG:
218                 if (wsvqa->audio_stream_index == -1) {
219                     AVStream *st = avformat_new_stream(s, NULL);
220                     if (!st)
221                         return AVERROR(ENOMEM);
222 
223                     wsvqa->audio_stream_index = st->index;
224                     if (!wsvqa->sample_rate)
225                         wsvqa->sample_rate = 22050;
226                     if (!wsvqa->channels)
227                         wsvqa->channels = 1;
228                     if (!wsvqa->bps)
229                         wsvqa->bps = 8;
230                     st->codecpar->sample_rate = wsvqa->sample_rate;
231                     st->codecpar->bits_per_coded_sample = wsvqa->bps;
232                     av_channel_layout_default(&st->codecpar->ch_layout, wsvqa->channels);
233                     st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
234 
235                     avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
236 
237                     switch (chunk_type) {
238                     case SND0_TAG:
239                         if (wsvqa->bps == 16)
240                             st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE;
241                         else
242                             st->codecpar->codec_id = AV_CODEC_ID_PCM_U8;
243                         break;
244                     case SND1_TAG:
245                         st->codecpar->codec_id = AV_CODEC_ID_WESTWOOD_SND1;
246                         break;
247                     case SND2_TAG:
248                         st->codecpar->codec_id = AV_CODEC_ID_ADPCM_IMA_WS;
249                         if ((ret = ff_alloc_extradata(st->codecpar, 2)) < 0)
250                             return ret;
251                         AV_WL16(st->codecpar->extradata, wsvqa->version);
252                         break;
253                     }
254                 }
255 
256                 pkt->stream_index = wsvqa->audio_stream_index;
257                 switch (chunk_type) {
258                 case SND1_TAG:
259                     /* unpacked size is stored in header */
260                     if(pkt->data)
261                         pkt->duration = AV_RL16(pkt->data) / wsvqa->channels;
262                     break;
263                 case SND2_TAG:
264                     /* 2 samples/byte, 1 or 2 samples per frame depending on stereo */
265                     pkt->duration = (chunk_size * 2) / wsvqa->channels;
266                     break;
267                 }
268                 break;
269             case VQFR_TAG:
270                 /* if a new codebook is available inside an earlier a VQFL chunk then
271                  * append it to 'pkt' */
272                 if (wsvqa->vqfl_chunk_size > 0) {
273                     int64_t current_pos = pkt->pos;
274 
275                     if (avio_seek(pb, wsvqa->vqfl_chunk_pos, SEEK_SET) < 0)
276                         return AVERROR(EIO);
277 
278                     /* the decoder expects chunks to be 16-bit aligned */
279                     if (wsvqa->vqfl_chunk_size % 2 == 1)
280                         wsvqa->vqfl_chunk_size++;
281 
282                     if (av_append_packet(pb, pkt, wsvqa->vqfl_chunk_size) < 0)
283                         return AVERROR(EIO);
284 
285                     if (avio_seek(pb, current_pos, SEEK_SET) < 0)
286                         return AVERROR(EIO);
287 
288                     wsvqa->vqfl_chunk_pos = 0;
289                     wsvqa->vqfl_chunk_size = 0;
290                 }
291 
292                 pkt->stream_index = wsvqa->video_stream_index;
293                 pkt->duration = 1;
294                 break;
295             }
296 
297             /* stay on 16-bit alignment */
298             if (skip_byte)
299                 avio_skip(pb, 1);
300 
301             return ret;
302         } else {
303             switch(chunk_type){
304             case CMDS_TAG:
305             case SN2J_TAG:
306             case VIEW_TAG:
307             case ZBUF_TAG:
308                 break;
309             default:
310                 av_log(s, AV_LOG_INFO, "Skipping unknown chunk %s\n",
311                        av_fourcc2str(av_bswap32(chunk_type)));
312             }
313             avio_skip(pb, chunk_size + skip_byte);
314         }
315     }
316 
317     return ret;
318 }
319 
320 const AVInputFormat ff_wsvqa_demuxer = {
321     .name           = "wsvqa",
322     .long_name      = NULL_IF_CONFIG_SMALL("Westwood Studios VQA"),
323     .priv_data_size = sizeof(WsVqaDemuxContext),
324     .read_probe     = wsvqa_probe,
325     .read_header    = wsvqa_read_header,
326     .read_packet    = wsvqa_read_packet,
327 };
328