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