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;