Mercurial > libavformat.hg
annotate idcin.c @ 1960:c0289552590f libavformat
Change the vhook code to send real timestamps to the filters instead of the
current time of day, which is useless, and which the filters could just as
easily query for themselves.
patch by Bobby Bingham, uhmmmm gmail com
author | diego |
---|---|
date | Thu, 29 Mar 2007 05:24:35 +0000 |
parents | a782462e2497 |
children | 1a3c9056982a |
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 /* cannot proceed without 20 bytes */ | |
108 if (p->buf_size < 20) | |
109 return 0; | |
110 | |
111 /* check the video width */ | |
1673 | 112 number = AV_RL32(&p->buf[0]); |
274 | 113 if ((number == 0) || (number > 1024)) |
114 return 0; | |
115 | |
116 /* check the video height */ | |
1673 | 117 number = AV_RL32(&p->buf[4]); |
274 | 118 if ((number == 0) || (number > 1024)) |
119 return 0; | |
120 | |
121 /* check the audio sample rate */ | |
1673 | 122 number = AV_RL32(&p->buf[8]); |
274 | 123 if ((number != 0) && ((number < 8000) | (number > 48000))) |
124 return 0; | |
125 | |
126 /* check the audio bytes/sample */ | |
1673 | 127 number = AV_RL32(&p->buf[12]); |
274 | 128 if (number > 2) |
129 return 0; | |
130 | |
131 /* check the audio channels */ | |
1673 | 132 number = AV_RL32(&p->buf[16]); |
274 | 133 if (number > 2) |
134 return 0; | |
135 | |
136 /* return half certainly since this check is a bit sketchy */ | |
137 return AVPROBE_SCORE_MAX / 2; | |
138 } | |
139 | |
140 static int idcin_read_header(AVFormatContext *s, | |
141 AVFormatParameters *ap) | |
142 { | |
143 ByteIOContext *pb = &s->pb; | |
144 IdcinDemuxContext *idcin = (IdcinDemuxContext *)s->priv_data; | |
145 AVStream *st; | |
146 unsigned int width, height; | |
147 unsigned int sample_rate, bytes_per_sample, channels; | |
148 | |
149 /* get the 5 header parameters */ | |
150 width = get_le32(pb); | |
151 height = get_le32(pb); | |
152 sample_rate = get_le32(pb); | |
153 bytes_per_sample = get_le32(pb); | |
154 channels = get_le32(pb); | |
155 | |
156 st = av_new_stream(s, 0); | |
157 if (!st) | |
158 return AVERROR_NOMEM; | |
462
b69898ffc92a
move time_base (pts_num/pts_den) from AVFormatContext -> AVStream
michael
parents:
386
diff
changeset
|
159 av_set_pts_info(st, 33, 1, 90000); |
274 | 160 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
|
161 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
|
162 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
|
163 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
|
164 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
|
165 st->codec->height = height; |
274 | 166 |
167 /* 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
|
168 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
|
169 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
|
170 if (get_buffer(pb, st->codec->extradata, HUFFMAN_TABLE_SIZE) != |
274 | 171 HUFFMAN_TABLE_SIZE) |
482 | 172 return AVERROR_IO; |
274 | 173 /* 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
|
174 st->codec->palctrl = &idcin->palctrl; |
274 | 175 |
176 /* if sample rate is 0, assume no audio */ | |
177 if (sample_rate) { | |
178 idcin->audio_present = 1; | |
179 st = av_new_stream(s, 0); | |
180 if (!st) | |
181 return AVERROR_NOMEM; | |
462
b69898ffc92a
move time_base (pts_num/pts_den) from AVFormatContext -> AVStream
michael
parents:
386
diff
changeset
|
182 av_set_pts_info(st, 33, 1, 90000); |
274 | 183 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
|
184 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
|
185 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
|
186 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
|
187 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
|
188 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
|
189 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
|
190 st->codec->block_align = bytes_per_sample * channels; |
274 | 191 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
|
192 st->codec->codec_id = CODEC_ID_PCM_U8; |
274 | 193 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
|
194 st->codec->codec_id = CODEC_ID_PCM_S16LE; |
274 | 195 |
196 if (sample_rate % 14 != 0) { | |
197 idcin->audio_chunk_size1 = (sample_rate / 14) * | |
198 bytes_per_sample * channels; | |
199 idcin->audio_chunk_size2 = (sample_rate / 14 + 1) * | |
200 bytes_per_sample * channels; | |
201 } else { | |
202 idcin->audio_chunk_size1 = idcin->audio_chunk_size2 = | |
203 (sample_rate / 14) * bytes_per_sample * channels; | |
204 } | |
205 idcin->current_audio_chunk = 0; | |
206 } else | |
207 idcin->audio_present = 1; | |
208 | |
209 idcin->next_chunk_is_video = 1; | |
210 idcin->pts = 0; | |
211 | |
212 return 0; | |
213 } | |
214 | |
215 static int idcin_read_packet(AVFormatContext *s, | |
216 AVPacket *pkt) | |
217 { | |
218 int ret; | |
219 unsigned int command; | |
220 unsigned int chunk_size; | |
221 IdcinDemuxContext *idcin = (IdcinDemuxContext *)s->priv_data; | |
222 ByteIOContext *pb = &s->pb; | |
223 int i; | |
224 int palette_scale; | |
295
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
225 unsigned char r, g, b; |
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
226 unsigned char palette_buffer[768]; |
274 | 227 |
228 if (url_feof(&s->pb)) | |
482 | 229 return AVERROR_IO; |
274 | 230 |
231 if (idcin->next_chunk_is_video) { | |
232 command = get_le32(pb); | |
233 if (command == 2) { | |
482 | 234 return AVERROR_IO; |
274 | 235 } else if (command == 1) { |
236 /* trigger a palette change */ | |
295
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
237 idcin->palctrl.palette_changed = 1; |
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
238 if (get_buffer(pb, palette_buffer, 768) != 768) |
482 | 239 return AVERROR_IO; |
274 | 240 /* scale the palette as necessary */ |
241 palette_scale = 2; | |
242 for (i = 0; i < 768; i++) | |
295
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
243 if (palette_buffer[i] > 63) { |
274 | 244 palette_scale = 0; |
245 break; | |
246 } | |
247 | |
295
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
248 for (i = 0; i < 256; i++) { |
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
249 r = palette_buffer[i * 3 ] << palette_scale; |
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
250 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
|
251 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
|
252 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
|
253 } |
274 | 254 } |
255 | |
256 chunk_size = get_le32(pb); | |
257 /* skip the number of decoded bytes (always equal to width * height) */ | |
258 url_fseek(pb, 4, SEEK_CUR); | |
259 chunk_size -= 4; | |
885 | 260 ret= av_get_packet(pb, pkt, chunk_size); |
775 | 261 if (ret != chunk_size) |
262 return AVERROR_IO; | |
274 | 263 pkt->stream_index = idcin->video_stream_index; |
264 pkt->pts = idcin->pts; | |
265 } else { | |
266 /* send out the audio chunk */ | |
267 if (idcin->current_audio_chunk) | |
268 chunk_size = idcin->audio_chunk_size2; | |
269 else | |
270 chunk_size = idcin->audio_chunk_size1; | |
775 | 271 ret= av_get_packet(pb, pkt, chunk_size); |
272 if (ret != chunk_size) | |
482 | 273 return AVERROR_IO; |
274 | 274 pkt->stream_index = idcin->audio_stream_index; |
275 pkt->pts = idcin->pts; | |
276 | |
277 idcin->current_audio_chunk ^= 1; | |
278 idcin->pts += FRAME_PTS_INC; | |
279 } | |
280 | |
281 if (idcin->audio_present) | |
282 idcin->next_chunk_is_video ^= 1; | |
283 | |
284 return ret; | |
285 } | |
286 | |
287 static int idcin_read_close(AVFormatContext *s) | |
288 { | |
295
bff1a372ae38
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
274
diff
changeset
|
289 |
274 | 290 return 0; |
291 } | |
292 | |
1169 | 293 AVInputFormat idcin_demuxer = { |
274 | 294 "idcin", |
295 "Id CIN format", | |
296 sizeof(IdcinDemuxContext), | |
297 idcin_probe, | |
298 idcin_read_header, | |
299 idcin_read_packet, | |
300 idcin_read_close, | |
301 }; |