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