Mercurial > libavformat.hg
annotate 4xm.c @ 791:f961db8ea65d libavformat
This trivial patch adds "avc1" as fourcc for h264 in mp4, which makes it
a little bit more standard, although it still seems to lack some
metadata. Anyway, recent mplayer plays these streams without problems.
It also has two globally scoped global structs changed to "static".
patch by (Erik Slagter <erik slagter name)
author | michael |
---|---|
date | Sun, 19 Jun 2005 23:45:54 +0000 |
parents | c5077fdab490 |
children | feca73904e67 |
rev | line source |
---|---|
137 | 1 /* |
2 * 4X Technologies .4xm File Demuxer (no muxer) | |
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 4xm.c | |
22 * 4X Technologies file demuxer | |
23 * by Mike Melanson (melanson@pcisys.net) | |
24 * for more information on the .4xm file format, visit: | |
25 * http://www.pcisys.net/~melanson/codecs/ | |
26 */ | |
27 | |
28 #include "avformat.h" | |
29 | |
386
c152849ee643
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
317
diff
changeset
|
30 #define RIFF_TAG MKTAG('R', 'I', 'F', 'F') |
c152849ee643
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
317
diff
changeset
|
31 #define _4XMV_TAG MKTAG('4', 'X', 'M', 'V') |
c152849ee643
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
317
diff
changeset
|
32 #define LIST_TAG MKTAG('L', 'I', 'S', 'T') |
c152849ee643
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
317
diff
changeset
|
33 #define HEAD_TAG MKTAG('H', 'E', 'A', 'D') |
c152849ee643
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
317
diff
changeset
|
34 #define TRK__TAG MKTAG('T', 'R', 'K', '_') |
c152849ee643
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
317
diff
changeset
|
35 #define MOVI_TAG MKTAG('M', 'O', 'V', 'I') |
c152849ee643
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
317
diff
changeset
|
36 #define VTRK_TAG MKTAG('V', 'T', 'R', 'K') |
c152849ee643
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
317
diff
changeset
|
37 #define STRK_TAG MKTAG('S', 'T', 'R', 'K') |
c152849ee643
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
317
diff
changeset
|
38 #define std__TAG MKTAG('s', 't', 'd', '_') |
c152849ee643
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
317
diff
changeset
|
39 #define name_TAG MKTAG('n', 'a', 'm', 'e') |
c152849ee643
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
317
diff
changeset
|
40 #define vtrk_TAG MKTAG('v', 't', 'r', 'k') |
c152849ee643
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
317
diff
changeset
|
41 #define strk_TAG MKTAG('s', 't', 'r', 'k') |
c152849ee643
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
317
diff
changeset
|
42 #define ifrm_TAG MKTAG('i', 'f', 'r', 'm') |
c152849ee643
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
317
diff
changeset
|
43 #define pfrm_TAG MKTAG('p', 'f', 'r', 'm') |
c152849ee643
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
317
diff
changeset
|
44 #define cfrm_TAG MKTAG('c', 'f', 'r', 'm') |
c152849ee643
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
317
diff
changeset
|
45 #define snd__TAG MKTAG('s', 'n', 'd', '_') |
137 | 46 |
47 #define vtrk_SIZE 0x44 | |
48 #define strk_SIZE 0x28 | |
49 | |
50 #define GET_LIST_HEADER() \ | |
143 | 51 fourcc_tag = get_le32(pb); \ |
137 | 52 size = get_le32(pb); \ |
53 if (fourcc_tag != LIST_TAG) \ | |
54 return AVERROR_INVALIDDATA; \ | |
143 | 55 fourcc_tag = get_le32(pb); |
137 | 56 |
57 typedef struct AudioTrack { | |
58 int sample_rate; | |
59 int bits; | |
60 int channels; | |
143 | 61 int stream_index; |
145 | 62 int adpcm; |
137 | 63 } AudioTrack; |
64 | |
65 typedef struct FourxmDemuxContext { | |
66 int width; | |
67 int height; | |
143 | 68 int video_stream_index; |
137 | 69 int track_count; |
70 AudioTrack *tracks; | |
71 int selected_track; | |
143 | 72 |
316
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
73 int64_t audio_pts; |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
74 int64_t video_pts; |
317 | 75 float fps; |
137 | 76 } FourxmDemuxContext; |
77 | |
316
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
78 static float get_le_float(unsigned char *buffer) |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
79 { |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
80 float f; |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
81 unsigned char *float_buffer = (unsigned char *)&f; |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
82 |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
83 #ifdef WORDS_BIGENDIAN |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
84 float_buffer[0] = buffer[3]; |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
85 float_buffer[1] = buffer[2]; |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
86 float_buffer[2] = buffer[1]; |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
87 float_buffer[3] = buffer[0]; |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
88 #else |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
89 float_buffer[0] = buffer[0]; |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
90 float_buffer[1] = buffer[1]; |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
91 float_buffer[2] = buffer[2]; |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
92 float_buffer[3] = buffer[3]; |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
93 #endif |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
94 |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
95 return f; |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
96 } |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
97 |
137 | 98 static int fourxm_probe(AVProbeData *p) |
99 { | |
254
bca5abd97e43
clean up 4xm demuxer; make valgrind just a little happier
tmmm
parents:
145
diff
changeset
|
100 if (p->buf_size < 12) |
bca5abd97e43
clean up 4xm demuxer; make valgrind just a little happier
tmmm
parents:
145
diff
changeset
|
101 return 0; |
bca5abd97e43
clean up 4xm demuxer; make valgrind just a little happier
tmmm
parents:
145
diff
changeset
|
102 |
143 | 103 if ((LE_32(&p->buf[0]) != RIFF_TAG) || |
104 (LE_32(&p->buf[8]) != _4XMV_TAG)) | |
137 | 105 return 0; |
106 | |
107 return AVPROBE_SCORE_MAX; | |
108 } | |
109 | |
110 static int fourxm_read_header(AVFormatContext *s, | |
143 | 111 AVFormatParameters *ap) |
137 | 112 { |
113 ByteIOContext *pb = &s->pb; | |
114 unsigned int fourcc_tag; | |
115 unsigned int size; | |
116 int header_size; | |
117 FourxmDemuxContext *fourxm = (FourxmDemuxContext *)s->priv_data; | |
118 unsigned char *header; | |
119 int i; | |
120 int current_track = -1; | |
121 AVStream *st; | |
122 | |
123 fourxm->track_count = 0; | |
124 fourxm->tracks = NULL; | |
125 fourxm->selected_track = 0; | |
317 | 126 fourxm->fps = 1.0; |
137 | 127 |
128 /* skip the first 3 32-bit numbers */ | |
129 url_fseek(pb, 12, SEEK_CUR); | |
130 | |
131 /* check for LIST-HEAD */ | |
132 GET_LIST_HEADER(); | |
133 header_size = size - 4; | |
134 if (fourcc_tag != HEAD_TAG) | |
135 return AVERROR_INVALIDDATA; | |
136 | |
137 /* allocate space for the header and load the whole thing */ | |
138 header = av_malloc(header_size); | |
139 if (!header) | |
140 return AVERROR_NOMEM; | |
141 if (get_buffer(pb, header, header_size) != header_size) | |
142 return AVERROR_IO; | |
143 | |
144 /* take the lazy approach and search for any and all vtrk and strk chunks */ | |
145 for (i = 0; i < header_size - 8; i++) { | |
143 | 146 fourcc_tag = LE_32(&header[i]); |
137 | 147 size = LE_32(&header[i + 4]); |
148 | |
316
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
149 if (fourcc_tag == std__TAG) { |
317 | 150 fourxm->fps = get_le_float(&header[i + 12]); |
316
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
151 } else if (fourcc_tag == vtrk_TAG) { |
137 | 152 /* check that there is enough data */ |
153 if (size != vtrk_SIZE) { | |
154 av_free(header); | |
155 return AVERROR_INVALIDDATA; | |
156 } | |
157 fourxm->width = LE_32(&header[i + 36]); | |
158 fourxm->height = LE_32(&header[i + 40]); | |
159 i += 8 + size; | |
143 | 160 |
161 /* allocate a new AVStream */ | |
162 st = av_new_stream(s, 0); | |
163 if (!st) | |
164 return AVERROR_NOMEM; | |
740 | 165 av_set_pts_info(st, 60, 1, fourxm->fps); |
143 | 166 |
167 fourxm->video_stream_index = st->index; | |
168 | |
169 st->codec.codec_type = CODEC_TYPE_VIDEO; | |
170 st->codec.codec_id = CODEC_ID_4XM; | |
171 st->codec.codec_tag = 0; /* no fourcc */ | |
172 st->codec.width = fourxm->width; | |
173 st->codec.height = fourxm->height; | |
174 | |
137 | 175 } else if (fourcc_tag == strk_TAG) { |
176 /* check that there is enough data */ | |
177 if (size != strk_SIZE) { | |
178 av_free(header); | |
179 return AVERROR_INVALIDDATA; | |
180 } | |
181 current_track = LE_32(&header[i + 8]); | |
182 if (current_track + 1 > fourxm->track_count) { | |
141 | 183 fourxm->track_count = current_track + 1; |
639 | 184 if((unsigned)fourxm->track_count >= UINT_MAX / sizeof(AudioTrack)) |
185 return -1; | |
141 | 186 fourxm->tracks = av_realloc(fourxm->tracks, |
187 fourxm->track_count * sizeof(AudioTrack)); | |
137 | 188 if (!fourxm->tracks) { |
189 av_free(header); | |
190 return AVERROR_NOMEM; | |
191 } | |
192 } | |
145 | 193 fourxm->tracks[current_track].adpcm = LE_32(&header[i + 12]); |
137 | 194 fourxm->tracks[current_track].channels = LE_32(&header[i + 36]); |
195 fourxm->tracks[current_track].sample_rate = LE_32(&header[i + 40]); | |
196 fourxm->tracks[current_track].bits = LE_32(&header[i + 44]); | |
197 i += 8 + size; | |
143 | 198 |
199 /* allocate a new AVStream */ | |
200 st = av_new_stream(s, current_track); | |
201 if (!st) | |
202 return AVERROR_NOMEM; | |
203 | |
740 | 204 av_set_pts_info(st, 60, 1, fourxm->tracks[current_track].sample_rate); |
462
b69898ffc92a
move time_base (pts_num/pts_den) from AVFormatContext -> AVStream
michael
parents:
386
diff
changeset
|
205 |
143 | 206 fourxm->tracks[current_track].stream_index = st->index; |
207 | |
208 st->codec.codec_type = CODEC_TYPE_AUDIO; | |
209 st->codec.codec_tag = 1; | |
210 st->codec.channels = fourxm->tracks[current_track].channels; | |
211 st->codec.sample_rate = fourxm->tracks[current_track].sample_rate; | |
212 st->codec.bits_per_sample = fourxm->tracks[current_track].bits; | |
213 st->codec.bit_rate = st->codec.channels * st->codec.sample_rate * | |
214 st->codec.bits_per_sample; | |
215 st->codec.block_align = st->codec.channels * st->codec.bits_per_sample; | |
145 | 216 if (fourxm->tracks[current_track].adpcm) |
217 st->codec.codec_id = CODEC_ID_ADPCM_4XM; | |
218 else if (st->codec.bits_per_sample == 8) | |
143 | 219 st->codec.codec_id = CODEC_ID_PCM_U8; |
220 else | |
221 st->codec.codec_id = CODEC_ID_PCM_S16LE; | |
137 | 222 } |
223 } | |
224 | |
225 av_free(header); | |
226 | |
227 /* skip over the LIST-MOVI chunk (which is where the stream should be */ | |
228 GET_LIST_HEADER(); | |
229 if (fourcc_tag != MOVI_TAG) | |
230 return AVERROR_INVALIDDATA; | |
231 | |
143 | 232 /* initialize context members */ |
740 | 233 fourxm->video_pts = -1; /* first frame will push to 0 */ |
316
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
234 fourxm->audio_pts = 0; |
137 | 235 |
236 return 0; | |
237 } | |
238 | |
239 static int fourxm_read_packet(AVFormatContext *s, | |
143 | 240 AVPacket *pkt) |
137 | 241 { |
242 FourxmDemuxContext *fourxm = s->priv_data; | |
243 ByteIOContext *pb = &s->pb; | |
244 unsigned int fourcc_tag; | |
145 | 245 unsigned int size, out_size; |
137 | 246 int ret = 0; |
247 int track_number; | |
248 int packet_read = 0; | |
143 | 249 unsigned char header[8]; |
316
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
250 int audio_frame_count; |
137 | 251 |
252 while (!packet_read) { | |
253 | |
143 | 254 if ((ret = get_buffer(&s->pb, header, 8)) < 0) |
255 return ret; | |
256 fourcc_tag = LE_32(&header[0]); | |
257 size = LE_32(&header[4]); | |
137 | 258 if (url_feof(pb)) |
482 | 259 return AVERROR_IO; |
137 | 260 switch (fourcc_tag) { |
261 | |
144 | 262 case LIST_TAG: |
316
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
263 /* this is a good time to bump the video pts */ |
740 | 264 fourxm->video_pts ++; |
316
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
265 |
144 | 266 /* skip the LIST-* tag and move on to the next fourcc */ |
267 get_le32(pb); | |
268 break; | |
269 | |
137 | 270 case ifrm_TAG: |
271 case pfrm_TAG: | |
139 | 272 case cfrm_TAG:{ |
143 | 273 |
274 /* allocate 8 more bytes than 'size' to account for fourcc | |
275 * and size */ | |
643 | 276 if (size + 8 < size || av_new_packet(pkt, size + 8)) |
482 | 277 return AVERROR_IO; |
143 | 278 pkt->stream_index = fourxm->video_stream_index; |
316
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
279 pkt->pts = fourxm->video_pts; |
775 | 280 pkt->pos = url_ftell(&s->pb); |
143 | 281 memcpy(pkt->data, header, 8); |
282 ret = get_buffer(&s->pb, &pkt->data[8], size); | |
283 | |
284 if (ret < 0) | |
285 av_free_packet(pkt); | |
286 else | |
287 packet_read = 1; | |
139 | 288 break; |
289 } | |
143 | 290 |
137 | 291 case snd__TAG: |
292 track_number = get_le32(pb); | |
145 | 293 out_size= get_le32(pb); |
294 size-=8; | |
295 | |
137 | 296 if (track_number == fourxm->selected_track) { |
775 | 297 ret= av_get_packet(&s->pb, pkt, size); |
298 if(ret<0) | |
482 | 299 return AVERROR_IO; |
143 | 300 pkt->stream_index = |
301 fourxm->tracks[fourxm->selected_track].stream_index; | |
316
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
302 pkt->pts = fourxm->audio_pts; |
775 | 303 packet_read = 1; |
143 | 304 |
316
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
305 /* pts accounting */ |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
306 audio_frame_count = size; |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
307 if (fourxm->tracks[fourxm->selected_track].adpcm) |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
308 audio_frame_count -= |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
309 2 * (fourxm->tracks[fourxm->selected_track].channels); |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
310 audio_frame_count /= |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
311 fourxm->tracks[fourxm->selected_track].channels; |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
312 if (fourxm->tracks[fourxm->selected_track].adpcm) |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
313 audio_frame_count *= 2; |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
314 else |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
315 audio_frame_count /= |
9aa23c6d396e
use the proper file framerate (specified by a float); account the pts
melanson
parents:
254
diff
changeset
|
316 (fourxm->tracks[fourxm->selected_track].bits / 8); |
740 | 317 fourxm->audio_pts += audio_frame_count; |
143 | 318 |
137 | 319 } else { |
320 url_fseek(pb, size, SEEK_CUR); | |
321 } | |
322 break; | |
323 | |
324 default: | |
325 url_fseek(pb, size, SEEK_CUR); | |
326 break; | |
327 } | |
328 } | |
329 return ret; | |
330 } | |
331 | |
332 static int fourxm_read_close(AVFormatContext *s) | |
333 { | |
334 FourxmDemuxContext *fourxm = (FourxmDemuxContext *)s->priv_data; | |
335 | |
336 av_free(fourxm->tracks); | |
337 | |
338 return 0; | |
339 } | |
340 | |
341 static AVInputFormat fourxm_iformat = { | |
342 "4xm", | |
343 "4X Technologies format", | |
344 sizeof(FourxmDemuxContext), | |
345 fourxm_probe, | |
346 fourxm_read_header, | |
347 fourxm_read_packet, | |
348 fourxm_read_close, | |
349 }; | |
350 | |
351 int fourxm_init(void) | |
352 { | |
353 av_register_input_format(&fourxm_iformat); | |
354 return 0; | |
355 } |