Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/*
2
 * id RoQ (.roq) File Demuxer
3
 * Copyright (c) 2003 The ffmpeg Project
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg 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
 * FFmpeg 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 FFmpeg; 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
 * 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 "libavutil/channel_layout.h"
31
#include "libavutil/intreadwrite.h"
32
#include "avformat.h"
33
#include "internal.h"
34
#include "avio_internal.h"
35
 
36
#define RoQ_MAGIC_NUMBER 0x1084
37
#define RoQ_CHUNK_PREAMBLE_SIZE 8
38
#define RoQ_AUDIO_SAMPLE_RATE 22050
39
#define RoQ_CHUNKS_TO_SCAN 30
40
 
41
#define RoQ_INFO           0x1001
42
#define RoQ_QUAD_CODEBOOK  0x1002
43
#define RoQ_QUAD_VQ        0x1011
44
#define RoQ_SOUND_MONO     0x1020
45
#define RoQ_SOUND_STEREO   0x1021
46
 
47
typedef struct RoqDemuxContext {
48
 
49
    int frame_rate;
50
    int width;
51
    int height;
52
    int audio_channels;
53
 
54
    int video_stream_index;
55
    int audio_stream_index;
56
 
57
    int64_t video_pts;
58
    unsigned int audio_frame_count;
59
 
60
} RoqDemuxContext;
61
 
62
static int roq_probe(AVProbeData *p)
63
{
64
    if ((AV_RL16(&p->buf[0]) != RoQ_MAGIC_NUMBER) ||
65
        (AV_RL32(&p->buf[2]) != 0xFFFFFFFF))
66
        return 0;
67
 
68
    return AVPROBE_SCORE_MAX;
69
}
70
 
71
static int roq_read_header(AVFormatContext *s)
72
{
73
    RoqDemuxContext *roq = s->priv_data;
74
    AVIOContext *pb = s->pb;
75
    unsigned char preamble[RoQ_CHUNK_PREAMBLE_SIZE];
76
 
77
    /* get the main header */
78
    if (avio_read(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) !=
79
        RoQ_CHUNK_PREAMBLE_SIZE)
80
        return AVERROR(EIO);
81
    roq->frame_rate = AV_RL16(&preamble[6]);
82
 
83
    /* init private context parameters */
84
    roq->width = roq->height = roq->audio_channels = roq->video_pts =
85
    roq->audio_frame_count = 0;
86
    roq->audio_stream_index = -1;
87
    roq->video_stream_index = -1;
88
 
89
    s->ctx_flags |= AVFMTCTX_NOHEADER;
90
 
91
    return 0;
92
}
93
 
94
static int roq_read_packet(AVFormatContext *s,
95
                           AVPacket *pkt)
96
{
97
    RoqDemuxContext *roq = s->priv_data;
98
    AVIOContext *pb = s->pb;
99
    int ret = 0;
100
    unsigned int chunk_size;
101
    unsigned int chunk_type;
102
    unsigned int codebook_size;
103
    unsigned char preamble[RoQ_CHUNK_PREAMBLE_SIZE];
104
    int packet_read = 0;
105
    int64_t codebook_offset;
106
 
107
    while (!packet_read) {
108
 
109
        if (url_feof(s->pb))
110
            return AVERROR(EIO);
111
 
112
        /* get the next chunk preamble */
113
        if ((ret = avio_read(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE)) !=
114
            RoQ_CHUNK_PREAMBLE_SIZE)
115
            return AVERROR(EIO);
116
 
117
        chunk_type = AV_RL16(&preamble[0]);
118
        chunk_size = AV_RL32(&preamble[2]);
119
        if(chunk_size > INT_MAX)
120
            return AVERROR_INVALIDDATA;
121
 
122
        chunk_size = ffio_limit(pb, chunk_size);
123
 
124
        switch (chunk_type) {
125
 
126
        case RoQ_INFO:
127
            if (roq->video_stream_index == -1) {
128
                AVStream *st = avformat_new_stream(s, NULL);
129
                if (!st)
130
                    return AVERROR(ENOMEM);
131
                avpriv_set_pts_info(st, 63, 1, roq->frame_rate);
132
                roq->video_stream_index = st->index;
133
                st->codec->codec_type   = AVMEDIA_TYPE_VIDEO;
134
                st->codec->codec_id     = AV_CODEC_ID_ROQ;
135
                st->codec->codec_tag    = 0;  /* no fourcc */
136
 
137
                if (avio_read(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != RoQ_CHUNK_PREAMBLE_SIZE)
138
                    return AVERROR(EIO);
139
                st->codec->width  = roq->width  = AV_RL16(preamble);
140
                st->codec->height = roq->height = AV_RL16(preamble + 2);
141
                break;
142
            }
143
            /* don't care about this chunk anymore */
144
            avio_skip(pb, RoQ_CHUNK_PREAMBLE_SIZE);
145
            break;
146
 
147
        case RoQ_QUAD_CODEBOOK:
148
            if (roq->video_stream_index < 0)
149
                return AVERROR_INVALIDDATA;
150
            /* packet needs to contain both this codebook and next VQ chunk */
151
            codebook_offset = avio_tell(pb) - RoQ_CHUNK_PREAMBLE_SIZE;
152
            codebook_size = chunk_size;
153
            avio_skip(pb, codebook_size);
154
            if (avio_read(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) !=
155
                RoQ_CHUNK_PREAMBLE_SIZE)
156
                return AVERROR(EIO);
157
            chunk_size = AV_RL32(&preamble[2]) + RoQ_CHUNK_PREAMBLE_SIZE * 2 +
158
                codebook_size;
159
 
160
            /* rewind */
161
            avio_seek(pb, codebook_offset, SEEK_SET);
162
 
163
            /* load up the packet */
164
            ret= av_get_packet(pb, pkt, chunk_size);
165
            if (ret != chunk_size)
166
                return AVERROR(EIO);
167
            pkt->stream_index = roq->video_stream_index;
168
            pkt->pts = roq->video_pts++;
169
 
170
            packet_read = 1;
171
            break;
172
 
173
        case RoQ_SOUND_MONO:
174
        case RoQ_SOUND_STEREO:
175
            if (roq->audio_stream_index == -1) {
176
                AVStream *st = avformat_new_stream(s, NULL);
177
                if (!st)
178
                    return AVERROR(ENOMEM);
179
                avpriv_set_pts_info(st, 32, 1, RoQ_AUDIO_SAMPLE_RATE);
180
                roq->audio_stream_index = st->index;
181
                st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
182
                st->codec->codec_id = AV_CODEC_ID_ROQ_DPCM;
183
                st->codec->codec_tag = 0;  /* no tag */
184
                if (chunk_type == RoQ_SOUND_STEREO) {
185
                    st->codec->channels       = 2;
186
                    st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
187
                } else {
188
                    st->codec->channels       = 1;
189
                    st->codec->channel_layout = AV_CH_LAYOUT_MONO;
190
                }
191
                roq->audio_channels    = st->codec->channels;
192
                st->codec->sample_rate = RoQ_AUDIO_SAMPLE_RATE;
193
                st->codec->bits_per_coded_sample = 16;
194
                st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
195
                    st->codec->bits_per_coded_sample;
196
                st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample;
197
            }
198
        case RoQ_QUAD_VQ:
199
            if (chunk_type == RoQ_QUAD_VQ) {
200
                if (roq->video_stream_index < 0)
201
                    return AVERROR_INVALIDDATA;
202
            }
203
 
204
            /* load up the packet */
205
            if (av_new_packet(pkt, chunk_size + RoQ_CHUNK_PREAMBLE_SIZE))
206
                return AVERROR(EIO);
207
            /* copy over preamble */
208
            memcpy(pkt->data, preamble, RoQ_CHUNK_PREAMBLE_SIZE);
209
 
210
            if (chunk_type == RoQ_QUAD_VQ) {
211
                pkt->stream_index = roq->video_stream_index;
212
                pkt->pts = roq->video_pts++;
213
            } else {
214
                pkt->stream_index = roq->audio_stream_index;
215
                pkt->pts = roq->audio_frame_count;
216
                roq->audio_frame_count += (chunk_size / roq->audio_channels);
217
            }
218
 
219
            pkt->pos= avio_tell(pb);
220
            ret = avio_read(pb, pkt->data + RoQ_CHUNK_PREAMBLE_SIZE,
221
                chunk_size);
222
            if (ret != chunk_size)
223
                ret = AVERROR(EIO);
224
 
225
            packet_read = 1;
226
            break;
227
 
228
        default:
229
            av_log(s, AV_LOG_ERROR, "  unknown RoQ chunk (%04X)\n", chunk_type);
230
            return AVERROR_INVALIDDATA;
231
        }
232
    }
233
 
234
    return ret;
235
}
236
 
237
AVInputFormat ff_roq_demuxer = {
238
    .name           = "roq",
239
    .long_name      = NULL_IF_CONFIG_SMALL("id RoQ"),
240
    .priv_data_size = sizeof(RoqDemuxContext),
241
    .read_probe     = roq_probe,
242
    .read_header    = roq_read_header,
243
    .read_packet    = roq_read_packet,
244
};