Mercurial > libavformat.hg
annotate nut.c @ 270:6821ccd70a1c libavformat
fix fabrice's broken get_bi and some minor changes in draft
author | al3x |
---|---|
date | Thu, 02 Oct 2003 14:59:54 +0000 |
parents | 3d92f793fd67 |
children | e35faf19f79f |
rev | line source |
---|---|
219 | 1 /* |
2 * NUT (de)muxer based on initial draft | |
3 * Copyright (c) 2003 Alex Beregszaszi | |
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 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 * NUT DRAFT can be found in MPlayer CVS at DOCS/tech/mpcf.txt | |
20 * | |
21 * Compatible with draft version 20030906 | |
22 * | |
23 */ | |
24 | |
25 /* | |
26 * TODO: | |
27 * - checksumming | |
28 * - correct rate denom/nom and sample_mul | |
29 * - correct timestamp handling | |
30 * - index writing | |
31 * - info and index packet reading support | |
32 * - startcode searching for broken streams | |
33 * - subpacket support | |
34 * - handling of codec specific headers | |
35 */ | |
36 | |
37 //#define DEBUG 1 | |
38 | |
39 #include "avformat.h" | |
40 #include "mpegaudio.h" | |
228 | 41 #include "avi.h" |
219 | 42 |
220 | 43 //from /dev/random |
44 | |
45 #define MAIN_STARTCODE (0xF9526A6200000000ULL + ('N'<<24) + ('U'<<16) + ('T'<<8) + 'M') | |
46 #define STREAM_STARTCODE (0xD667773F00000000ULL + ('N'<<24) + ('U'<<16) + ('T'<<8) + 'S') | |
47 #define KEYFRAME_STARTCODE (0xCB86308700000000ULL + ('N'<<24) + ('U'<<16) + ('T'<<8) + 'K') | |
48 #define INDEX_STARTCODE (0xEBFCDE0E00000000ULL + ('N'<<24) + ('U'<<16) + ('T'<<8) + 'X') | |
49 #define INFO_STARTCODE (0xA37B643500000000ULL + ('N'<<24) + ('U'<<16) + ('T'<<8) + 'I') | |
50 | |
219 | 51 typedef struct { |
52 int curr_frame_start; | |
53 int last_frame_size; | |
54 int curr_frame_size; | |
55 } NUTContext; | |
56 | |
57 static int bytes_left(ByteIOContext *bc) | |
58 { | |
59 return bc->buf_end - bc->buf_ptr; | |
60 } | |
61 | |
62 static uint64_t get_v(ByteIOContext *bc) | |
63 { | |
64 uint64_t val = 0; | |
65 | |
66 for(; bytes_left(bc) > 0; ) | |
67 { | |
68 int tmp = get_byte(bc); | |
69 | |
70 if (tmp&0x80) | |
71 val= (val<<7) + tmp - 0x80; | |
72 else | |
73 return (val<<7) + tmp; | |
74 } | |
75 return -1; | |
76 } | |
77 | |
78 static int64_t get_s(ByteIOContext *bc) | |
79 { | |
80 int64_t v = get_v(bc) + 1; | |
81 | |
82 if (v&1) | |
83 return -(v>>1); | |
84 else | |
85 return (v>>1); | |
86 } | |
87 | |
240 | 88 static int get_b(ByteIOContext *bc, char *data, int maxlen) |
219 | 89 { |
240 | 90 int i, len; |
219 | 91 |
92 len = get_v(bc); | |
240 | 93 for (i = 0; i < len && i < maxlen; i++) |
94 data[i] = get_byte(bc); | |
270
6821ccd70a1c
fix fabrice's broken get_bi and some minor changes in draft
al3x
parents:
241
diff
changeset
|
95 /* skip remaining bytes */ |
6821ccd70a1c
fix fabrice's broken get_bi and some minor changes in draft
al3x
parents:
241
diff
changeset
|
96 for (; i < len; i++) |
6821ccd70a1c
fix fabrice's broken get_bi and some minor changes in draft
al3x
parents:
241
diff
changeset
|
97 get_byte(bc); |
240 | 98 |
99 return 0; | |
100 } | |
101 | |
102 static int get_bi(ByteIOContext *bc) | |
103 { | |
270
6821ccd70a1c
fix fabrice's broken get_bi and some minor changes in draft
al3x
parents:
241
diff
changeset
|
104 int i, len, val = 0; |
240 | 105 |
106 len = get_v(bc); | |
270
6821ccd70a1c
fix fabrice's broken get_bi and some minor changes in draft
al3x
parents:
241
diff
changeset
|
107 for (i = 0; i < len && i <= 4; i++) |
240 | 108 val |= get_byte(bc) << (i * 8); |
270
6821ccd70a1c
fix fabrice's broken get_bi and some minor changes in draft
al3x
parents:
241
diff
changeset
|
109 /* skip remaining bytes */ |
6821ccd70a1c
fix fabrice's broken get_bi and some minor changes in draft
al3x
parents:
241
diff
changeset
|
110 for (; i < len; i++) |
6821ccd70a1c
fix fabrice's broken get_bi and some minor changes in draft
al3x
parents:
241
diff
changeset
|
111 get_byte(bc); |
240 | 112 |
228 | 113 return val; |
219 | 114 } |
115 | |
116 static int get_packetheader(NUTContext *nut, ByteIOContext *bc) | |
117 { | |
118 nut->curr_frame_start = url_ftell(bc); | |
119 nut->curr_frame_size = get_v(bc); | |
120 nut->last_frame_size = get_v(bc); | |
121 dprintf("Packet: fwd: %d bwd: %d\n", | |
122 nut->curr_frame_size, nut->last_frame_size); | |
123 | |
124 return 0; | |
125 } | |
126 | |
221 | 127 /** |
128 * | |
129 */ | |
130 static int get_length(uint64_t val){ | |
131 int i; | |
219 | 132 |
221 | 133 for (i=7; ; i+=7) |
134 if ((val>>i) == 0) | |
135 return i; | |
219 | 136 |
221 | 137 return 7; //not reached |
219 | 138 } |
139 | |
140 static int put_v(ByteIOContext *bc, uint64_t val) | |
141 { | |
142 int i; | |
143 | |
144 // if (bytes_left(s)*8 < 9) | |
145 // return -1; | |
146 | |
147 if (bytes_left(bc) < 1) | |
148 return -1; | |
149 | |
150 val &= 0x7FFFFFFFFFFFFFFFULL; // FIXME can only encode upto 63 bits currently | |
221 | 151 i= get_length(val); |
219 | 152 |
220 | 153 for (i-=7; i>0; i-=7){ |
219 | 154 put_byte(bc, 0x80 | (val>>i)); |
220 | 155 } |
219 | 156 |
157 put_byte(bc, val&0x7f); | |
158 | |
159 return 0; | |
160 } | |
161 | |
162 static int put_s(ByteIOContext *bc, uint64_t val) | |
163 { | |
164 if (val<=0) | |
165 return put_v(bc, -2*val); | |
166 else | |
167 return put_v(bc, 2*val-1); | |
168 } | |
169 | |
170 static int put_b(ByteIOContext *bc, char *data, int len) | |
171 { | |
172 int i; | |
173 | |
174 put_v(bc, len); | |
175 for (i = 0; i < len; i++) | |
176 put_byte(bc, data[i]); | |
177 | |
178 return 0; | |
179 } | |
180 | |
228 | 181 static int put_bi(ByteIOContext *bc, int val) |
182 { | |
183 put_v(bc, 4); | |
184 put_le32(bc, val); | |
185 return 0; | |
186 } | |
187 | |
221 | 188 static int put_packetheader(NUTContext *nut, ByteIOContext *bc, int max_size) |
219 | 189 { |
190 put_flush_packet(bc); | |
191 nut->curr_frame_start = url_ftell(bc); | |
221 | 192 nut->curr_frame_size = max_size; |
219 | 193 |
194 /* packet header */ | |
195 put_v(bc, nut->curr_frame_size); /* forward ptr */ | |
196 put_v(bc, nut->last_frame_size); /* backward ptr */ | |
197 dprintf("Packet: fwd: %d, bwd: %d\n", | |
198 nut->curr_frame_size, nut->last_frame_size); | |
199 | |
200 nut->last_frame_size = nut->curr_frame_size; | |
201 | |
202 return 0; | |
203 } | |
204 | |
221 | 205 static int update_packetheader(NUTContext *nut, ByteIOContext *bc, int additional_size){ |
206 offset_t start= nut->curr_frame_start; | |
207 offset_t cur= url_ftell(bc); | |
208 int size= cur - start + additional_size; | |
209 | |
210 assert( size <= nut->curr_frame_size ); | |
219 | 211 |
221 | 212 url_fseek(bc, start, SEEK_SET); |
213 put_v(bc, size); | |
214 if(get_length(size) < get_length(nut->curr_frame_size)) | |
215 put_byte(bc, 0x80); | |
216 nut->curr_frame_size= size; | |
217 dprintf("Packet update: size: %d\n", size); | |
219 | 218 |
221 | 219 url_fseek(bc, cur, SEEK_SET); |
220 | |
219 | 221 return 0; |
222 } | |
223 | |
224 static int nut_write_header(AVFormatContext *s) | |
225 { | |
226 NUTContext *nut = s->priv_data; | |
227 ByteIOContext *bc = &s->pb; | |
228 AVCodecContext *codec; | |
229 int i; | |
230 | |
231 /* main header */ | |
220 | 232 put_be64(bc, MAIN_STARTCODE); |
223 | 233 put_packetheader(nut, bc, 120); |
219 | 234 put_v(bc, 0); /* version */ |
235 put_v(bc, s->nb_streams); | |
220 | 236 put_be32(bc, 0); /* FIXME: checksum */ |
219 | 237 |
221 | 238 update_packetheader(nut, bc, 0); |
239 | |
219 | 240 /* stream headers */ |
241 for (i = 0; i < s->nb_streams; i++) | |
242 { | |
243 codec = &s->streams[i]->codec; | |
244 | |
223 | 245 put_be64(bc, STREAM_STARTCODE); |
221 | 246 put_packetheader(nut, bc, 120); |
222 | 247 put_v(bc, i /*s->streams[i]->index*/); |
219 | 248 put_v(bc, (codec->codec_type == CODEC_TYPE_AUDIO) ? 32 : 0); |
249 if (codec->codec_tag) | |
228 | 250 put_bi(bc, codec->codec_tag); |
219 | 251 else if (codec->codec_type == CODEC_TYPE_VIDEO) |
252 { | |
253 int tmp = codec_get_bmp_tag(codec->codec_id); | |
228 | 254 put_bi(bc, tmp); |
219 | 255 } |
256 else if (codec->codec_type == CODEC_TYPE_AUDIO) | |
257 { | |
258 int tmp = codec_get_wav_tag(codec->codec_id); | |
228 | 259 put_bi(bc, tmp); |
219 | 260 } |
261 put_v(bc, codec->bit_rate); | |
262 put_v(bc, 0); /* no language code */ | |
263 put_v(bc, codec->frame_rate_base); | |
264 put_v(bc, codec->frame_rate); | |
265 put_v(bc, 0); /* timestamp_shift */ | |
266 put_v(bc, 0); /* shuffle type */ | |
267 put_byte(bc, 0); /* flags: 0x1 - fixed_fps, 0x2 - index_present */ | |
268 | |
269 put_v(bc, 0); /* no codec specific headers */ | |
270 | |
271 switch(codec->codec_type) | |
272 { | |
273 case CODEC_TYPE_AUDIO: | |
274 put_v(bc, codec->sample_rate / (double)(codec->frame_rate_base / codec->frame_rate)); | |
275 put_v(bc, codec->channels); | |
220 | 276 put_be32(bc, 0); /* FIXME: checksum */ |
219 | 277 break; |
278 case CODEC_TYPE_VIDEO: | |
279 put_v(bc, codec->width); | |
280 put_v(bc, codec->height); | |
281 put_v(bc, 0); /* aspected w */ | |
282 put_v(bc, 0); /* aspected h */ | |
283 put_v(bc, 0); /* csp type -- unknown */ | |
220 | 284 put_be32(bc, 0); /* FIXME: checksum */ |
219 | 285 break; |
228 | 286 default: |
287 break; | |
219 | 288 } |
221 | 289 update_packetheader(nut, bc, 0); |
219 | 290 } |
291 | |
292 #if 0 | |
293 /* info header */ | |
223 | 294 put_be64(bc, INFO_STARTCODE); |
219 | 295 put_packetheader(nut, bc, 16+strlen(s->author)+strlen(s->title)+ |
221 | 296 strlen(s->comment)+strlen(s->copyright)); |
219 | 297 if (s->author[0]) |
298 { | |
299 put_v(bc, 5); /* type */ | |
300 put_b(bc, s->author, strlen(s->author)); | |
301 } | |
302 if (s->title[0]) | |
303 { | |
304 put_v(bc, 6); /* type */ | |
305 put_b(bc, s->title, strlen(s->title)); | |
306 } | |
307 if (s->comment[0]) | |
308 { | |
309 put_v(bc, 7); /* type */ | |
310 put_b(bc, s->comment, strlen(s->comment)); | |
311 } | |
312 if (s->copyright[0]) | |
313 { | |
314 put_v(bc, 8); /* type */ | |
315 put_b(bc, s->copyright, strlen(s->copyright)); | |
316 } | |
317 /* encoder */ | |
318 put_v(bc, 9); /* type */ | |
222 | 319 put_b(bc, LIBAVFORMAT_IDENT "\0", strlen(LIBAVFORMAT_IDENT)); |
320 | |
321 put_v(bc, 0); /* eof info */ | |
219 | 322 |
220 | 323 put_be32(bc, 0); /* FIXME: checksum */ |
221 | 324 update_packetheader(nut, bc, 0); |
219 | 325 #endif |
326 | |
327 put_flush_packet(bc); | |
328 | |
329 return 0; | |
330 } | |
331 | |
332 static int nut_write_packet(AVFormatContext *s, int stream_index, | |
241 | 333 const uint8_t *buf, int size, int64_t pts) |
219 | 334 { |
335 NUTContext *nut = s->priv_data; | |
336 ByteIOContext *bc = &s->pb; | |
337 int key_frame = 0; | |
228 | 338 int flags; |
219 | 339 AVCodecContext *enc; |
340 | |
341 if (stream_index > s->nb_streams) | |
342 return 1; | |
343 | |
344 enc = &s->streams[stream_index]->codec; | |
240 | 345 key_frame = enc->coded_frame->key_frame; |
219 | 346 |
347 if (key_frame) | |
220 | 348 put_be64(bc, KEYFRAME_STARTCODE); |
349 | |
350 flags=0; | |
351 flags<<=2; flags|=1; //priority | |
352 flags<<=1; flags|=0; //checksum | |
353 flags<<=1; flags|=0; //msb_timestamp_flag | |
354 flags<<=2; flags|=1; //subpacket_type | |
355 flags<<=1; flags|=0; //reserved | |
356 | |
357 put_byte(bc, flags); | |
223 | 358 |
359 put_packetheader(nut, bc, size+20); | |
219 | 360 put_v(bc, stream_index); |
241 | 361 put_s(bc, pts); /* lsb_timestamp */ |
221 | 362 update_packetheader(nut, bc, size); |
219 | 363 |
364 put_buffer(bc, buf, size); | |
365 | |
366 put_flush_packet(bc); | |
367 | |
368 return 0; | |
369 } | |
370 | |
371 static int nut_write_trailer(AVFormatContext *s) | |
372 { | |
373 ByteIOContext *bc = &s->pb; | |
374 #if 0 | |
375 int i; | |
376 | |
377 /* WRITE INDEX */ | |
378 | |
379 for (i = 0; s->nb_streams; i++) | |
380 { | |
223 | 381 put_be64(bc, INDEX_STARTCODE); |
221 | 382 put_packetheader(nut, bc, 64); |
219 | 383 put_v(bc, s->streams[i]->id); |
384 put_v(bc, ...); | |
220 | 385 put_be32(bc, 0); /* FIXME: checksum */ |
221 | 386 update_packetheader(nut, bc, 0); |
219 | 387 } |
388 #endif | |
389 | |
390 put_flush_packet(bc); | |
391 | |
392 return 0; | |
393 } | |
394 | |
395 static int nut_probe(AVProbeData *p) | |
396 { | |
220 | 397 int i; |
398 uint64_t code; | |
399 | |
400 code = 0xff; | |
401 for (i = 0; i < p->buf_size; i++) { | |
402 int c = p->buf[i]; | |
403 code = (code << 8) | c; | |
404 if (code == MAIN_STARTCODE) | |
405 return AVPROBE_SCORE_MAX; | |
406 } | |
407 return 0; | |
219 | 408 } |
409 | |
410 static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap) | |
411 { | |
412 NUTContext *nut = s->priv_data; | |
413 ByteIOContext *bc = &s->pb; | |
220 | 414 uint64_t tmp; |
219 | 415 int cur_stream, nb_streams; |
416 | |
417 /* main header */ | |
220 | 418 tmp = get_be64(bc); |
419 if (tmp != MAIN_STARTCODE) | |
420 fprintf(stderr, "damaged? startcode!=1 (%Ld)\n", tmp); | |
223 | 421 get_packetheader(nut, bc); |
219 | 422 |
423 tmp = get_v(bc); | |
424 if (tmp != 0) | |
220 | 425 fprintf(stderr, "bad version (%Ld)\n", tmp); |
219 | 426 |
427 nb_streams = get_v(bc); | |
220 | 428 get_be32(bc); /* checkusm */ |
219 | 429 |
430 s->bit_rate = 0; | |
431 | |
432 /* stream header */ | |
433 for (cur_stream = 0; cur_stream < nb_streams; cur_stream++) | |
434 { | |
435 int class; | |
436 AVStream *st; | |
437 | |
220 | 438 tmp = get_be64(bc); |
439 if (tmp != STREAM_STARTCODE) | |
440 fprintf(stderr, "damaged? startcode!=1 (%Ld)\n", tmp); | |
223 | 441 get_packetheader(nut, bc); |
219 | 442 st = av_new_stream(s, get_v(bc)); |
443 if (!st) | |
444 return AVERROR_NOMEM; | |
445 class = get_v(bc); | |
240 | 446 tmp = get_bi(bc); |
219 | 447 switch(class) |
448 { | |
449 case 0: | |
450 st->codec.codec_type = CODEC_TYPE_VIDEO; | |
451 st->codec.codec_id = codec_get_bmp_id(tmp); | |
452 if (st->codec.codec_id == CODEC_ID_NONE) | |
453 fprintf(stderr, "Unknown codec?!\n"); | |
454 break; | |
455 case 32: | |
456 st->codec.codec_type = CODEC_TYPE_AUDIO; | |
457 st->codec.codec_id = codec_get_wav_id(tmp); | |
458 if (st->codec.codec_id == CODEC_ID_NONE) | |
459 fprintf(stderr, "Unknown codec?!\n"); | |
460 break; | |
461 default: | |
462 fprintf(stderr, "Unknown stream class (%d)\n", class); | |
463 return -1; | |
464 } | |
465 s->bit_rate += get_v(bc); | |
240 | 466 get_b(bc, NULL, 0); /* language code */ |
219 | 467 st->codec.frame_rate_base = get_v(bc); |
468 st->codec.frame_rate = get_v(bc); | |
469 get_v(bc); /* FIXME: msb timestamp base */ | |
470 get_v(bc); /* shuffle type */ | |
471 get_byte(bc); /* flags */ | |
472 | |
473 get_v(bc); /* FIXME: codec specific data headers */ | |
474 | |
475 if (class == 0) /* VIDEO */ | |
476 { | |
477 st->codec.width = get_v(bc); | |
478 st->codec.height = get_v(bc); | |
479 get_v(bc); /* aspected w */ | |
480 get_v(bc); /* aspected h */ | |
481 get_v(bc); /* csp type */ | |
240 | 482 get_be32(bc); /* checksum */ |
219 | 483 } |
484 if (class == 32) /* AUDIO */ | |
485 { | |
486 st->codec.sample_rate = get_v(bc) * (double)(st->codec.frame_rate_base / st->codec.frame_rate); | |
487 st->codec.channels = get_v(bc); | |
240 | 488 get_be32(bc); /* checksum */ |
219 | 489 } |
490 } | |
491 | |
492 return 0; | |
493 } | |
494 | |
495 static int nut_read_packet(AVFormatContext *s, AVPacket *pkt) | |
496 { | |
497 NUTContext *nut = s->priv_data; | |
498 ByteIOContext *bc = &s->pb; | |
220 | 499 int id, timestamp, size; |
219 | 500 int key_frame = 0; |
220 | 501 uint64_t tmp; |
219 | 502 |
503 | |
504 if (url_feof(bc)) | |
505 return -1; | |
506 | |
507 tmp = get_byte(bc); | |
220 | 508 if (tmp & 0x80) /* zero bit set? */ |
219 | 509 { |
220 | 510 tmp<<=8 ; tmp |= get_byte(bc); |
511 tmp<<=16; tmp |= get_be16(bc); | |
512 tmp<<=32; tmp |= get_be32(bc); | |
513 if (tmp == KEYFRAME_STARTCODE) | |
219 | 514 { |
515 key_frame = 1; | |
516 tmp = get_byte(bc); /* flags */ | |
517 } | |
518 else | |
220 | 519 fprintf(stderr, "error in zero bit / startcode %LX\n", tmp); |
219 | 520 } |
223 | 521 get_packetheader(nut, bc); |
220 | 522 #if 0 |
523 if (((tmp & 0x60)>>5) > 3) /* priority <= 3 */ | |
219 | 524 fprintf(stderr, "sanity check failed!\n"); |
220 | 525 #endif |
219 | 526 id = get_v(bc); |
527 timestamp = get_s(bc); | |
528 | |
529 size = (nut->curr_frame_size - (url_ftell(bc)-nut->curr_frame_start)); | |
220 | 530 dprintf("flags: 0x%Lx, timestamp: %d, packet size: %d\n", tmp, timestamp, size); |
219 | 531 |
532 if (size < 0) | |
533 return -1; | |
534 | |
535 av_new_packet(pkt, size); | |
536 get_buffer(bc, pkt->data, size); | |
537 pkt->stream_index = id; | |
538 if (key_frame) | |
539 pkt->flags |= PKT_FLAG_KEY; | |
540 pkt->pts = timestamp; | |
541 | |
542 return 0; | |
543 } | |
544 | |
545 static AVInputFormat nut_iformat = { | |
546 "nut", | |
547 "nut format", | |
548 sizeof(NUTContext), | |
549 nut_probe, | |
550 nut_read_header, | |
551 nut_read_packet, | |
552 // nut_read_close, | |
553 // nut_read_seek, | |
554 .extensions = "nut", | |
555 }; | |
556 | |
557 static AVOutputFormat nut_oformat = { | |
558 "nut", | |
559 "nut format", | |
560 "video/x-nut", | |
561 "nut", | |
562 sizeof(NUTContext), | |
563 #ifdef CONFIG_VORBIS | |
564 CODEC_ID_VORBIS, | |
565 #elif defined(CONFIG_MP3LAME) | |
232 | 566 CODEC_ID_MP3, |
219 | 567 #else |
223 | 568 CODEC_ID_MP2, /* AC3 needs liba52 decoder */ |
219 | 569 #endif |
570 CODEC_ID_MPEG4, | |
571 nut_write_header, | |
572 nut_write_packet, | |
573 nut_write_trailer, | |
574 }; | |
575 | |
576 int nut_init(void) | |
577 { | |
578 av_register_input_format(&nut_iformat); | |
579 av_register_output_format(&nut_oformat); | |
580 return 0; | |
581 } |