Mercurial > libavformat.hg
comparison 4xm.c @ 143:76dd1e93b064 libavformat
dispatch video as well as audio
author | tmmm |
---|---|
date | Wed, 28 May 2003 02:41:24 +0000 |
parents | d2d2ec541148 |
children | 9e73bf732800 |
comparison
equal
deleted
inserted
replaced
142:720bab5adc70 | 143:76dd1e93b064 |
---|---|
30 #define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0]) | 30 #define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0]) |
31 #define LE_32(x) ((((uint8_t*)(x))[3] << 24) | \ | 31 #define LE_32(x) ((((uint8_t*)(x))[3] << 24) | \ |
32 (((uint8_t*)(x))[2] << 16) | \ | 32 (((uint8_t*)(x))[2] << 16) | \ |
33 (((uint8_t*)(x))[1] << 8) | \ | 33 (((uint8_t*)(x))[1] << 8) | \ |
34 ((uint8_t*)(x))[0]) | 34 ((uint8_t*)(x))[0]) |
35 #define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1]) | |
36 #define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \ | |
37 (((uint8_t*)(x))[1] << 16) | \ | |
38 (((uint8_t*)(x))[2] << 8) | \ | |
39 ((uint8_t*)(x))[3]) | |
40 | 35 |
41 #define FOURCC_TAG( ch0, ch1, ch2, ch3 ) \ | 36 #define FOURCC_TAG( ch0, ch1, ch2, ch3 ) \ |
42 ( (long)(unsigned char)(ch3) | \ | 37 ( (long)(unsigned char)(ch0) | \ |
43 ( (long)(unsigned char)(ch2) << 8 ) | \ | 38 ( (long)(unsigned char)(ch1) << 8 ) | \ |
44 ( (long)(unsigned char)(ch1) << 16 ) | \ | 39 ( (long)(unsigned char)(ch2) << 16 ) | \ |
45 ( (long)(unsigned char)(ch0) << 24 ) ) | 40 ( (long)(unsigned char)(ch3) << 24 ) ) |
46 | 41 |
47 #define RIFF_TAG FOURCC_TAG('R', 'I', 'F', 'F') | 42 #define RIFF_TAG FOURCC_TAG('R', 'I', 'F', 'F') |
48 #define _4XMV_TAG FOURCC_TAG('4', 'X', 'M', 'V') | 43 #define _4XMV_TAG FOURCC_TAG('4', 'X', 'M', 'V') |
49 #define LIST_TAG FOURCC_TAG('L', 'I', 'S', 'T') | 44 #define LIST_TAG FOURCC_TAG('L', 'I', 'S', 'T') |
50 #define HEAD_TAG FOURCC_TAG('H', 'E', 'A', 'D') | 45 #define HEAD_TAG FOURCC_TAG('H', 'E', 'A', 'D') |
63 | 58 |
64 #define vtrk_SIZE 0x44 | 59 #define vtrk_SIZE 0x44 |
65 #define strk_SIZE 0x28 | 60 #define strk_SIZE 0x28 |
66 | 61 |
67 #define GET_LIST_HEADER() \ | 62 #define GET_LIST_HEADER() \ |
68 fourcc_tag = get_be32(pb); \ | 63 fourcc_tag = get_le32(pb); \ |
69 size = get_le32(pb); \ | 64 size = get_le32(pb); \ |
70 if (fourcc_tag != LIST_TAG) \ | 65 if (fourcc_tag != LIST_TAG) \ |
71 return AVERROR_INVALIDDATA; \ | 66 return AVERROR_INVALIDDATA; \ |
72 fourcc_tag = get_be32(pb); | 67 fourcc_tag = get_le32(pb); |
73 | 68 |
74 typedef struct AudioTrack { | 69 typedef struct AudioTrack { |
75 int sample_rate; | 70 int sample_rate; |
76 int bits; | 71 int bits; |
77 int channels; | 72 int channels; |
73 int stream_index; | |
78 } AudioTrack; | 74 } AudioTrack; |
79 | 75 |
80 typedef struct FourxmDemuxContext { | 76 typedef struct FourxmDemuxContext { |
81 int width; | 77 int width; |
82 int height; | 78 int height; |
79 int video_stream_index; | |
83 int track_count; | 80 int track_count; |
84 AudioTrack *tracks; | 81 AudioTrack *tracks; |
85 int selected_track; | 82 int selected_track; |
83 | |
84 int64_t pts; | |
85 int last_chunk_was_audio; | |
86 int last_audio_frame_count; | |
86 } FourxmDemuxContext; | 87 } FourxmDemuxContext; |
87 | 88 |
88 static int fourxm_probe(AVProbeData *p) | 89 static int fourxm_probe(AVProbeData *p) |
89 { | 90 { |
90 if ((BE_32(&p->buf[0]) != RIFF_TAG) || | 91 if ((LE_32(&p->buf[0]) != RIFF_TAG) || |
91 (BE_32(&p->buf[8]) != _4XMV_TAG)) | 92 (LE_32(&p->buf[8]) != _4XMV_TAG)) |
92 return 0; | 93 return 0; |
93 | 94 |
94 printf (" detected .4xm file\n"); | |
95 | |
96 return AVPROBE_SCORE_MAX; | 95 return AVPROBE_SCORE_MAX; |
97 } | 96 } |
98 | 97 |
99 static int fourxm_read_header(AVFormatContext *s, | 98 static int fourxm_read_header(AVFormatContext *s, |
100 AVFormatParameters *ap) | 99 AVFormatParameters *ap) |
101 { | 100 { |
102 ByteIOContext *pb = &s->pb; | 101 ByteIOContext *pb = &s->pb; |
103 unsigned int fourcc_tag; | 102 unsigned int fourcc_tag; |
104 unsigned int size; | 103 unsigned int size; |
105 int header_size; | 104 int header_size; |
129 if (get_buffer(pb, header, header_size) != header_size) | 128 if (get_buffer(pb, header, header_size) != header_size) |
130 return AVERROR_IO; | 129 return AVERROR_IO; |
131 | 130 |
132 /* take the lazy approach and search for any and all vtrk and strk chunks */ | 131 /* take the lazy approach and search for any and all vtrk and strk chunks */ |
133 for (i = 0; i < header_size - 8; i++) { | 132 for (i = 0; i < header_size - 8; i++) { |
134 fourcc_tag = BE_32(&header[i]); | 133 fourcc_tag = LE_32(&header[i]); |
135 size = LE_32(&header[i + 4]); | 134 size = LE_32(&header[i + 4]); |
136 | 135 |
137 if (fourcc_tag == vtrk_TAG) { | 136 if (fourcc_tag == vtrk_TAG) { |
138 /* check that there is enough data */ | 137 /* check that there is enough data */ |
139 if (size != vtrk_SIZE) { | 138 if (size != vtrk_SIZE) { |
141 return AVERROR_INVALIDDATA; | 140 return AVERROR_INVALIDDATA; |
142 } | 141 } |
143 fourxm->width = LE_32(&header[i + 36]); | 142 fourxm->width = LE_32(&header[i + 36]); |
144 fourxm->height = LE_32(&header[i + 40]); | 143 fourxm->height = LE_32(&header[i + 40]); |
145 i += 8 + size; | 144 i += 8 + size; |
145 | |
146 /* allocate a new AVStream */ | |
147 st = av_new_stream(s, 0); | |
148 if (!st) | |
149 return AVERROR_NOMEM; | |
150 | |
151 fourxm->video_stream_index = st->index; | |
152 | |
153 st->codec.codec_type = CODEC_TYPE_VIDEO; | |
154 st->codec.codec_id = CODEC_ID_4XM; | |
155 st->codec.codec_tag = 0; /* no fourcc */ | |
156 st->codec.width = fourxm->width; | |
157 st->codec.height = fourxm->height; | |
158 | |
146 } else if (fourcc_tag == strk_TAG) { | 159 } else if (fourcc_tag == strk_TAG) { |
147 /* check that there is enough data */ | 160 /* check that there is enough data */ |
148 if (size != strk_SIZE) { | 161 if (size != strk_SIZE) { |
149 av_free(header); | 162 av_free(header); |
150 return AVERROR_INVALIDDATA; | 163 return AVERROR_INVALIDDATA; |
161 } | 174 } |
162 fourxm->tracks[current_track].channels = LE_32(&header[i + 36]); | 175 fourxm->tracks[current_track].channels = LE_32(&header[i + 36]); |
163 fourxm->tracks[current_track].sample_rate = LE_32(&header[i + 40]); | 176 fourxm->tracks[current_track].sample_rate = LE_32(&header[i + 40]); |
164 fourxm->tracks[current_track].bits = LE_32(&header[i + 44]); | 177 fourxm->tracks[current_track].bits = LE_32(&header[i + 44]); |
165 i += 8 + size; | 178 i += 8 + size; |
179 | |
180 /* allocate a new AVStream */ | |
181 st = av_new_stream(s, current_track); | |
182 if (!st) | |
183 return AVERROR_NOMEM; | |
184 | |
185 fourxm->tracks[current_track].stream_index = st->index; | |
186 | |
187 st->codec.codec_type = CODEC_TYPE_AUDIO; | |
188 st->codec.codec_tag = 1; | |
189 st->codec.channels = fourxm->tracks[current_track].channels; | |
190 st->codec.sample_rate = fourxm->tracks[current_track].sample_rate; | |
191 st->codec.bits_per_sample = fourxm->tracks[current_track].bits; | |
192 st->codec.bit_rate = st->codec.channels * st->codec.sample_rate * | |
193 st->codec.bits_per_sample; | |
194 st->codec.block_align = st->codec.channels * st->codec.bits_per_sample; | |
195 if (st->codec.bits_per_sample == 8) | |
196 st->codec.codec_id = CODEC_ID_PCM_U8; | |
197 else | |
198 st->codec.codec_id = CODEC_ID_PCM_S16LE; | |
166 } | 199 } |
167 } | 200 } |
168 | 201 |
169 av_free(header); | 202 av_free(header); |
170 | 203 |
171 /* skip over the LIST-MOVI chunk (which is where the stream should be */ | 204 /* skip over the LIST-MOVI chunk (which is where the stream should be */ |
172 GET_LIST_HEADER(); | 205 GET_LIST_HEADER(); |
173 if (fourcc_tag != MOVI_TAG) | 206 if (fourcc_tag != MOVI_TAG) |
174 return AVERROR_INVALIDDATA; | 207 return AVERROR_INVALIDDATA; |
175 | 208 |
176 if (current_track > -1) { | 209 /* initialize context members */ |
177 st = av_new_stream(s, 0); | 210 fourxm->pts = 0; |
178 if (!st) | 211 fourxm->last_chunk_was_audio = 0; |
179 return AVERROR_NOMEM; | 212 fourxm->last_audio_frame_count = 0; |
180 | 213 |
181 st->codec.codec_type = CODEC_TYPE_AUDIO; | 214 /* set the pts reference (1 pts = 1/90000) */ |
182 st->codec.codec_tag = 1; | 215 s->pts_num = 1; |
183 st->codec.channels = fourxm->tracks[current_track].channels; | 216 s->pts_den = 90000; |
184 st->codec.sample_rate = fourxm->tracks[current_track].sample_rate; | |
185 st->codec.bits_per_sample = fourxm->tracks[current_track].bits; | |
186 st->codec.bit_rate = st->codec.channels * st->codec.sample_rate * | |
187 st->codec.bits_per_sample; | |
188 st->codec.block_align = st->codec.channels * st->codec.bits_per_sample; | |
189 if (st->codec.bits_per_sample == 8) | |
190 st->codec.codec_id = CODEC_ID_PCM_U8; | |
191 else | |
192 st->codec.codec_id = CODEC_ID_PCM_S16LE; | |
193 } | |
194 | 217 |
195 return 0; | 218 return 0; |
196 } | 219 } |
197 | 220 |
198 static int fourxm_read_packet(AVFormatContext *s, | 221 static int fourxm_read_packet(AVFormatContext *s, |
199 AVPacket *pkt) | 222 AVPacket *pkt) |
200 { | 223 { |
201 FourxmDemuxContext *fourxm = s->priv_data; | 224 FourxmDemuxContext *fourxm = s->priv_data; |
202 ByteIOContext *pb = &s->pb; | 225 ByteIOContext *pb = &s->pb; |
203 unsigned int fourcc_tag; | 226 unsigned int fourcc_tag; |
204 unsigned int size; | 227 unsigned int size; |
205 int ret = 0; | 228 int ret = 0; |
206 int track_number; | 229 int track_number; |
207 int packet_read = 0; | 230 int packet_read = 0; |
231 unsigned char header[8]; | |
232 int64_t pts_inc; | |
208 | 233 |
209 while (!packet_read) { | 234 while (!packet_read) { |
210 | 235 |
211 fourcc_tag = get_be32(pb); | 236 if ((ret = get_buffer(&s->pb, header, 8)) < 0) |
212 size = get_le32(pb); | 237 return ret; |
238 fourcc_tag = LE_32(&header[0]); | |
239 size = LE_32(&header[4]); | |
213 if (fourcc_tag == LIST_TAG) { | 240 if (fourcc_tag == LIST_TAG) { |
214 /* skip the LIST-FRAM tag and get the next fourcc */ | 241 /* skip the LIST-FRAM tag and get the next fourcc */ |
215 get_be32(pb); | 242 get_le32(pb); |
216 fourcc_tag = get_be32(pb); | 243 fourcc_tag = get_le32(pb); |
217 size = get_le32(pb); | 244 size = get_le32(pb); |
218 } | 245 } |
219 | 246 |
220 if (url_feof(pb)) | 247 if (url_feof(pb)) |
221 return -EIO; | 248 return -EIO; |
222 | 249 |
223 switch (fourcc_tag) { | 250 switch (fourcc_tag) { |
224 | 251 |
225 case ifrm_TAG: | 252 case ifrm_TAG: |
226 printf (" %cfrm chunk\n", (char)(fourcc_tag >> 24) & 0xFF); | |
227 url_fseek(pb, size, SEEK_CUR); | |
228 break; | |
229 case pfrm_TAG: | 253 case pfrm_TAG: |
230 printf (" %cfrm chunk\n", (char)(fourcc_tag >> 24) & 0xFF); | |
231 url_fseek(pb, size, SEEK_CUR); | |
232 break; | |
233 case cfrm_TAG:{ | 254 case cfrm_TAG:{ |
234 int unknown= get_le32(pb); | 255 |
235 int id= get_le32(pb); | 256 int id, whole; |
236 int whole= get_le32(pb); | |
237 static int stats[1000]; | 257 static int stats[1000]; |
258 | |
259 /* bump the pts if this last data sent out was audio */ | |
260 if (fourxm->last_chunk_was_audio) { | |
261 fourxm->last_chunk_was_audio = 0; | |
262 pts_inc = fourxm->last_audio_frame_count; | |
263 pts_inc *= 90000; | |
264 pts_inc /= fourxm->tracks[fourxm->selected_track].sample_rate; | |
265 fourxm->pts += pts_inc; | |
266 } | |
267 | |
268 /* allocate 8 more bytes than 'size' to account for fourcc | |
269 * and size */ | |
270 if (av_new_packet(pkt, size + 8)) | |
271 return -EIO; | |
272 pkt->stream_index = fourxm->video_stream_index; | |
273 pkt->pts = fourxm->pts; | |
274 memcpy(pkt->data, header, 8); | |
275 ret = get_buffer(&s->pb, &pkt->data[8], size); | |
276 | |
277 if (fourcc_tag == cfrm_TAG) { | |
278 id = LE_32(&pkt->data[12]); | |
279 whole = LE_32(&pkt->data[16]); | |
238 stats[id] += size - 12; | 280 stats[id] += size - 12; |
239 printf(" cfrm chunk id:%d size:%d whole:%d until now:%d\n", id, size, whole, stats[id]); | 281 printf(" cfrm chunk id:%d size:%d whole:%d until now:%d\n", id, size, whole, stats[id]); |
240 url_fseek(pb, size-12, SEEK_CUR); | 282 } |
283 | |
284 if (ret < 0) | |
285 av_free_packet(pkt); | |
286 else | |
287 packet_read = 1; | |
241 break; | 288 break; |
242 } | 289 } |
290 | |
243 case snd__TAG: | 291 case snd__TAG: |
244 printf (" snd_ chunk, "); | 292 printf (" snd_ chunk, "); |
245 track_number = get_le32(pb); | 293 track_number = get_le32(pb); |
246 size = get_le32(pb); | 294 size = get_le32(pb); |
247 if (track_number == fourxm->selected_track) { | 295 if (track_number == fourxm->selected_track) { |
248 printf ("correct track, dispatching...\n"); | 296 printf ("correct track, dispatching...\n"); |
249 if (av_new_packet(pkt, size)) | 297 if (av_new_packet(pkt, size)) |
250 return -EIO; | 298 return -EIO; |
299 pkt->stream_index = | |
300 fourxm->tracks[fourxm->selected_track].stream_index; | |
301 pkt->pts = fourxm->pts; | |
251 ret = get_buffer(&s->pb, pkt->data, size); | 302 ret = get_buffer(&s->pb, pkt->data, size); |
252 if (ret < 0) | 303 if (ret < 0) |
253 av_free_packet(pkt); | 304 av_free_packet(pkt); |
254 packet_read = 1; | 305 else |
306 packet_read = 1; | |
307 | |
308 /* maintain pts info for the benefit of the video track */ | |
309 fourxm->last_chunk_was_audio = 1; | |
310 fourxm->last_audio_frame_count = size / | |
311 ((fourxm->tracks[fourxm->selected_track].bits / 8) * | |
312 fourxm->tracks[fourxm->selected_track].channels); | |
313 | |
255 } else { | 314 } else { |
256 printf ("wrong track, skipping...\n"); | 315 printf ("wrong track, skipping...\n"); |
257 url_fseek(pb, size, SEEK_CUR); | 316 url_fseek(pb, size, SEEK_CUR); |
258 } | 317 } |
259 break; | 318 break; |