Statistics
| Branch: | Revision:

ffmpeg / libavformat / idroq.c @ 1d7d9935

History | View | Annotate | Download (8.7 KB)

1 3ef8be2b Mike Melanson
/*
2
 * Id RoQ (.roq) File Demuxer
3
 * Copyright (c) 2003 The ffmpeg Project
4
 *
5 b78e7197 Diego Biurrun
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8 3ef8be2b Mike Melanson
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10 b78e7197 Diego Biurrun
 * version 2.1 of the License, or (at your option) any later version.
11 3ef8be2b Mike Melanson
 *
12 b78e7197 Diego Biurrun
 * FFmpeg is distributed in the hope that it will be useful,
13 3ef8be2b Mike Melanson
 * 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 b78e7197 Diego Biurrun
 * License along with FFmpeg; if not, write to the Free Software
19 5509bffa Diego Biurrun
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 3ef8be2b Mike Melanson
 */
21
22
/**
23
 * @file idroq.c
24
 * Id RoQ format file demuxer
25
 * by Mike Melanson (melanson@pcisys.net)
26
 * for more information on the .roq file format, visit:
27
 *   http://www.csse.monash.edu.au/~timf/
28
 */
29
30
#include "avformat.h"
31
32
#define RoQ_MAGIC_NUMBER 0x1084
33
#define RoQ_CHUNK_PREAMBLE_SIZE 8
34
#define RoQ_AUDIO_SAMPLE_RATE 22050
35
#define RoQ_CHUNKS_TO_SCAN 30
36
37
#define RoQ_INFO           0x1001
38
#define RoQ_QUAD_CODEBOOK  0x1002
39
#define RoQ_QUAD_VQ        0x1011
40
#define RoQ_SOUND_MONO     0x1020
41
#define RoQ_SOUND_STEREO   0x1021
42
43
typedef struct RoqDemuxContext {
44
45
    int width;
46
    int height;
47
    int audio_channels;
48
    int framerate;
49
    int frame_pts_inc;
50
51
    int video_stream_index;
52
    int audio_stream_index;
53
54
    int64_t video_pts;
55
    unsigned int audio_frame_count;
56
57
} RoqDemuxContext;
58
59
static int roq_probe(AVProbeData *p)
60
{
61 e7106d5b Mike Melanson
    if (p->buf_size < 6)
62
        return 0;
63
64 fead30d4 Alex Beregszaszi
    if ((AV_RL16(&p->buf[0]) != RoQ_MAGIC_NUMBER) ||
65
        (AV_RL32(&p->buf[2]) != 0xFFFFFFFF))
66 3ef8be2b Mike Melanson
        return 0;
67
68
    return AVPROBE_SCORE_MAX;
69
}
70
71
static int roq_read_header(AVFormatContext *s,
72
                           AVFormatParameters *ap)
73
{
74
    RoqDemuxContext *roq = s->priv_data;
75
    ByteIOContext *pb = &s->pb;
76
    AVStream *st;
77
    unsigned char preamble[RoQ_CHUNK_PREAMBLE_SIZE];
78
    int i;
79
    unsigned int chunk_size;
80
    unsigned int chunk_type;
81
82
    /* get the main header */
83 115329f1 Diego Biurrun
    if (get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) !=
84 3ef8be2b Mike Melanson
        RoQ_CHUNK_PREAMBLE_SIZE)
85
        return AVERROR_IO;
86 fead30d4 Alex Beregszaszi
    roq->framerate = AV_RL16(&preamble[6]);
87 3ef8be2b Mike Melanson
    roq->frame_pts_inc = 90000 / roq->framerate;
88
89
    /* init private context parameters */
90 115329f1 Diego Biurrun
    roq->width = roq->height = roq->audio_channels = roq->video_pts =
91 3ef8be2b Mike Melanson
    roq->audio_frame_count = 0;
92
93
    /* scan the first n chunks searching for A/V parameters */
94
    for (i = 0; i < RoQ_CHUNKS_TO_SCAN; i++) {
95 115329f1 Diego Biurrun
        if (get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) !=
96 3ef8be2b Mike Melanson
            RoQ_CHUNK_PREAMBLE_SIZE)
97
            return AVERROR_IO;
98
99 fead30d4 Alex Beregszaszi
        chunk_type = AV_RL16(&preamble[0]);
100
        chunk_size = AV_RL32(&preamble[2]);
101 3ef8be2b Mike Melanson
102
        switch (chunk_type) {
103
104
        case RoQ_INFO:
105
            /* fetch the width and height; reuse the preamble bytes */
106 115329f1 Diego Biurrun
            if (get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) !=
107 3ef8be2b Mike Melanson
                RoQ_CHUNK_PREAMBLE_SIZE)
108
                return AVERROR_IO;
109 fead30d4 Alex Beregszaszi
            roq->width = AV_RL16(&preamble[0]);
110
            roq->height = AV_RL16(&preamble[2]);
111 3ef8be2b Mike Melanson
            break;
112
113
        case RoQ_QUAD_CODEBOOK:
114
        case RoQ_QUAD_VQ:
115
            /* ignore during this scan */
116
            url_fseek(pb, chunk_size, SEEK_CUR);
117
            break;
118
119
        case RoQ_SOUND_MONO:
120
            roq->audio_channels = 1;
121
            url_fseek(pb, chunk_size, SEEK_CUR);
122
            break;
123
124
        case RoQ_SOUND_STEREO:
125
            roq->audio_channels = 2;
126
            url_fseek(pb, chunk_size, SEEK_CUR);
127
            break;
128
129
        default:
130 fead30d4 Alex Beregszaszi
            av_log(s, AV_LOG_ERROR, " unknown RoQ chunk type (%04X)\n", AV_RL16(&preamble[0]));
131 3ef8be2b Mike Melanson
            return AVERROR_INVALIDDATA;
132
            break;
133
        }
134
135
        /* if all necessary parameters have been gathered, exit early */
136
        if ((roq->width && roq->height) && roq->audio_channels)
137
            break;
138
    }
139
140
    /* seek back to the first chunk */
141
    url_fseek(pb, RoQ_CHUNK_PREAMBLE_SIZE, SEEK_SET);
142
143
    /* initialize the decoders */
144
    st = av_new_stream(s, 0);
145
    if (!st)
146
        return AVERROR_NOMEM;
147 9ee91c2f Michael Niedermayer
    /* set the pts reference (1 pts = 1/90000) */
148
    av_set_pts_info(st, 33, 1, 90000);
149 3ef8be2b Mike Melanson
    roq->video_stream_index = st->index;
150 01f4895c Michael Niedermayer
    st->codec->codec_type = CODEC_TYPE_VIDEO;
151
    st->codec->codec_id = CODEC_ID_ROQ;
152
    st->codec->codec_tag = 0;  /* no fourcc */
153
    st->codec->width = roq->width;
154
    st->codec->height = roq->height;
155 3ef8be2b Mike Melanson
156
    if (roq->audio_channels) {
157
        st = av_new_stream(s, 0);
158
        if (!st)
159
            return AVERROR_NOMEM;
160 9ee91c2f Michael Niedermayer
        av_set_pts_info(st, 33, 1, 90000);
161 3ef8be2b Mike Melanson
        roq->audio_stream_index = st->index;
162 01f4895c Michael Niedermayer
        st->codec->codec_type = CODEC_TYPE_AUDIO;
163
        st->codec->codec_id = CODEC_ID_ROQ_DPCM;
164
        st->codec->codec_tag = 0;  /* no tag */
165
        st->codec->channels = roq->audio_channels;
166
        st->codec->sample_rate = RoQ_AUDIO_SAMPLE_RATE;
167
        st->codec->bits_per_sample = 16;
168
        st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
169
            st->codec->bits_per_sample;
170
        st->codec->block_align = st->codec->channels * st->codec->bits_per_sample;
171 3ef8be2b Mike Melanson
    }
172
173
    return 0;
174
}
175
176
static int roq_read_packet(AVFormatContext *s,
177
                           AVPacket *pkt)
178
{
179
    RoqDemuxContext *roq = s->priv_data;
180
    ByteIOContext *pb = &s->pb;
181
    int ret = 0;
182
    unsigned int chunk_size;
183
    unsigned int chunk_type;
184
    unsigned int codebook_size;
185
    unsigned char preamble[RoQ_CHUNK_PREAMBLE_SIZE];
186
    int packet_read = 0;
187
    offset_t codebook_offset;
188
189
    while (!packet_read) {
190
191
        if (url_feof(&s->pb))
192 0bd586c5 Mike Melanson
            return AVERROR_IO;
193 3ef8be2b Mike Melanson
194
        /* get the next chunk preamble */
195 115329f1 Diego Biurrun
        if ((ret = get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE)) !=
196 3ef8be2b Mike Melanson
            RoQ_CHUNK_PREAMBLE_SIZE)
197 0bd586c5 Mike Melanson
            return AVERROR_IO;
198 3ef8be2b Mike Melanson
199 fead30d4 Alex Beregszaszi
        chunk_type = AV_RL16(&preamble[0]);
200
        chunk_size = AV_RL32(&preamble[2]);
201 0ecca7a4 Michael Niedermayer
        if(chunk_size > INT_MAX)
202
            return AVERROR_INVALIDDATA;
203 3ef8be2b Mike Melanson
204
        switch (chunk_type) {
205
206
        case RoQ_INFO:
207
            /* don't care about this chunk anymore */
208
            url_fseek(pb, RoQ_CHUNK_PREAMBLE_SIZE, SEEK_CUR);
209
            break;
210
211
        case RoQ_QUAD_CODEBOOK:
212
            /* packet needs to contain both this codebook and next VQ chunk */
213
            codebook_offset = url_ftell(pb) - RoQ_CHUNK_PREAMBLE_SIZE;
214
            codebook_size = chunk_size;
215
            url_fseek(pb, codebook_size, SEEK_CUR);
216 115329f1 Diego Biurrun
            if (get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) !=
217 3ef8be2b Mike Melanson
                RoQ_CHUNK_PREAMBLE_SIZE)
218 0bd586c5 Mike Melanson
                return AVERROR_IO;
219 fead30d4 Alex Beregszaszi
            chunk_size = AV_RL32(&preamble[2]) + RoQ_CHUNK_PREAMBLE_SIZE * 2 +
220 3ef8be2b Mike Melanson
                codebook_size;
221
222
            /* rewind */
223
            url_fseek(pb, codebook_offset, SEEK_SET);
224
225
            /* load up the packet */
226 2692067a Michael Niedermayer
            ret= av_get_packet(pb, pkt, chunk_size);
227
            if (ret != chunk_size)
228 0bd586c5 Mike Melanson
                return AVERROR_IO;
229 3ef8be2b Mike Melanson
            pkt->stream_index = roq->video_stream_index;
230
            pkt->pts = roq->video_pts;
231
232
            roq->video_pts += roq->frame_pts_inc;
233
            packet_read = 1;
234
            break;
235
236
        case RoQ_SOUND_MONO:
237
        case RoQ_SOUND_STEREO:
238
        case RoQ_QUAD_VQ:
239
            /* load up the packet */
240
            if (av_new_packet(pkt, chunk_size + RoQ_CHUNK_PREAMBLE_SIZE))
241 0bd586c5 Mike Melanson
                return AVERROR_IO;
242 3ef8be2b Mike Melanson
            /* copy over preamble */
243
            memcpy(pkt->data, preamble, RoQ_CHUNK_PREAMBLE_SIZE);
244
245
            if (chunk_type == RoQ_QUAD_VQ) {
246
                pkt->stream_index = roq->video_stream_index;
247
                pkt->pts = roq->video_pts;
248
                roq->video_pts += roq->frame_pts_inc;
249
            } else {
250
                pkt->stream_index = roq->audio_stream_index;
251
                pkt->pts = roq->audio_frame_count;
252
                pkt->pts *= 90000;
253
                pkt->pts /= RoQ_AUDIO_SAMPLE_RATE;
254
                roq->audio_frame_count += (chunk_size / roq->audio_channels);
255
            }
256
257 2692067a Michael Niedermayer
            pkt->pos= url_ftell(pb);
258 d42f74b8 Mike Melanson
            ret = get_buffer(pb, pkt->data + RoQ_CHUNK_PREAMBLE_SIZE,
259
                chunk_size);
260 3ef8be2b Mike Melanson
            if (ret != chunk_size)
261 0bd586c5 Mike Melanson
                ret = AVERROR_IO;
262 3ef8be2b Mike Melanson
263
            packet_read = 1;
264
            break;
265
266
        default:
267 bc874dae Michel Bardiaux
            av_log(s, AV_LOG_ERROR, "  unknown RoQ chunk (%04X)\n", chunk_type);
268 3ef8be2b Mike Melanson
            return AVERROR_INVALIDDATA;
269
            break;
270
        }
271
    }
272
273
    return ret;
274
}
275
276
static int roq_read_close(AVFormatContext *s)
277
{
278
//    RoqDemuxContext *roq = (RoqDemuxContext *)s->priv_data;
279
280
    return 0;
281
}
282
283 ff70e601 Måns Rullgård
AVInputFormat roq_demuxer = {
284 3ef8be2b Mike Melanson
    "RoQ",
285
    "Id RoQ format",
286
    sizeof(RoqDemuxContext),
287
    roq_probe,
288
    roq_read_header,
289
    roq_read_packet,
290
    roq_read_close,
291
};