~ubuntu-branches/ubuntu/saucy/gst-libav1.0/saucy-proposed

« back to all changes in this revision

Viewing changes to gst-libs/ext/libav/libavformat/westwood_vqa.c

  • Committer: Package Import Robot
  • Author(s): Sebastian Dröge
  • Date: 2013-07-30 09:00:15 UTC
  • mfrom: (1.1.16) (7.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20130730090015-sc1ou2yssu7q5w4e
Tags: 1.1.3-1
* New upstream development snapshot:
  + debian/control:
    - Build depend on GStreamer and gst-plugins-base >= 1.1.3.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Westwood Studios VQA Format Demuxer
 
3
 * Copyright (c) 2003 The ffmpeg Project
 
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
 * Westwood Studios VQA file demuxer
 
25
 * by Mike Melanson (melanson@pcisys.net)
 
26
 * for more information on the Westwood file formats, visit:
 
27
 *   http://www.pcisys.net/~melanson/codecs/
 
28
 *   http://www.geocities.com/SiliconValley/8682/aud3.txt
 
29
 */
 
30
 
 
31
#include "libavutil/intreadwrite.h"
 
32
#include "avformat.h"
 
33
#include "internal.h"
 
34
 
 
35
#define FORM_TAG MKBETAG('F', 'O', 'R', 'M')
 
36
#define WVQA_TAG MKBETAG('W', 'V', 'Q', 'A')
 
37
#define VQHD_TAG MKBETAG('V', 'Q', 'H', 'D')
 
38
#define FINF_TAG MKBETAG('F', 'I', 'N', 'F')
 
39
#define SND0_TAG MKBETAG('S', 'N', 'D', '0')
 
40
#define SND1_TAG MKBETAG('S', 'N', 'D', '1')
 
41
#define SND2_TAG MKBETAG('S', 'N', 'D', '2')
 
42
#define VQFR_TAG MKBETAG('V', 'Q', 'F', 'R')
 
43
 
 
44
/* don't know what these tags are for, but acknowledge their existence */
 
45
#define CINF_TAG MKBETAG('C', 'I', 'N', 'F')
 
46
#define CINH_TAG MKBETAG('C', 'I', 'N', 'H')
 
47
#define CIND_TAG MKBETAG('C', 'I', 'N', 'D')
 
48
#define PINF_TAG MKBETAG('P', 'I', 'N', 'F')
 
49
#define PINH_TAG MKBETAG('P', 'I', 'N', 'H')
 
50
#define PIND_TAG MKBETAG('P', 'I', 'N', 'D')
 
51
#define CMDS_TAG MKBETAG('C', 'M', 'D', 'S')
 
52
 
 
53
#define VQA_HEADER_SIZE 0x2A
 
54
#define VQA_PREAMBLE_SIZE 8
 
55
 
 
56
typedef struct WsVqaDemuxContext {
 
57
    int version;
 
58
    int bps;
 
59
    int channels;
 
60
    int sample_rate;
 
61
    int audio_stream_index;
 
62
    int video_stream_index;
 
63
} WsVqaDemuxContext;
 
64
 
 
65
static int wsvqa_probe(AVProbeData *p)
 
66
{
 
67
    /* need 12 bytes to qualify */
 
68
    if (p->buf_size < 12)
 
69
        return 0;
 
70
 
 
71
    /* check for the VQA signatures */
 
72
    if ((AV_RB32(&p->buf[0]) != FORM_TAG) ||
 
73
        (AV_RB32(&p->buf[8]) != WVQA_TAG))
 
74
        return 0;
 
75
 
 
76
    return AVPROBE_SCORE_MAX;
 
77
}
 
78
 
 
79
static int wsvqa_read_header(AVFormatContext *s)
 
80
{
 
81
    WsVqaDemuxContext *wsvqa = s->priv_data;
 
82
    AVIOContext *pb = s->pb;
 
83
    AVStream *st;
 
84
    unsigned char *header;
 
85
    unsigned char scratch[VQA_PREAMBLE_SIZE];
 
86
    unsigned int chunk_tag;
 
87
    unsigned int chunk_size;
 
88
    int fps;
 
89
 
 
90
    /* initialize the video decoder stream */
 
91
    st = avformat_new_stream(s, NULL);
 
92
    if (!st)
 
93
        return AVERROR(ENOMEM);
 
94
    st->start_time = 0;
 
95
    wsvqa->video_stream_index = st->index;
 
96
    st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
 
97
    st->codec->codec_id = AV_CODEC_ID_WS_VQA;
 
98
    st->codec->codec_tag = 0;  /* no fourcc */
 
99
 
 
100
    /* skip to the start of the VQA header */
 
101
    avio_seek(pb, 20, SEEK_SET);
 
102
 
 
103
    /* the VQA header needs to go to the decoder */
 
104
    st->codec->extradata_size = VQA_HEADER_SIZE;
 
105
    st->codec->extradata = av_mallocz(VQA_HEADER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
 
106
    header = (unsigned char *)st->codec->extradata;
 
107
    if (avio_read(pb, st->codec->extradata, VQA_HEADER_SIZE) !=
 
108
        VQA_HEADER_SIZE) {
 
109
        av_free(st->codec->extradata);
 
110
        return AVERROR(EIO);
 
111
    }
 
112
    st->codec->width = AV_RL16(&header[6]);
 
113
    st->codec->height = AV_RL16(&header[8]);
 
114
    fps = header[12];
 
115
    st->nb_frames =
 
116
    st->duration  = AV_RL16(&header[4]);
 
117
    if (fps < 1 || fps > 30) {
 
118
        av_log(s, AV_LOG_ERROR, "invalid fps: %d\n", fps);
 
119
        return AVERROR_INVALIDDATA;
 
120
    }
 
121
    avpriv_set_pts_info(st, 64, 1, fps);
 
122
 
 
123
    wsvqa->version      = AV_RL16(&header[ 0]);
 
124
    wsvqa->sample_rate  = AV_RL16(&header[24]);
 
125
    wsvqa->channels     = header[26];
 
126
    wsvqa->bps          = header[27];
 
127
    wsvqa->audio_stream_index = -1;
 
128
 
 
129
    s->ctx_flags |= AVFMTCTX_NOHEADER;
 
130
 
 
131
    /* there are 0 or more chunks before the FINF chunk; iterate until
 
132
     * FINF has been skipped and the file will be ready to be demuxed */
 
133
    do {
 
134
        if (avio_read(pb, scratch, VQA_PREAMBLE_SIZE) != VQA_PREAMBLE_SIZE) {
 
135
            av_free(st->codec->extradata);
 
136
            return AVERROR(EIO);
 
137
        }
 
138
        chunk_tag = AV_RB32(&scratch[0]);
 
139
        chunk_size = AV_RB32(&scratch[4]);
 
140
 
 
141
        /* catch any unknown header tags, for curiousity */
 
142
        switch (chunk_tag) {
 
143
        case CINF_TAG:
 
144
        case CINH_TAG:
 
145
        case CIND_TAG:
 
146
        case PINF_TAG:
 
147
        case PINH_TAG:
 
148
        case PIND_TAG:
 
149
        case FINF_TAG:
 
150
        case CMDS_TAG:
 
151
            break;
 
152
 
 
153
        default:
 
154
            av_log (s, AV_LOG_ERROR, " note: unknown chunk seen (%c%c%c%c)\n",
 
155
                scratch[0], scratch[1],
 
156
                scratch[2], scratch[3]);
 
157
            break;
 
158
        }
 
159
 
 
160
        avio_skip(pb, chunk_size);
 
161
    } while (chunk_tag != FINF_TAG);
 
162
 
 
163
    return 0;
 
164
}
 
165
 
 
166
static int wsvqa_read_packet(AVFormatContext *s,
 
167
                             AVPacket *pkt)
 
168
{
 
169
    WsVqaDemuxContext *wsvqa = s->priv_data;
 
170
    AVIOContext *pb = s->pb;
 
171
    int ret = -1;
 
172
    unsigned char preamble[VQA_PREAMBLE_SIZE];
 
173
    unsigned int chunk_type;
 
174
    unsigned int chunk_size;
 
175
    int skip_byte;
 
176
 
 
177
    while (avio_read(pb, preamble, VQA_PREAMBLE_SIZE) == VQA_PREAMBLE_SIZE) {
 
178
        chunk_type = AV_RB32(&preamble[0]);
 
179
        chunk_size = AV_RB32(&preamble[4]);
 
180
        skip_byte = chunk_size & 0x01;
 
181
 
 
182
        if ((chunk_type == SND0_TAG) || (chunk_type == SND1_TAG) ||
 
183
            (chunk_type == SND2_TAG) || (chunk_type == VQFR_TAG)) {
 
184
 
 
185
            if (av_new_packet(pkt, chunk_size))
 
186
                return AVERROR(EIO);
 
187
            ret = avio_read(pb, pkt->data, chunk_size);
 
188
            if (ret != chunk_size) {
 
189
                av_free_packet(pkt);
 
190
                return AVERROR(EIO);
 
191
            }
 
192
 
 
193
            switch (chunk_type) {
 
194
            case SND0_TAG:
 
195
            case SND1_TAG:
 
196
            case SND2_TAG:
 
197
                if (wsvqa->audio_stream_index == -1) {
 
198
                    AVStream *st = avformat_new_stream(s, NULL);
 
199
                    if (!st)
 
200
                        return AVERROR(ENOMEM);
 
201
 
 
202
                    wsvqa->audio_stream_index = st->index;
 
203
                    if (!wsvqa->sample_rate)
 
204
                        wsvqa->sample_rate = 22050;
 
205
                    if (!wsvqa->channels)
 
206
                        wsvqa->channels = 1;
 
207
                    if (!wsvqa->bps)
 
208
                        wsvqa->bps = 8;
 
209
                    st->codec->sample_rate = wsvqa->sample_rate;
 
210
                    st->codec->bits_per_coded_sample = wsvqa->bps;
 
211
                    st->codec->channels = wsvqa->channels;
 
212
                    st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
 
213
 
 
214
                    avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
 
215
 
 
216
                    switch (chunk_type) {
 
217
                    case SND0_TAG:
 
218
                        if (wsvqa->bps == 16)
 
219
                            st->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
 
220
                        else
 
221
                            st->codec->codec_id = AV_CODEC_ID_PCM_U8;
 
222
                        break;
 
223
                    case SND1_TAG:
 
224
                        st->codec->codec_id = AV_CODEC_ID_WESTWOOD_SND1;
 
225
                        break;
 
226
                    case SND2_TAG:
 
227
                        st->codec->codec_id = AV_CODEC_ID_ADPCM_IMA_WS;
 
228
                        st->codec->extradata_size = 2;
 
229
                        st->codec->extradata = av_mallocz(2 + FF_INPUT_BUFFER_PADDING_SIZE);
 
230
                        if (!st->codec->extradata)
 
231
                            return AVERROR(ENOMEM);
 
232
                        AV_WL16(st->codec->extradata, wsvqa->version);
 
233
                        break;
 
234
                    }
 
235
                }
 
236
 
 
237
                pkt->stream_index = wsvqa->audio_stream_index;
 
238
                switch (chunk_type) {
 
239
                case SND1_TAG:
 
240
                    /* unpacked size is stored in header */
 
241
                    pkt->duration = AV_RL16(pkt->data) / wsvqa->channels;
 
242
                    break;
 
243
                case SND2_TAG:
 
244
                    /* 2 samples/byte, 1 or 2 samples per frame depending on stereo */
 
245
                    pkt->duration = (chunk_size * 2) / wsvqa->channels;
 
246
                    break;
 
247
                }
 
248
                break;
 
249
            case VQFR_TAG:
 
250
                pkt->stream_index = wsvqa->video_stream_index;
 
251
                pkt->duration = 1;
 
252
                break;
 
253
            }
 
254
 
 
255
            /* stay on 16-bit alignment */
 
256
            if (skip_byte)
 
257
                avio_skip(pb, 1);
 
258
 
 
259
            return ret;
 
260
        } else {
 
261
            switch(chunk_type){
 
262
            case CMDS_TAG:
 
263
                break;
 
264
            default:
 
265
                av_log(s, AV_LOG_INFO, "Skipping unknown chunk 0x%08X\n", chunk_type);
 
266
            }
 
267
            avio_skip(pb, chunk_size + skip_byte);
 
268
        }
 
269
    }
 
270
 
 
271
    return ret;
 
272
}
 
273
 
 
274
AVInputFormat ff_wsvqa_demuxer = {
 
275
    .name           = "wsvqa",
 
276
    .long_name      = NULL_IF_CONFIG_SMALL("Westwood Studios VQA"),
 
277
    .priv_data_size = sizeof(WsVqaDemuxContext),
 
278
    .read_probe     = wsvqa_probe,
 
279
    .read_header    = wsvqa_read_header,
 
280
    .read_packet    = wsvqa_read_packet,
 
281
};