Mercurial > libavformat.hg
annotate idcin.c @ 2400:fcaecfb05781 libavformat
When looking for the last packet in each
stream, so as to calculate the duration, don't stop
as soon as all streams have seen at least one packet.
Otherwise the duration will be shorter than it
should be. We must keep reading to the end-of-file.
patch by neilb suse de
author | michael |
---|---|
date | Sat, 18 Aug 2007 00:52:05 +0000 |
parents | b21c2af60bc9 |
children | d52c718e83f9 |
rev | line source |
---|---|
274 | 1 /* |
2 * Id Quake II CIN File Demuxer | |
3 * Copyright (c) 2003 The ffmpeg Project | |
4 * | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1169
diff
changeset
|
5 * This file is part of FFmpeg. |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1169
diff
changeset
|
6 * |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1169
diff
changeset
|
7 * FFmpeg is free software; you can redistribute it and/or |
274 | 8 * modify it under the terms of the GNU Lesser General Public |
9 * License as published by the Free Software Foundation; either | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1169
diff
changeset
|
10 * version 2.1 of the License, or (at your option) any later version. |
274 | 11 * |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1169
diff
changeset
|
12 * FFmpeg is distributed in the hope that it will be useful, |
274 | 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 | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1169
diff
changeset
|
18 * License along with FFmpeg; if not, write to the Free Software |
896
edbe5c3717f9
Update licensing information: The FSF changed postal address.
diego
parents:
885
diff
changeset
|
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
274 | 20 */ |
21 | |
22 /** | |
23 * @file idcin.c | |
24 * Id Quake II CIN file demuxer by Mike Melanson (melanson@pcisys.net) | |
25 * For more information about the Id CIN format, visit: | |
26 * http://www.csse.monash.edu.au/~timf/ | |
27 * | |
28 * CIN is a somewhat quirky and ill-defined format. Here are some notes | |
29 * for anyone trying to understand the technical details of this format: | |
30 * | |
31 * The format has no definite file signature. This is problematic for a | |
32 * general-purpose media player that wants to automatically detect file | |
33 * types. However, a CIN file does start with 5 32-bit numbers that | |
34 * specify audio and video parameters. This demuxer gets around the lack | |
35 * of file signature by performing sanity checks on those parameters. | |
36 * Probabalistically, this is a reasonable solution since the number of | |
37 * valid combinations of the 5 parameters is a very small subset of the | |
38 * total 160-bit number space. | |
39 * | |
40 * Refer to the function idcin_probe() for the precise A/V parameters | |
41 * that this demuxer allows. | |
42 * | |
43 * Next, each audio and video frame has a duration of 1/14 sec. If the | |
44 * audio sample rate is a multiple of the common frequency 22050 Hz it will | |
45 * divide evenly by 14. However, if the sample rate is 11025 Hz: | |
46 * 11025 (samples/sec) / 14 (frames/sec) = 787.5 (samples/frame) | |
47 * The way the CIN stores audio in this case is by storing 787 sample | |
48 * frames in the first audio frame and 788 sample frames in the second | |
49 * audio frame. Therefore, the total number of bytes in an audio frame | |
50 * is given as: | |
51 * audio frame #0: 787 * (bytes/sample) * (# channels) bytes in frame | |
52 * audio frame #1: 788 * (bytes/sample) * (# channels) bytes in frame | |
53 * audio frame #2: 787 * (bytes/sample) * (# channels) bytes in frame | |
54 * audio frame #3: 788 * (bytes/sample) * (# channels) bytes in frame | |
55 * | |
56 * Finally, not all Id CIN creation tools agree on the resolution of the | |
57 * color palette, apparently. Some creation tools specify red, green, and | |
58 * blue palette components in terms of 6-bit VGA color DAC values which | |
59 * range from 0..63. Other tools specify the RGB components as full 8-bit | |
60 * values that range from 0..255. Since there are no markers in the file to | |
61 * differentiate between the two variants, this demuxer uses the following | |
62 * heuristic: | |
63 * - load the 768 palette bytes from disk | |
64 * - assume that they will need to be shifted left by 2 bits to | |
65 * transform them from 6-bit values to 8-bit values | |
66 * - scan through all 768 palette bytes | |
67 * - if any bytes exceed 63, do not shift the bytes at all before | |
68 * transmitting them to the video decoder | |
69 */ | |
70 | |
71 #include "avformat.h" | |
72 | |
73 #define HUFFMAN_TABLE_SIZE (64 * 1024) | |
74 #define FRAME_PTS_INC (90000 / 14) | |
75 | |
76 typedef struct IdcinDemuxContext { | |
77 int video_stream_index; | |
78 int audio_stream_index; | |
79 int audio_chunk_size1; | |
80 int audio_chunk_size2; | |
81 | |
82 /* demux state variables */ | |
83 int current_audio_chunk; | |
84 int next_chunk_is_video; | |
85 int audio_present; | |
86 | |
87 int64_t pts; | |
88 | |
295
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
89 AVPaletteControl palctrl; |
274 | 90 } IdcinDemuxContext; |
91 | |
92 static int idcin_probe(AVProbeData *p) | |
93 { | |
94 unsigned int number; | |
95 | |
96 /* | |
97 * This is what you could call a "probabilistic" file check: Id CIN | |
98 * files don't have a definite file signature. In lieu of such a marker, | |
99 * perform sanity checks on the 5 32-bit header fields: | |
100 * width, height: greater than 0, less than or equal to 1024 | |
101 * audio sample rate: greater than or equal to 8000, less than or | |
102 * equal to 48000, or 0 for no audio | |
103 * audio sample width (bytes/sample): 0 for no audio, or 1 or 2 | |
104 * audio channels: 0 for no audio, or 1 or 2 | |
105 */ | |
106 | |
107 /* check the video width */ | |
1673 | 108 number = AV_RL32(&p->buf[0]); |
274 | 109 if ((number == 0) || (number > 1024)) |
110 return 0; | |
111 | |
112 /* check the video height */ | |
1673 | 113 number = AV_RL32(&p->buf[4]); |
274 | 114 if ((number == 0) || (number > 1024)) |
115 return 0; | |
116 | |
117 /* check the audio sample rate */ | |
1673 | 118 number = AV_RL32(&p->buf[8]); |
274 | 119 if ((number != 0) && ((number < 8000) | (number > 48000))) |
120 return 0; | |
121 | |
122 /* check the audio bytes/sample */ | |
1673 | 123 number = AV_RL32(&p->buf[12]); |
274 | 124 if (number > 2) |
125 return 0; | |
126 | |
127 /* check the audio channels */ | |
1673 | 128 number = AV_RL32(&p->buf[16]); |
274 | 129 if (number > 2) |
130 return 0; | |
131 | |
132 /* return half certainly since this check is a bit sketchy */ | |
133 return AVPROBE_SCORE_MAX / 2; | |
134 } | |
135 | |
136 static int idcin_read_header(AVFormatContext *s, | |
137 AVFormatParameters *ap) | |
138 { | |
139 ByteIOContext *pb = &s->pb; | |
2006 | 140 IdcinDemuxContext *idcin = s->priv_data; |
274 | 141 AVStream *st; |
142 unsigned int width, height; | |
143 unsigned int sample_rate, bytes_per_sample, channels; | |
144 | |
145 /* get the 5 header parameters */ | |
146 width = get_le32(pb); | |
147 height = get_le32(pb); | |
148 sample_rate = get_le32(pb); | |
149 bytes_per_sample = get_le32(pb); | |
150 channels = get_le32(pb); | |
151 | |
152 st = av_new_stream(s, 0); | |
153 if (!st) | |
2273
7eb456c4ed8a
Replace all occurrences of AVERROR_NOMEM with AVERROR(ENOMEM).
takis
parents:
2006
diff
changeset
|
154 return AVERROR(ENOMEM); |
462
b69898ffc92a
move time_base (pts_num/pts_den) from AVFormatContext -> AVStream
michael
parents:
386
diff
changeset
|
155 av_set_pts_info(st, 33, 1, 90000); |
274 | 156 idcin->video_stream_index = st->index; |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
157 st->codec->codec_type = CODEC_TYPE_VIDEO; |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
158 st->codec->codec_id = CODEC_ID_IDCIN; |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
159 st->codec->codec_tag = 0; /* no fourcc */ |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
160 st->codec->width = width; |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
161 st->codec->height = height; |
274 | 162 |
163 /* load up the Huffman tables into extradata */ | |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
164 st->codec->extradata_size = HUFFMAN_TABLE_SIZE; |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
165 st->codec->extradata = av_malloc(HUFFMAN_TABLE_SIZE); |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
166 if (get_buffer(pb, st->codec->extradata, HUFFMAN_TABLE_SIZE) != |
274 | 167 HUFFMAN_TABLE_SIZE) |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2273
diff
changeset
|
168 return AVERROR(EIO); |
274 | 169 /* save a reference in order to transport the palette */ |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
170 st->codec->palctrl = &idcin->palctrl; |
274 | 171 |
172 /* if sample rate is 0, assume no audio */ | |
173 if (sample_rate) { | |
174 idcin->audio_present = 1; | |
175 st = av_new_stream(s, 0); | |
176 if (!st) | |
2273
7eb456c4ed8a
Replace all occurrences of AVERROR_NOMEM with AVERROR(ENOMEM).
takis
parents:
2006
diff
changeset
|
177 return AVERROR(ENOMEM); |
462
b69898ffc92a
move time_base (pts_num/pts_den) from AVFormatContext -> AVStream
michael
parents:
386
diff
changeset
|
178 av_set_pts_info(st, 33, 1, 90000); |
274 | 179 idcin->audio_stream_index = st->index; |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
180 st->codec->codec_type = CODEC_TYPE_AUDIO; |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
181 st->codec->codec_tag = 1; |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
182 st->codec->channels = channels; |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
183 st->codec->sample_rate = sample_rate; |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
184 st->codec->bits_per_sample = bytes_per_sample * 8; |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
185 st->codec->bit_rate = sample_rate * bytes_per_sample * 8 * channels; |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
186 st->codec->block_align = bytes_per_sample * channels; |
274 | 187 if (bytes_per_sample == 1) |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
188 st->codec->codec_id = CODEC_ID_PCM_U8; |
274 | 189 else |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
190 st->codec->codec_id = CODEC_ID_PCM_S16LE; |
274 | 191 |
192 if (sample_rate % 14 != 0) { | |
193 idcin->audio_chunk_size1 = (sample_rate / 14) * | |
194 bytes_per_sample * channels; | |
195 idcin->audio_chunk_size2 = (sample_rate / 14 + 1) * | |
196 bytes_per_sample * channels; | |
197 } else { | |
198 idcin->audio_chunk_size1 = idcin->audio_chunk_size2 = | |
199 (sample_rate / 14) * bytes_per_sample * channels; | |
200 } | |
201 idcin->current_audio_chunk = 0; | |
202 } else | |
203 idcin->audio_present = 1; | |
204 | |
205 idcin->next_chunk_is_video = 1; | |
206 idcin->pts = 0; | |
207 | |
208 return 0; | |
209 } | |
210 | |
211 static int idcin_read_packet(AVFormatContext *s, | |
212 AVPacket *pkt) | |
213 { | |
214 int ret; | |
215 unsigned int command; | |
216 unsigned int chunk_size; | |
2006 | 217 IdcinDemuxContext *idcin = s->priv_data; |
274 | 218 ByteIOContext *pb = &s->pb; |
219 int i; | |
220 int palette_scale; | |
295
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
221 unsigned char r, g, b; |
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
222 unsigned char palette_buffer[768]; |
274 | 223 |
224 if (url_feof(&s->pb)) | |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2273
diff
changeset
|
225 return AVERROR(EIO); |
274 | 226 |
227 if (idcin->next_chunk_is_video) { | |
228 command = get_le32(pb); | |
229 if (command == 2) { | |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2273
diff
changeset
|
230 return AVERROR(EIO); |
274 | 231 } else if (command == 1) { |
232 /* trigger a palette change */ | |
295
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
233 idcin->palctrl.palette_changed = 1; |
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
234 if (get_buffer(pb, palette_buffer, 768) != 768) |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2273
diff
changeset
|
235 return AVERROR(EIO); |
274 | 236 /* scale the palette as necessary */ |
237 palette_scale = 2; | |
238 for (i = 0; i < 768; i++) | |
295
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
239 if (palette_buffer[i] > 63) { |
274 | 240 palette_scale = 0; |
241 break; | |
242 } | |
243 | |
295
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
244 for (i = 0; i < 256; i++) { |
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
245 r = palette_buffer[i * 3 ] << palette_scale; |
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
246 g = palette_buffer[i * 3 + 1] << palette_scale; |
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
247 b = palette_buffer[i * 3 + 2] << palette_scale; |
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
248 idcin->palctrl.palette[i] = (r << 16) | (g << 8) | (b); |
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
249 } |
274 | 250 } |
251 | |
252 chunk_size = get_le32(pb); | |
253 /* skip the number of decoded bytes (always equal to width * height) */ | |
254 url_fseek(pb, 4, SEEK_CUR); | |
255 chunk_size -= 4; | |
885 | 256 ret= av_get_packet(pb, pkt, chunk_size); |
775 | 257 if (ret != chunk_size) |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2273
diff
changeset
|
258 return AVERROR(EIO); |
274 | 259 pkt->stream_index = idcin->video_stream_index; |
260 pkt->pts = idcin->pts; | |
261 } else { | |
262 /* send out the audio chunk */ | |
263 if (idcin->current_audio_chunk) | |
264 chunk_size = idcin->audio_chunk_size2; | |
265 else | |
266 chunk_size = idcin->audio_chunk_size1; | |
775 | 267 ret= av_get_packet(pb, pkt, chunk_size); |
268 if (ret != chunk_size) | |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2273
diff
changeset
|
269 return AVERROR(EIO); |
274 | 270 pkt->stream_index = idcin->audio_stream_index; |
271 pkt->pts = idcin->pts; | |
272 | |
273 idcin->current_audio_chunk ^= 1; | |
274 idcin->pts += FRAME_PTS_INC; | |
275 } | |
276 | |
277 if (idcin->audio_present) | |
278 idcin->next_chunk_is_video ^= 1; | |
279 | |
280 return ret; | |
281 } | |
282 | |
283 static int idcin_read_close(AVFormatContext *s) | |
284 { | |
295
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
285 |
274 | 286 return 0; |
287 } | |
288 | |
1169 | 289 AVInputFormat idcin_demuxer = { |
274 | 290 "idcin", |
291 "Id CIN format", | |
292 sizeof(IdcinDemuxContext), | |
293 idcin_probe, | |
294 idcin_read_header, | |
295 idcin_read_packet, | |
296 idcin_read_close, | |
297 }; |