Mercurial > libavformat.hg
annotate nut.c @ 594:89a09ede50ad libavformat
First implementation of nsv demuxer.
Get libavformat linked with lavc and lmp3lame is required. BeOS requires no undefined syms on link! (besides it's bad to leave undef syms)
author | mmu_man |
---|---|
date | Sat, 20 Nov 2004 23:10:07 +0000 |
parents | fe24632a577b |
children | 0b52743104ac |
rev | line source |
---|---|
219 | 1 /* |
403 | 2 * "NUT" Container Format muxer and demuxer (DRAFT-200403??) |
219 | 3 * Copyright (c) 2003 Alex Beregszaszi |
403 | 4 * Copyright (c) 2004 Michael Niedermayer |
219 | 5 * |
6 * This library is free software; you can redistribute it and/or | |
7 * modify it under the terms of the GNU Lesser General Public | |
8 * License as published by the Free Software Foundation; either | |
9 * version 2 of the License, or (at your option) any later version. | |
10 * | |
11 * This library is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 * Lesser General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public | |
17 * License along with this library; if not, write to the Free Software | |
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 * | |
20 * NUT DRAFT can be found in MPlayer CVS at DOCS/tech/mpcf.txt | |
21 * | |
272 | 22 * AND http://people.fsn.hu/~alex/nut/ (TeX, pdf, ps, dvi, ..) |
219 | 23 * |
24 */ | |
25 | |
26 /* | |
27 * TODO: | |
28 * - index writing | |
415 | 29 * - index packet reading support |
219 | 30 */ |
31 | |
32 //#define DEBUG 1 | |
33 | |
403 | 34 #include <limits.h> |
219 | 35 #include "avformat.h" |
36 #include "mpegaudio.h" | |
228 | 37 #include "avi.h" |
219 | 38 |
403 | 39 #undef NDEBUG |
40 #include <assert.h> | |
41 | |
461 | 42 //#define TRACE |
43 | |
220 | 44 //from /dev/random |
45 | |
403 | 46 #define MAIN_STARTCODE (0x7A561F5F04ADULL + (((uint64_t)('N'<<8) + 'M')<<48)) |
47 #define STREAM_STARTCODE (0x11405BF2F9DBULL + (((uint64_t)('N'<<8) + 'S')<<48)) | |
48 #define KEYFRAME_STARTCODE (0xE4ADEECA4569ULL + (((uint64_t)('N'<<8) + 'K')<<48)) | |
49 #define INDEX_STARTCODE (0xDD672F23E64EULL + (((uint64_t)('N'<<8) + 'X')<<48)) | |
50 #define INFO_STARTCODE (0xAB68B596BA78ULL + (((uint64_t)('N'<<8) + 'I')<<48)) | |
51 | |
478 | 52 #define ID_STRING "nut/multimedia container\0" |
53 | |
456 | 54 #define MAX_DISTANCE (1024*16-1) |
55 #define MAX_SHORT_DISTANCE (1024*4-1) | |
403 | 56 |
461 | 57 #define FLAG_DATA_SIZE 1 |
58 #define FLAG_KEY_FRAME 2 | |
59 #define FLAG_INVALID 4 | |
403 | 60 |
61 typedef struct { | |
62 uint8_t flags; | |
63 uint8_t stream_id_plus1; | |
456 | 64 uint16_t size_mul; |
65 uint16_t size_lsb; | |
461 | 66 int16_t timestamp_delta; |
67 uint8_t reserved_count; | |
403 | 68 } FrameCode; |
69 | |
70 typedef struct { | |
71 int last_key_frame; | |
72 int msb_timestamp_shift; | |
73 int rate_num; | |
74 int rate_den; | |
75 int64_t last_pts; | |
426 | 76 int64_t last_sync_pos; ///<pos of last 1/2 type frame |
456 | 77 int decode_delay; |
403 | 78 } StreamContext; |
220 | 79 |
219 | 80 typedef struct { |
403 | 81 AVFormatContext *avf; |
82 int written_packet_size; | |
456 | 83 int64_t packet_start[3]; //0-> startcode less, 1-> short startcode 2-> long startcodes |
403 | 84 FrameCode frame_code[256]; |
419 | 85 int stream_count; |
421 | 86 uint64_t next_startcode; ///< stores the next startcode if it has alraedy been parsed but the stream isnt seekable |
403 | 87 StreamContext *stream; |
456 | 88 int max_distance; |
478 | 89 int max_short_distance; |
461 | 90 int rate_num; |
91 int rate_den; | |
92 int short_startcode; | |
219 | 93 } NUTContext; |
94 | |
415 | 95 static char *info_table[][2]={ |
96 {NULL , NULL }, // end | |
97 {NULL , NULL }, | |
98 {NULL , "UTF8"}, | |
99 {NULL , "v"}, | |
100 {NULL , "s"}, | |
101 {"StreamId" , "v"}, | |
102 {"SegmentId" , "v"}, | |
103 {"StartTimestamp" , "v"}, | |
104 {"EndTimestamp" , "v"}, | |
105 {"Author" , "UTF8"}, | |
416 | 106 {"Title" , "UTF8"}, |
415 | 107 {"Description" , "UTF8"}, |
108 {"Copyright" , "UTF8"}, | |
109 {"Encoder" , "UTF8"}, | |
110 {"Keyword" , "UTF8"}, | |
111 {"Cover" , "JPEG"}, | |
112 {"Cover" , "PNG"}, | |
113 }; | |
114 | |
403 | 115 static void update(NUTContext *nut, int stream_index, int64_t frame_start, int frame_type, int frame_code, int key_frame, int size, int64_t pts){ |
116 StreamContext *stream= &nut->stream[stream_index]; | |
117 | |
118 stream->last_key_frame= key_frame; | |
456 | 119 nut->packet_start[ frame_type ]= frame_start; |
403 | 120 stream->last_pts= pts; |
121 } | |
122 | |
461 | 123 static void reset(AVFormatContext *s, int64_t global_ts){ |
403 | 124 NUTContext *nut = s->priv_data; |
125 int i; | |
126 | |
127 for(i=0; i<s->nb_streams; i++){ | |
128 StreamContext *stream= &nut->stream[i]; | |
129 | |
130 stream->last_key_frame= 1; | |
461 | 131 |
132 stream->last_pts= av_rescale(global_ts, stream->rate_num*(int64_t)nut->rate_den, stream->rate_den*(int64_t)nut->rate_num); | |
403 | 133 } |
134 } | |
135 | |
136 static void build_frame_code(AVFormatContext *s){ | |
137 NUTContext *nut = s->priv_data; | |
461 | 138 int key_frame, index, pred, stream_id; |
403 | 139 int start=0; |
140 int end= 255; | |
141 int keyframe_0_esc= s->nb_streams > 2; | |
461 | 142 int pred_table[10]; |
403 | 143 |
144 if(keyframe_0_esc){ | |
456 | 145 /* keyframe = 0 escape */ |
146 FrameCode *ft= &nut->frame_code[start]; | |
461 | 147 ft->flags= FLAG_DATA_SIZE; |
456 | 148 ft->stream_id_plus1= 0; |
149 ft->size_mul=1; | |
461 | 150 ft->timestamp_delta=0; |
456 | 151 start++; |
403 | 152 } |
153 | |
154 for(stream_id= 0; stream_id<s->nb_streams; stream_id++){ | |
155 int start2= start + (end-start)*stream_id / s->nb_streams; | |
156 int end2 = start + (end-start)*(stream_id+1) / s->nb_streams; | |
157 AVCodecContext *codec = &s->streams[stream_id]->codec; | |
158 int is_audio= codec->codec_type == CODEC_TYPE_AUDIO; | |
159 int intra_only= /*codec->intra_only || */is_audio; | |
160 int pred_count; | |
161 | |
162 for(key_frame=0; key_frame<2; key_frame++){ | |
163 if(intra_only && keyframe_0_esc && key_frame==0) | |
164 continue; | |
165 | |
456 | 166 { |
167 FrameCode *ft= &nut->frame_code[start2]; | |
168 ft->flags= FLAG_KEY_FRAME*key_frame; | |
461 | 169 ft->flags|= FLAG_DATA_SIZE; |
456 | 170 ft->stream_id_plus1= stream_id + 1; |
171 ft->size_mul=1; | |
461 | 172 ft->timestamp_delta=0; |
456 | 173 start2++; |
403 | 174 } |
175 } | |
176 | |
177 key_frame= intra_only; | |
178 #if 1 | |
179 if(is_audio){ | |
180 int frame_bytes= codec->frame_size*(int64_t)codec->bit_rate / (8*codec->sample_rate); | |
461 | 181 int pts; |
182 for(pts=0; pts<2; pts++){ | |
456 | 183 for(pred=0; pred<2; pred++){ |
403 | 184 FrameCode *ft= &nut->frame_code[start2]; |
461 | 185 ft->flags= FLAG_KEY_FRAME*key_frame; |
403 | 186 ft->stream_id_plus1= stream_id + 1; |
456 | 187 ft->size_mul=frame_bytes + 2; |
188 ft->size_lsb=frame_bytes + pred; | |
461 | 189 ft->timestamp_delta=pts; |
403 | 190 start2++; |
191 } | |
192 } | |
193 }else{ | |
194 FrameCode *ft= &nut->frame_code[start2]; | |
195 ft->flags= FLAG_KEY_FRAME | FLAG_DATA_SIZE; | |
196 ft->stream_id_plus1= stream_id + 1; | |
197 ft->size_mul=1; | |
461 | 198 ft->timestamp_delta=1; |
403 | 199 start2++; |
200 } | |
201 #endif | |
461 | 202 |
203 if(codec->has_b_frames){ | |
204 pred_count=5; | |
205 pred_table[0]=-2; | |
206 pred_table[1]=-1; | |
207 pred_table[2]=1; | |
208 pred_table[3]=3; | |
209 pred_table[4]=4; | |
210 }else if(codec->codec_id == CODEC_ID_VORBIS){ | |
211 pred_count=3; | |
212 pred_table[0]=2; | |
213 pred_table[1]=9; | |
214 pred_table[2]=16; | |
215 }else{ | |
216 pred_count=1; | |
217 pred_table[0]=1; | |
218 } | |
219 | |
403 | 220 for(pred=0; pred<pred_count; pred++){ |
221 int start3= start2 + (end2-start2)*pred / pred_count; | |
222 int end3 = start2 + (end2-start2)*(pred+1) / pred_count; | |
223 | |
224 for(index=start3; index<end3; index++){ | |
225 FrameCode *ft= &nut->frame_code[index]; | |
461 | 226 ft->flags= FLAG_KEY_FRAME*key_frame; |
403 | 227 ft->flags|= FLAG_DATA_SIZE; |
228 ft->stream_id_plus1= stream_id + 1; | |
229 //FIXME use single byte size and pred from last | |
230 ft->size_mul= end3-start3; | |
231 ft->size_lsb= index - start3; | |
461 | 232 ft->timestamp_delta= pred_table[pred]; |
403 | 233 } |
234 } | |
235 } | |
236 memmove(&nut->frame_code['N'+1], &nut->frame_code['N'], sizeof(FrameCode)*(255-'N')); | |
461 | 237 nut->frame_code['N'].flags= FLAG_INVALID; |
403 | 238 } |
239 | |
219 | 240 static uint64_t get_v(ByteIOContext *bc) |
241 { | |
242 uint64_t val = 0; | |
243 | |
421 | 244 for(;;) |
219 | 245 { |
246 int tmp = get_byte(bc); | |
247 | |
248 if (tmp&0x80) | |
249 val= (val<<7) + tmp - 0x80; | |
456 | 250 else{ |
251 //av_log(NULL, AV_LOG_DEBUG, "get_v()= %lld\n", (val<<7) + tmp); | |
219 | 252 return (val<<7) + tmp; |
456 | 253 } |
219 | 254 } |
255 return -1; | |
256 } | |
257 | |
415 | 258 static int get_str(ByteIOContext *bc, char *string, int maxlen){ |
259 int len= get_v(bc); | |
219 | 260 |
415 | 261 if(len && maxlen) |
262 get_buffer(bc, string, FFMIN(len, maxlen)); | |
263 while(len > maxlen){ | |
264 get_byte(bc); | |
265 len--; | |
266 } | |
240 | 267 |
415 | 268 if(maxlen) |
269 string[FFMIN(len, maxlen-1)]= 0; | |
240 | 270 |
415 | 271 if(maxlen == len) |
272 return -1; | |
273 else | |
274 return 0; | |
219 | 275 } |
276 | |
461 | 277 static int64_t get_s(ByteIOContext *bc){ |
278 int64_t v = get_v(bc) + 1; | |
279 | |
280 if (v&1) return -(v>>1); | |
281 else return (v>>1); | |
282 } | |
283 | |
426 | 284 static uint64_t get_vb(ByteIOContext *bc){ |
285 uint64_t val=0; | |
286 int i= get_v(bc); | |
287 | |
288 if(i>8) | |
289 return UINT64_MAX; | |
290 | |
291 while(i--) | |
292 val = (val<<8) + get_byte(bc); | |
293 | |
456 | 294 //av_log(NULL, AV_LOG_DEBUG, "get_vb()= %lld\n", val); |
426 | 295 return val; |
296 } | |
297 | |
461 | 298 #ifdef TRACE |
299 static inline uint64_t get_v_trace(ByteIOContext *bc, char *file, char *func, int line){ | |
300 uint64_t v= get_v(bc); | |
301 | |
302 printf("get_v %5lld / %llX in %s %s:%d\n", v, v, file, func, line); | |
303 return v; | |
304 } | |
305 | |
306 static inline int64_t get_s_trace(ByteIOContext *bc, char *file, char *func, int line){ | |
307 int64_t v= get_s(bc); | |
308 | |
309 printf("get_s %5lld / %llX in %s %s:%d\n", v, v, file, func, line); | |
310 return v; | |
311 } | |
312 | |
313 static inline uint64_t get_vb_trace(ByteIOContext *bc, char *file, char *func, int line){ | |
314 uint64_t v= get_vb(bc); | |
315 | |
316 printf("get_vb %5lld / %llX in %s %s:%d\n", v, v, file, func, line); | |
317 return v; | |
318 } | |
319 #define get_v(bc) get_v_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__) | |
320 #define get_s(bc) get_s_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__) | |
321 #define get_vb(bc) get_vb_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__) | |
322 #endif | |
323 | |
324 | |
456 | 325 static int get_packetheader(NUTContext *nut, ByteIOContext *bc, int calculate_checksum) |
219 | 326 { |
456 | 327 int64_t start, size; |
328 start= url_ftell(bc) - 8; | |
403 | 329 |
421 | 330 init_checksum(bc, calculate_checksum ? update_adler32 : NULL, 0); |
403 | 331 |
332 size= get_v(bc); | |
333 | |
456 | 334 nut->packet_start[2] = start; |
403 | 335 nut->written_packet_size= size; |
336 | |
337 return size; | |
219 | 338 } |
339 | |
418
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
340 static int check_checksum(ByteIOContext *bc){ |
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
341 unsigned long checksum= get_checksum(bc); |
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
342 return checksum != get_be32(bc); |
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
343 } |
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
344 |
221 | 345 /** |
346 * | |
347 */ | |
348 static int get_length(uint64_t val){ | |
349 int i; | |
219 | 350 |
426 | 351 for (i=7; val>>i; i+=7); |
219 | 352 |
426 | 353 return i; |
219 | 354 } |
355 | |
419 | 356 static uint64_t find_any_startcode(ByteIOContext *bc, int64_t pos){ |
357 uint64_t state=0; | |
358 | |
359 if(pos >= 0) | |
360 url_fseek(bc, pos, SEEK_SET); //note, this may fail if the stream isnt seekable, but that shouldnt matter, as in this case we simply start where we are currently | |
361 | |
421 | 362 while(!url_feof(bc)){ |
419 | 363 state= (state<<8) | get_byte(bc); |
364 if((state>>56) != 'N') | |
365 continue; | |
366 switch(state){ | |
367 case MAIN_STARTCODE: | |
368 case STREAM_STARTCODE: | |
369 case KEYFRAME_STARTCODE: | |
370 case INFO_STARTCODE: | |
371 case INDEX_STARTCODE: | |
372 return state; | |
373 } | |
374 } | |
426 | 375 |
419 | 376 return 0; |
377 } | |
378 | |
426 | 379 /** |
380 * find the given startcode. | |
381 * @param code the startcode | |
382 * @param pos the start position of the search, or -1 if the current position | |
383 * @returns the position of the startcode or -1 if not found | |
384 */ | |
385 static int64_t find_startcode(ByteIOContext *bc, uint64_t code, int64_t pos){ | |
419 | 386 for(;;){ |
387 uint64_t startcode= find_any_startcode(bc, pos); | |
388 if(startcode == code) | |
426 | 389 return url_ftell(bc) - 8; |
419 | 390 else if(startcode == 0) |
391 return -1; | |
392 pos=-1; | |
393 } | |
394 } | |
395 | |
277
a313e1080322
disable encoders where appropriate (patch courtesy of BERO
melanson
parents:
272
diff
changeset
|
396 #ifdef CONFIG_ENCODERS |
461 | 397 |
426 | 398 static void put_v(ByteIOContext *bc, uint64_t val) |
219 | 399 { |
400 int i; | |
401 | |
456 | 402 //av_log(NULL, AV_LOG_DEBUG, "put_v()= %lld\n", val); |
219 | 403 val &= 0x7FFFFFFFFFFFFFFFULL; // FIXME can only encode upto 63 bits currently |
221 | 404 i= get_length(val); |
219 | 405 |
220 | 406 for (i-=7; i>0; i-=7){ |
219 | 407 put_byte(bc, 0x80 | (val>>i)); |
220 | 408 } |
219 | 409 |
410 put_byte(bc, val&0x7f); | |
411 } | |
412 | |
426 | 413 /** |
414 * stores a string as vb. | |
415 */ | |
416 static void put_str(ByteIOContext *bc, const char *string){ | |
415 | 417 int len= strlen(string); |
219 | 418 |
419 put_v(bc, len); | |
415 | 420 put_buffer(bc, string, len); |
426 | 421 } |
422 | |
461 | 423 static void put_s(ByteIOContext *bc, uint64_t val){ |
424 if (val<=0) put_v(bc, -2*val ); | |
425 else put_v(bc, 2*val-1); | |
426 } | |
427 | |
426 | 428 static void put_vb(ByteIOContext *bc, uint64_t val){ |
429 int i; | |
415 | 430 |
426 | 431 for (i=8; val>>i; i+=8); |
432 | |
433 put_v(bc, i>>3); | |
434 for(i-=8; i>=0; i-=8) | |
435 put_byte(bc, (val>>i)&0xFF); | |
228 | 436 } |
437 | |
461 | 438 #ifdef TRACE |
439 static inline void put_v_trace(ByteIOContext *bc, uint64_t v, char *file, char *func, int line){ | |
440 printf("get_v %5lld / %llX in %s %s:%d\n", v, v, file, func, line); | |
441 | |
442 put_v(bc, v); | |
443 } | |
444 | |
445 static inline void put_s_trace(ByteIOContext *bc, int64_t v, char *file, char *func, int line){ | |
446 printf("get_s %5lld / %llX in %s %s:%d\n", v, v, file, func, line); | |
447 | |
448 put_s(bc, v); | |
449 } | |
450 | |
451 static inline void put_vb_trace(ByteIOContext *bc, uint64_t v, char *file, char *func, int line){ | |
452 printf("get_vb %5lld / %llX in %s %s:%d\n", v, v, file, func, line); | |
453 | |
454 put_vb(bc, v); | |
455 } | |
456 #define put_v(bc, v) put_v_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__) | |
457 #define put_s(bc, v) put_s_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__) | |
458 #define put_vb(bc, v) put_vb_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__) | |
459 #endif | |
460 | |
418
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
461 static int put_packetheader(NUTContext *nut, ByteIOContext *bc, int max_size, int calculate_checksum) |
219 | 462 { |
463 put_flush_packet(bc); | |
456 | 464 nut->packet_start[2]+= nut->written_packet_size; |
465 assert(url_ftell(bc) - 8 == nut->packet_start[2]); | |
403 | 466 nut->written_packet_size = max_size; |
418
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
467 |
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
468 if(calculate_checksum) |
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
469 init_checksum(bc, update_adler32, 0); |
403 | 470 |
219 | 471 /* packet header */ |
403 | 472 put_v(bc, nut->written_packet_size); /* forward ptr */ |
219 | 473 |
474 return 0; | |
475 } | |
476 | |
418
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
477 static int update_packetheader(NUTContext *nut, ByteIOContext *bc, int additional_size, int calculate_checksum){ |
456 | 478 int64_t start= nut->packet_start[2]; |
403 | 479 int64_t cur= url_ftell(bc); |
221 | 480 int size= cur - start + additional_size; |
481 | |
418
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
482 if(calculate_checksum) |
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
483 size += 4; |
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
484 |
403 | 485 if(size != nut->written_packet_size){ |
486 int i; | |
487 | |
488 assert( size <= nut->written_packet_size ); | |
219 | 489 |
456 | 490 url_fseek(bc, start + 8, SEEK_SET); |
403 | 491 for(i=get_length(size); i < get_length(nut->written_packet_size); i+=7) |
492 put_byte(bc, 0x80); | |
493 put_v(bc, size); | |
219 | 494 |
403 | 495 url_fseek(bc, cur, SEEK_SET); |
496 nut->written_packet_size= size; //FIXME may fail if multiple updates with differing sizes, as get_length may differ | |
418
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
497 |
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
498 if(calculate_checksum) |
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
499 put_be32(bc, get_checksum(bc)); |
403 | 500 } |
221 | 501 |
219 | 502 return 0; |
503 } | |
504 | |
505 static int nut_write_header(AVFormatContext *s) | |
506 { | |
507 NUTContext *nut = s->priv_data; | |
508 ByteIOContext *bc = &s->pb; | |
509 AVCodecContext *codec; | |
461 | 510 int i, j, tmp_time, tmp_flags,tmp_stream, tmp_mul, tmp_size, tmp_fields; |
219 | 511 |
403 | 512 nut->avf= s; |
513 | |
514 nut->stream = | |
515 av_mallocz(sizeof(StreamContext)*s->nb_streams); | |
478 | 516 |
517 | |
518 put_buffer(bc, ID_STRING, strlen(ID_STRING)); | |
519 put_byte(bc, 0); | |
520 nut->packet_start[2]= url_ftell(bc); | |
403 | 521 |
219 | 522 /* main header */ |
220 | 523 put_be64(bc, MAIN_STARTCODE); |
418
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
524 put_packetheader(nut, bc, 120+5*256, 1); |
456 | 525 put_v(bc, 2); /* version */ |
219 | 526 put_v(bc, s->nb_streams); |
456 | 527 put_v(bc, MAX_DISTANCE); |
478 | 528 put_v(bc, MAX_SHORT_DISTANCE); |
403 | 529 |
461 | 530 put_v(bc, nut->rate_num=1); |
531 put_v(bc, nut->rate_den=2); | |
532 put_v(bc, nut->short_startcode=0x4EFE79); | |
533 | |
403 | 534 build_frame_code(s); |
461 | 535 assert(nut->frame_code['N'].flags == FLAG_INVALID); |
536 | |
537 tmp_time= tmp_flags= tmp_stream= tmp_mul= tmp_size= /*tmp_res=*/ INT_MAX; | |
403 | 538 for(i=0; i<256;){ |
461 | 539 tmp_fields=0; |
540 tmp_size= 0; | |
541 if(tmp_time != nut->frame_code[i].timestamp_delta) tmp_fields=1; | |
542 if(tmp_mul != nut->frame_code[i].size_mul ) tmp_fields=2; | |
543 if(tmp_stream != nut->frame_code[i].stream_id_plus1) tmp_fields=3; | |
544 if(tmp_size != nut->frame_code[i].size_lsb ) tmp_fields=4; | |
545 // if(tmp_res != nut->frame_code[i].res ) tmp_fields=5; | |
403 | 546 |
461 | 547 tmp_time = nut->frame_code[i].timestamp_delta; |
548 tmp_flags = nut->frame_code[i].flags; | |
549 tmp_stream= nut->frame_code[i].stream_id_plus1; | |
550 tmp_mul = nut->frame_code[i].size_mul; | |
551 tmp_size = nut->frame_code[i].size_lsb; | |
552 // tmp_res = nut->frame_code[i].res; | |
553 | |
403 | 554 for(j=0; i<256; j++,i++){ |
461 | 555 if(nut->frame_code[i].timestamp_delta != tmp_time ) break; |
403 | 556 if(nut->frame_code[i].flags != tmp_flags ) break; |
557 if(nut->frame_code[i].stream_id_plus1 != tmp_stream) break; | |
558 if(nut->frame_code[i].size_mul != tmp_mul ) break; | |
461 | 559 if(nut->frame_code[i].size_lsb != tmp_size+j) break; |
560 // if(nut->frame_code[i].res != tmp_res ) break; | |
403 | 561 } |
461 | 562 if(j != tmp_mul - tmp_size) tmp_fields=6; |
563 | |
564 put_v(bc, tmp_flags); | |
565 put_v(bc, tmp_fields); | |
566 if(tmp_fields>0) put_s(bc, tmp_time); | |
567 if(tmp_fields>1) put_v(bc, tmp_mul); | |
568 if(tmp_fields>2) put_v(bc, tmp_stream); | |
569 if(tmp_fields>3) put_v(bc, tmp_size); | |
570 if(tmp_fields>4) put_v(bc, 0 /*tmp_res*/); | |
571 if(tmp_fields>5) put_v(bc, j); | |
403 | 572 } |
573 | |
418
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
574 update_packetheader(nut, bc, 0, 1); |
221 | 575 |
219 | 576 /* stream headers */ |
577 for (i = 0; i < s->nb_streams; i++) | |
578 { | |
403 | 579 int nom, denom, gcd; |
271 | 580 |
219 | 581 codec = &s->streams[i]->codec; |
582 | |
223 | 583 put_be64(bc, STREAM_STARTCODE); |
418
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
584 put_packetheader(nut, bc, 120 + codec->extradata_size, 1); |
222 | 585 put_v(bc, i /*s->streams[i]->index*/); |
219 | 586 put_v(bc, (codec->codec_type == CODEC_TYPE_AUDIO) ? 32 : 0); |
587 if (codec->codec_tag) | |
426 | 588 put_vb(bc, codec->codec_tag); |
219 | 589 else if (codec->codec_type == CODEC_TYPE_VIDEO) |
590 { | |
426 | 591 put_vb(bc, codec_get_bmp_tag(codec->codec_id)); |
219 | 592 } |
593 else if (codec->codec_type == CODEC_TYPE_AUDIO) | |
594 { | |
426 | 595 put_vb(bc, codec_get_wav_tag(codec->codec_id)); |
282 | 596 } |
415 | 597 else |
426 | 598 put_vb(bc, 0); |
282 | 599 |
600 if (codec->codec_type == CODEC_TYPE_VIDEO) | |
601 { | |
602 nom = codec->frame_rate; | |
603 denom = codec->frame_rate_base; | |
604 } | |
605 else | |
606 { | |
403 | 607 nom = codec->sample_rate; |
608 if(codec->frame_size>0) | |
609 denom= codec->frame_size; | |
610 else | |
611 denom= 1; //unlucky | |
219 | 612 } |
403 | 613 gcd= ff_gcd(nom, denom); |
614 nom /= gcd; | |
615 denom /= gcd; | |
616 nut->stream[i].rate_num= nom; | |
617 nut->stream[i].rate_den= denom; | |
463
696f41bc8784
store index for seeking in the native timebase of each stream
michael
parents:
462
diff
changeset
|
618 av_set_pts_info(s->streams[i], 60, denom, nom); |
403 | 619 |
219 | 620 put_v(bc, codec->bit_rate); |
426 | 621 put_vb(bc, 0); /* no language code */ |
271 | 622 put_v(bc, nom); |
623 put_v(bc, denom); | |
403 | 624 if(nom / denom < 1000) |
625 nut->stream[i].msb_timestamp_shift = 7; | |
626 else | |
627 nut->stream[i].msb_timestamp_shift = 14; | |
628 put_v(bc, nut->stream[i].msb_timestamp_shift); | |
456 | 629 put_v(bc, codec->has_b_frames); |
219 | 630 put_byte(bc, 0); /* flags: 0x1 - fixed_fps, 0x2 - index_present */ |
631 | |
403 | 632 if(codec->extradata_size){ |
633 put_v(bc, 1); | |
634 put_v(bc, codec->extradata_size); | |
635 put_buffer(bc, codec->extradata, codec->extradata_size); | |
636 } | |
637 put_v(bc, 0); /* end of codec specific headers */ | |
219 | 638 |
639 switch(codec->codec_type) | |
640 { | |
641 case CODEC_TYPE_AUDIO: | |
456 | 642 put_v(bc, codec->sample_rate); |
643 put_v(bc, 1); | |
219 | 644 put_v(bc, codec->channels); |
645 break; | |
646 case CODEC_TYPE_VIDEO: | |
647 put_v(bc, codec->width); | |
648 put_v(bc, codec->height); | |
403 | 649 put_v(bc, codec->sample_aspect_ratio.num); |
650 put_v(bc, codec->sample_aspect_ratio.den); | |
219 | 651 put_v(bc, 0); /* csp type -- unknown */ |
652 break; | |
228 | 653 default: |
654 break; | |
219 | 655 } |
418
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
656 update_packetheader(nut, bc, 0, 1); |
219 | 657 } |
658 | |
659 /* info header */ | |
223 | 660 put_be64(bc, INFO_STARTCODE); |
415 | 661 put_packetheader(nut, bc, 30+strlen(s->author)+strlen(s->title)+ |
418
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
662 strlen(s->comment)+strlen(s->copyright)+strlen(LIBAVFORMAT_IDENT), 1); |
219 | 663 if (s->author[0]) |
664 { | |
415 | 665 put_v(bc, 9); /* type */ |
666 put_str(bc, s->author); | |
219 | 667 } |
668 if (s->title[0]) | |
669 { | |
415 | 670 put_v(bc, 10); /* type */ |
671 put_str(bc, s->title); | |
219 | 672 } |
673 if (s->comment[0]) | |
674 { | |
415 | 675 put_v(bc, 11); /* type */ |
676 put_str(bc, s->comment); | |
219 | 677 } |
678 if (s->copyright[0]) | |
679 { | |
415 | 680 put_v(bc, 12); /* type */ |
681 put_str(bc, s->copyright); | |
219 | 682 } |
683 /* encoder */ | |
441 | 684 if(!(s->streams[0]->codec.flags & CODEC_FLAG_BITEXACT)){ |
685 put_v(bc, 13); /* type */ | |
686 put_str(bc, LIBAVFORMAT_IDENT); | |
687 } | |
222 | 688 |
689 put_v(bc, 0); /* eof info */ | |
418
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
690 update_packetheader(nut, bc, 0, 1); |
219 | 691 |
692 put_flush_packet(bc); | |
693 | |
694 return 0; | |
695 } | |
696 | |
456 | 697 static int64_t lsb2full(StreamContext *stream, int64_t lsb){ |
698 int64_t mask = (1<<stream->msb_timestamp_shift)-1; | |
699 int64_t delta= stream->last_pts - mask/2; | |
700 return ((lsb - delta)&mask) + delta; | |
701 } | |
702 | |
468 | 703 static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) |
219 | 704 { |
705 NUTContext *nut = s->priv_data; | |
468 | 706 StreamContext *stream= &nut->stream[pkt->stream_index]; |
219 | 707 ByteIOContext *bc = &s->pb; |
403 | 708 int key_frame = 0, full_pts=0; |
219 | 709 AVCodecContext *enc; |
456 | 710 int64_t coded_pts; |
461 | 711 int frame_type, best_length, frame_code, flags, i, size_mul, size_lsb, time_delta; |
403 | 712 const int64_t frame_start= url_ftell(bc); |
468 | 713 int64_t pts= pkt->pts; |
714 int size= pkt->size; | |
715 int stream_index= pkt->stream_index; | |
219 | 716 |
717 enc = &s->streams[stream_index]->codec; | |
468 | 718 key_frame = !!(pkt->flags & PKT_FLAG_KEY); |
403 | 719 |
720 frame_type=0; | |
456 | 721 if(frame_start + size + 20 - FFMAX(nut->packet_start[1], nut->packet_start[2]) > MAX_DISTANCE) |
722 frame_type=2; | |
723 if(key_frame && !stream->last_key_frame) | |
724 frame_type=2; | |
725 | |
461 | 726 if(frame_type>1){ |
727 int64_t global_ts= av_rescale(pts, stream->rate_den*(int64_t)nut->rate_num, stream->rate_num*(int64_t)nut->rate_den); | |
728 reset(s, global_ts); | |
729 put_be64(bc, KEYFRAME_STARTCODE); | |
730 put_v(bc, global_ts); | |
731 } | |
732 assert(stream->last_pts != AV_NOPTS_VALUE); | |
733 coded_pts = pts & ((1<<stream->msb_timestamp_shift)-1); | |
734 if(lsb2full(stream, coded_pts) != pts) | |
456 | 735 full_pts=1; |
328 | 736 |
456 | 737 if(full_pts) |
738 coded_pts= pts + (1<<stream->msb_timestamp_shift); | |
403 | 739 |
740 best_length=INT_MAX; | |
741 frame_code= -1; | |
742 for(i=0; i<256; i++){ | |
743 int stream_id_plus1= nut->frame_code[i].stream_id_plus1; | |
429
983639863758
removing keyframe prediction and checksum threshold
michael
parents:
427
diff
changeset
|
744 int fc_key_frame; |
403 | 745 int length=0; |
746 size_mul= nut->frame_code[i].size_mul; | |
747 size_lsb= nut->frame_code[i].size_lsb; | |
461 | 748 time_delta= nut->frame_code[i].timestamp_delta; |
403 | 749 flags= nut->frame_code[i].flags; |
750 | |
456 | 751 assert(size_mul > size_lsb); |
752 | |
403 | 753 if(stream_id_plus1 == 0) length+= get_length(stream_index); |
754 else if(stream_id_plus1 - 1 != stream_index) | |
755 continue; | |
429
983639863758
removing keyframe prediction and checksum threshold
michael
parents:
427
diff
changeset
|
756 fc_key_frame= !!(flags & FLAG_KEY_FRAME); |
983639863758
removing keyframe prediction and checksum threshold
michael
parents:
427
diff
changeset
|
757 |
403 | 758 assert(key_frame==0 || key_frame==1); |
759 if(fc_key_frame != key_frame) | |
760 continue; | |
761 | |
456 | 762 if(flags & FLAG_DATA_SIZE){ |
403 | 763 if(size % size_mul != size_lsb) |
764 continue; | |
456 | 765 length += get_length(size / size_mul); |
766 }else if(size != size_lsb) | |
767 continue; | |
220 | 768 |
461 | 769 if(full_pts && time_delta) |
403 | 770 continue; |
771 | |
461 | 772 if(!time_delta){ |
456 | 773 length += get_length(coded_pts); |
403 | 774 }else{ |
461 | 775 if(time_delta != pts - stream->last_pts) |
403 | 776 continue; |
777 } | |
778 | |
779 if(length < best_length){ | |
780 best_length= length; | |
781 frame_code=i; | |
782 } | |
783 // av_log(s, AV_LOG_DEBUG, "%d %d %d %d %d %d %d %d %d %d\n", key_frame, frame_type, full_pts, size, stream_index, flags, size_mul, size_lsb, stream_id_plus1, length); | |
784 } | |
223 | 785 |
403 | 786 assert(frame_code != -1); |
787 flags= nut->frame_code[frame_code].flags; | |
788 size_mul= nut->frame_code[frame_code].size_mul; | |
789 size_lsb= nut->frame_code[frame_code].size_lsb; | |
461 | 790 time_delta= nut->frame_code[frame_code].timestamp_delta; |
791 #ifdef TRACE | |
403 | 792 best_length /= 7; |
793 best_length ++; //frame_code | |
456 | 794 if(frame_type==2){ |
795 best_length += 8; // startcode | |
403 | 796 } |
461 | 797 av_log(s, AV_LOG_DEBUG, "kf:%d ft:%d pt:%d fc:%2X len:%2d size:%d stream:%d flag:%d mul:%d lsb:%d s+1:%d pts_delta:%d pts:%lld fs:%lld\n", key_frame, frame_type, full_pts ? 1 : 0, frame_code, best_length, size, stream_index, flags, size_mul, size_lsb, nut->frame_code[frame_code].stream_id_plus1,(int)(pts - stream->last_pts), pts, frame_start); |
456 | 798 // av_log(s, AV_LOG_DEBUG, "%d %d %d\n", stream->lru_pts_delta[0], stream->lru_pts_delta[1], stream->lru_pts_delta[2]); |
403 | 799 #endif |
800 | |
456 | 801 assert(frame_type != 1); //short startcode not implemented yet |
403 | 802 put_byte(bc, frame_code); |
803 | |
804 if(nut->frame_code[frame_code].stream_id_plus1 == 0) | |
805 put_v(bc, stream_index); | |
461 | 806 if (!time_delta){ |
456 | 807 put_v(bc, coded_pts); |
403 | 808 } |
809 if(flags & FLAG_DATA_SIZE) | |
810 put_v(bc, size / size_mul); | |
461 | 811 else |
812 assert(size == size_lsb); | |
456 | 813 if(size > MAX_DISTANCE){ |
814 assert(frame_type > 1); | |
403 | 815 } |
219 | 816 |
468 | 817 put_buffer(bc, pkt->data, size); |
403 | 818 |
819 update(nut, stream_index, frame_start, frame_type, frame_code, key_frame, size, pts); | |
219 | 820 |
821 return 0; | |
822 } | |
823 | |
824 static int nut_write_trailer(AVFormatContext *s) | |
825 { | |
328 | 826 NUTContext *nut = s->priv_data; |
219 | 827 ByteIOContext *bc = &s->pb; |
403 | 828 |
219 | 829 #if 0 |
830 int i; | |
831 | |
832 /* WRITE INDEX */ | |
833 | |
834 for (i = 0; s->nb_streams; i++) | |
835 { | |
223 | 836 put_be64(bc, INDEX_STARTCODE); |
418
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
837 put_packetheader(nut, bc, 64, 1); |
219 | 838 put_v(bc, s->streams[i]->id); |
839 put_v(bc, ...); | |
418
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
840 update_packetheader(nut, bc, 0, 1); |
219 | 841 } |
842 #endif | |
843 | |
844 put_flush_packet(bc); | |
328 | 845 |
403 | 846 av_freep(&nut->stream); |
219 | 847 |
848 return 0; | |
849 } | |
277
a313e1080322
disable encoders where appropriate (patch courtesy of BERO
melanson
parents:
272
diff
changeset
|
850 #endif //CONFIG_ENCODERS |
219 | 851 |
852 static int nut_probe(AVProbeData *p) | |
853 { | |
220 | 854 int i; |
456 | 855 uint64_t code= 0xff; |
220 | 856 |
857 for (i = 0; i < p->buf_size; i++) { | |
456 | 858 code = (code << 8) | p->buf[i]; |
220 | 859 if (code == MAIN_STARTCODE) |
860 return AVPROBE_SCORE_MAX; | |
861 } | |
862 return 0; | |
219 | 863 } |
864 | |
419 | 865 static int decode_main_header(NUTContext *nut){ |
866 AVFormatContext *s= nut->avf; | |
219 | 867 ByteIOContext *bc = &s->pb; |
220 | 868 uint64_t tmp; |
461 | 869 int i, j, tmp_stream, tmp_mul, tmp_time, tmp_size, count, tmp_res; |
219 | 870 |
456 | 871 get_packetheader(nut, bc, 1); |
403 | 872 |
419 | 873 tmp = get_v(bc); |
456 | 874 if (tmp != 2){ |
419 | 875 av_log(s, AV_LOG_ERROR, "bad version (%Ld)\n", tmp); |
876 return -1; | |
877 } | |
219 | 878 |
419 | 879 nut->stream_count = get_v(bc); |
456 | 880 nut->max_distance = get_v(bc); |
478 | 881 nut->max_short_distance = get_v(bc); |
461 | 882 nut->rate_num= get_v(bc); |
883 nut->rate_den= get_v(bc); | |
884 nut->short_startcode= get_v(bc); | |
885 if(nut->short_startcode>>16 != 'N'){ | |
886 av_log(s, AV_LOG_ERROR, "invalid short startcode %X\n", nut->short_startcode); | |
887 return -1; | |
888 } | |
456 | 889 |
403 | 890 for(i=0; i<256;){ |
891 int tmp_flags = get_v(bc); | |
461 | 892 int tmp_fields= get_v(bc); |
893 if(tmp_fields>0) tmp_time = get_s(bc); | |
894 if(tmp_fields>1) tmp_mul = get_v(bc); | |
895 if(tmp_fields>2) tmp_stream= get_v(bc); | |
896 if(tmp_fields>3) tmp_size = get_v(bc); | |
897 else tmp_size = 0; | |
898 if(tmp_fields>4) tmp_res = get_v(bc); | |
899 else tmp_res = 0; | |
900 if(tmp_fields>5) count = get_v(bc); | |
901 else count = tmp_mul - tmp_size; | |
902 | |
903 while(tmp_fields-- > 6) | |
904 get_v(bc); | |
905 | |
403 | 906 if(count == 0 || i+count > 256){ |
907 av_log(s, AV_LOG_ERROR, "illegal count %d at %d\n", count, i); | |
908 return -1; | |
909 } | |
461 | 910 if(tmp_stream > nut->stream_count + 1){ |
911 av_log(s, AV_LOG_ERROR, "illegal stream number\n"); | |
912 return -1; | |
913 } | |
403 | 914 |
915 for(j=0; j<count; j++,i++){ | |
916 nut->frame_code[i].flags = tmp_flags ; | |
461 | 917 nut->frame_code[i].timestamp_delta = tmp_time ; |
403 | 918 nut->frame_code[i].stream_id_plus1 = tmp_stream; |
919 nut->frame_code[i].size_mul = tmp_mul ; | |
461 | 920 nut->frame_code[i].size_lsb = tmp_size+j; |
921 nut->frame_code[i].reserved_count = tmp_res ; | |
403 | 922 } |
923 } | |
461 | 924 if(nut->frame_code['N'].flags != FLAG_INVALID){ |
403 | 925 av_log(s, AV_LOG_ERROR, "illegal frame_code table\n"); |
926 return -1; | |
927 } | |
419 | 928 |
418
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
929 if(check_checksum(bc)){ |
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
930 av_log(s, AV_LOG_ERROR, "Main header checksum missmatch\n"); |
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
931 return -1; |
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
932 } |
419 | 933 |
934 return 0; | |
935 } | |
936 | |
937 static int decode_stream_header(NUTContext *nut){ | |
938 AVFormatContext *s= nut->avf; | |
939 ByteIOContext *bc = &s->pb; | |
461 | 940 int class, nom, denom, stream_id; |
419 | 941 uint64_t tmp; |
942 AVStream *st; | |
943 | |
456 | 944 get_packetheader(nut, bc, 1); |
419 | 945 stream_id= get_v(bc); |
946 if(stream_id >= nut->stream_count || s->streams[stream_id]) | |
947 return -1; | |
948 | |
949 st = av_new_stream(s, stream_id); | |
950 if (!st) | |
951 return AVERROR_NOMEM; | |
462
b69898ffc92a
move time_base (pts_num/pts_den) from AVFormatContext -> AVStream
michael
parents:
461
diff
changeset
|
952 |
419 | 953 class = get_v(bc); |
426 | 954 tmp = get_vb(bc); |
432 | 955 st->codec.codec_tag= tmp; |
419 | 956 switch(class) |
957 { | |
958 case 0: | |
959 st->codec.codec_type = CODEC_TYPE_VIDEO; | |
960 st->codec.codec_id = codec_get_bmp_id(tmp); | |
961 if (st->codec.codec_id == CODEC_ID_NONE) | |
962 av_log(s, AV_LOG_ERROR, "Unknown codec?!\n"); | |
963 break; | |
964 case 32: | |
965 st->codec.codec_type = CODEC_TYPE_AUDIO; | |
966 st->codec.codec_id = codec_get_wav_id(tmp); | |
967 if (st->codec.codec_id == CODEC_ID_NONE) | |
968 av_log(s, AV_LOG_ERROR, "Unknown codec?!\n"); | |
969 break; | |
970 default: | |
971 av_log(s, AV_LOG_ERROR, "Unknown stream class (%d)\n", class); | |
972 return -1; | |
973 } | |
974 s->bit_rate += get_v(bc); | |
426 | 975 get_vb(bc); /* language code */ |
419 | 976 nom = get_v(bc); |
977 denom = get_v(bc); | |
978 nut->stream[stream_id].msb_timestamp_shift = get_v(bc); | |
456 | 979 nut->stream[stream_id].decode_delay= get_v(bc); |
419 | 980 get_byte(bc); /* flags */ |
981 | |
982 /* codec specific data headers */ | |
983 while(get_v(bc) != 0){ | |
984 st->codec.extradata_size= get_v(bc); | |
587
fe24632a577b
allocate a few bytes more for extradata so the bitstream reader if its used by the codec for parsing extardata, doesnt read over the end
michael
parents:
555
diff
changeset
|
985 st->codec.extradata= av_mallocz(st->codec.extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); |
419 | 986 get_buffer(bc, st->codec.extradata, st->codec.extradata_size); |
987 // url_fskip(bc, get_v(bc)); | |
988 } | |
989 | |
990 if (class == 0) /* VIDEO */ | |
991 { | |
992 st->codec.width = get_v(bc); | |
993 st->codec.height = get_v(bc); | |
994 st->codec.sample_aspect_ratio.num= get_v(bc); | |
995 st->codec.sample_aspect_ratio.den= get_v(bc); | |
996 get_v(bc); /* csp type */ | |
997 | |
998 st->codec.frame_rate = nom; | |
999 st->codec.frame_rate_base = denom; | |
1000 } | |
1001 if (class == 32) /* AUDIO */ | |
1002 { | |
456 | 1003 st->codec.sample_rate = get_v(bc); |
1004 get_v(bc); // samplerate_den | |
419 | 1005 st->codec.channels = get_v(bc); |
1006 } | |
1007 if(check_checksum(bc)){ | |
1008 av_log(s, AV_LOG_ERROR, "Stream header %d checksum missmatch\n", stream_id); | |
1009 return -1; | |
1010 } | |
463
696f41bc8784
store index for seeking in the native timebase of each stream
michael
parents:
462
diff
changeset
|
1011 av_set_pts_info(s->streams[stream_id], 60, denom, nom); |
419 | 1012 nut->stream[stream_id].rate_num= nom; |
1013 nut->stream[stream_id].rate_den= denom; | |
1014 return 0; | |
1015 } | |
1016 | |
1017 static int decode_info_header(NUTContext *nut){ | |
1018 AVFormatContext *s= nut->avf; | |
1019 ByteIOContext *bc = &s->pb; | |
1020 | |
456 | 1021 get_packetheader(nut, bc, 1); |
419 | 1022 |
1023 for(;;){ | |
1024 int id= get_v(bc); | |
1025 char *name, *type, custom_name[256], custom_type[256]; | |
1026 | |
1027 if(!id) | |
1028 break; | |
1029 else if(id >= sizeof(info_table)/sizeof(info_table[0])){ | |
1030 av_log(s, AV_LOG_ERROR, "info id is too large %d %d\n", id, sizeof(info_table)/sizeof(info_table[0])); | |
1031 return -1; | |
1032 } | |
1033 | |
1034 type= info_table[id][1]; | |
1035 name= info_table[id][0]; | |
1036 //av_log(s, AV_LOG_DEBUG, "%d %s %s\n", id, type, name); | |
1037 | |
1038 if(!type){ | |
1039 get_str(bc, custom_type, sizeof(custom_type)); | |
1040 type= custom_type; | |
1041 } | |
1042 if(!name){ | |
1043 get_str(bc, custom_name, sizeof(custom_name)); | |
1044 name= custom_name; | |
1045 } | |
1046 | |
1047 if(!strcmp(type, "v")){ | |
1048 int value= get_v(bc); | |
1049 }else{ | |
1050 if(!strcmp(name, "Author")) | |
1051 get_str(bc, s->author, sizeof(s->author)); | |
1052 else if(!strcmp(name, "Title")) | |
1053 get_str(bc, s->title, sizeof(s->title)); | |
1054 else if(!strcmp(name, "Copyright")) | |
1055 get_str(bc, s->copyright, sizeof(s->copyright)); | |
1056 else if(!strcmp(name, "Description")) | |
1057 get_str(bc, s->comment, sizeof(s->comment)); | |
1058 else | |
1059 get_str(bc, NULL, 0); | |
1060 } | |
1061 } | |
1062 if(check_checksum(bc)){ | |
1063 av_log(s, AV_LOG_ERROR, "Info header checksum missmatch\n"); | |
1064 return -1; | |
1065 } | |
1066 return 0; | |
1067 } | |
1068 | |
1069 static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap) | |
1070 { | |
1071 NUTContext *nut = s->priv_data; | |
1072 ByteIOContext *bc = &s->pb; | |
1073 int64_t pos; | |
1074 int inited_stream_count; | |
1075 | |
1076 nut->avf= s; | |
1077 | |
1078 /* main header */ | |
1079 pos=0; | |
1080 for(;;){ | |
426 | 1081 pos= find_startcode(bc, MAIN_STARTCODE, pos)+1; |
1082 if (pos<0){ | |
419 | 1083 av_log(s, AV_LOG_ERROR, "no main startcode found\n"); |
1084 return -1; | |
1085 } | |
1086 if(decode_main_header(nut) >= 0) | |
1087 break; | |
1088 } | |
1089 | |
219 | 1090 |
1091 s->bit_rate = 0; | |
328 | 1092 |
419 | 1093 nut->stream = av_malloc(sizeof(StreamContext)*nut->stream_count); |
272 | 1094 |
419 | 1095 /* stream headers */ |
1096 pos=0; | |
1097 for(inited_stream_count=0; inited_stream_count < nut->stream_count;){ | |
426 | 1098 pos= find_startcode(bc, STREAM_STARTCODE, pos)+1; |
1099 if (pos<0){ | |
419 | 1100 av_log(s, AV_LOG_ERROR, "not all stream headers found\n"); |
418
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
1101 return -1; |
41da3366d341
checksuming for nut & nice checksum API for libavformat
michael
parents:
416
diff
changeset
|
1102 } |
419 | 1103 if(decode_stream_header(nut) >= 0) |
1104 inited_stream_count++; | |
415 | 1105 } |
1106 | |
419 | 1107 /* info headers */ |
1108 pos=0; | |
1109 for(;;){ | |
1110 uint64_t startcode= find_any_startcode(bc, pos); | |
1111 pos= url_ftell(bc); | |
415 | 1112 |
419 | 1113 if(startcode==0){ |
1114 av_log(s, AV_LOG_ERROR, "EOF before video frames\n"); | |
1115 return -1; | |
1116 }else if(startcode == KEYFRAME_STARTCODE){ | |
421 | 1117 nut->next_startcode= startcode; |
419 | 1118 break; |
1119 }else if(startcode != INFO_STARTCODE){ | |
1120 continue; | |
415 | 1121 } |
419 | 1122 |
1123 decode_info_header(nut); | |
1124 } | |
1125 | |
219 | 1126 return 0; |
1127 } | |
1128 | |
461 | 1129 static int decode_frame_header(NUTContext *nut, int *key_frame_ret, int64_t *pts_ret, int *stream_id_ret, int frame_code, int frame_type, int64_t frame_start){ |
421 | 1130 AVFormatContext *s= nut->avf; |
403 | 1131 StreamContext *stream; |
219 | 1132 ByteIOContext *bc = &s->pb; |
461 | 1133 int size, flags, size_mul, size_lsb, stream_id, time_delta; |
328 | 1134 int64_t pts = 0; |
219 | 1135 |
456 | 1136 if(frame_type < 2 && frame_start - nut->packet_start[2] > nut->max_distance){ |
1137 av_log(s, AV_LOG_ERROR, "last frame must have been damaged\n"); | |
1138 return -1; | |
1139 } | |
1140 | |
1141 if(frame_type) | |
1142 nut->packet_start[ frame_type ]= frame_start; //otherwise 1 goto 1 may happen | |
1143 | |
403 | 1144 flags= nut->frame_code[frame_code].flags; |
1145 size_mul= nut->frame_code[frame_code].size_mul; | |
1146 size_lsb= nut->frame_code[frame_code].size_lsb; | |
1147 stream_id= nut->frame_code[frame_code].stream_id_plus1 - 1; | |
461 | 1148 time_delta= nut->frame_code[frame_code].timestamp_delta; |
1149 | |
403 | 1150 if(stream_id==-1) |
1151 stream_id= get_v(bc); | |
1152 if(stream_id >= s->nb_streams){ | |
1153 av_log(s, AV_LOG_ERROR, "illegal stream_id\n"); | |
1154 return -1; | |
1155 } | |
1156 stream= &nut->stream[stream_id]; | |
421 | 1157 |
1158 // av_log(s, AV_LOG_DEBUG, "ft:%d ppts:%d %d %d\n", frame_type, stream->lru_pts_delta[0], stream->lru_pts_delta[1], stream->lru_pts_delta[2]); | |
456 | 1159 |
1160 *key_frame_ret= !!(flags & FLAG_KEY_FRAME); | |
403 | 1161 |
461 | 1162 if(!time_delta){ |
456 | 1163 int64_t mask = (1<<stream->msb_timestamp_shift)-1; |
1164 pts= get_v(bc); | |
1165 if(pts > mask){ | |
1166 pts -= mask+1; | |
1167 }else{ | |
1168 if(stream->last_pts == AV_NOPTS_VALUE){ | |
1169 av_log(s, AV_LOG_ERROR, "no reference pts available\n"); | |
1170 return -1; | |
426 | 1171 } |
456 | 1172 pts= lsb2full(stream, pts); |
403 | 1173 } |
1174 }else{ | |
456 | 1175 if(stream->last_pts == AV_NOPTS_VALUE){ |
1176 av_log(s, AV_LOG_ERROR, "no reference pts available\n"); | |
1177 return -1; | |
1178 } | |
461 | 1179 pts= stream->last_pts + time_delta; |
403 | 1180 } |
456 | 1181 |
1182 if(*key_frame_ret){ | |
1183 // av_log(s, AV_LOG_DEBUG, "stream:%d start:%lld pts:%lld length:%lld\n",stream_id, frame_start, av_pts, frame_start - nut->stream[stream_id].last_sync_pos); | |
1184 av_add_index_entry( | |
1185 s->streams[stream_id], | |
1186 frame_start, | |
463
696f41bc8784
store index for seeking in the native timebase of each stream
michael
parents:
462
diff
changeset
|
1187 pts, |
456 | 1188 frame_start - nut->stream[stream_id].last_sync_pos, |
1189 AVINDEX_KEYFRAME); | |
1190 nut->stream[stream_id].last_sync_pos= frame_start; | |
1191 // assert(nut->packet_start == frame_start); | |
403 | 1192 } |
456 | 1193 |
1194 assert(size_mul > size_lsb); | |
1195 size= size_lsb; | |
1196 if(flags & FLAG_DATA_SIZE) | |
1197 size+= size_mul*get_v(bc); | |
403 | 1198 |
461 | 1199 #ifdef TRACE |
1200 av_log(s, AV_LOG_DEBUG, "fs:%lld fc:%d ft:%d kf:%d pts:%lld size:%d mul:%d lsb:%d flags:%d delta:%d\n", frame_start, frame_code, frame_type, *key_frame_ret, pts, size, size_mul, size_lsb, flags, time_delta); | |
1201 #endif | |
421 | 1202 |
456 | 1203 if(frame_type==0 && url_ftell(bc) - nut->packet_start[2] + size > nut->max_distance){ |
421 | 1204 av_log(s, AV_LOG_ERROR, "frame size too large\n"); |
1205 return -1; | |
1206 } | |
219 | 1207 |
456 | 1208 *stream_id_ret = stream_id; |
463
696f41bc8784
store index for seeking in the native timebase of each stream
michael
parents:
462
diff
changeset
|
1209 *pts_ret = pts; |
456 | 1210 |
1211 update(nut, stream_id, frame_start, frame_type, frame_code, *key_frame_ret, size, pts); | |
1212 | |
1213 return size; | |
1214 } | |
1215 | |
461 | 1216 static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code, int frame_type, int64_t frame_start){ |
456 | 1217 AVFormatContext *s= nut->avf; |
1218 ByteIOContext *bc = &s->pb; | |
1219 int size, stream_id, key_frame; | |
1220 int64_t pts; | |
1221 | |
461 | 1222 size= decode_frame_header(nut, &key_frame, &pts, &stream_id, frame_code, frame_type, frame_start); |
456 | 1223 if(size < 0) |
1224 return -1; | |
1225 | |
219 | 1226 av_new_packet(pkt, size); |
1227 get_buffer(bc, pkt->data, size); | |
403 | 1228 pkt->stream_index = stream_id; |
219 | 1229 if (key_frame) |
1230 pkt->flags |= PKT_FLAG_KEY; | |
456 | 1231 pkt->pts = pts; |
403 | 1232 |
421 | 1233 return 0; |
1234 } | |
403 | 1235 |
421 | 1236 static int nut_read_packet(AVFormatContext *s, AVPacket *pkt) |
1237 { | |
1238 NUTContext *nut = s->priv_data; | |
1239 ByteIOContext *bc = &s->pb; | |
456 | 1240 int i, frame_code=0; |
421 | 1241 |
1242 for(;;){ | |
461 | 1243 int64_t pos= url_ftell(bc); |
426 | 1244 int frame_type= 0; |
421 | 1245 uint64_t tmp= nut->next_startcode; |
1246 nut->next_startcode=0; | |
1247 | |
1248 if (url_feof(bc)) | |
1249 return -1; | |
1250 | |
461 | 1251 if(tmp){ |
1252 pos-=8; | |
1253 }else{ | |
421 | 1254 frame_code = get_byte(bc); |
1255 if(frame_code == 'N'){ | |
1256 tmp= frame_code; | |
426 | 1257 for(i=1; i<8; i++) |
1258 tmp = (tmp<<8) + get_byte(bc); | |
421 | 1259 } |
1260 } | |
1261 switch(tmp){ | |
1262 case MAIN_STARTCODE: | |
1263 case STREAM_STARTCODE: | |
1264 case INDEX_STARTCODE: | |
456 | 1265 get_packetheader(nut, bc, 0); |
461 | 1266 assert(nut->packet_start[2] == pos); |
456 | 1267 url_fseek(bc, nut->written_packet_size + nut->packet_start[2], SEEK_SET); |
421 | 1268 break; |
1269 case INFO_STARTCODE: | |
1270 if(decode_info_header(nut)<0) | |
1271 goto resync; | |
1272 break; | |
426 | 1273 case KEYFRAME_STARTCODE: |
1274 frame_type = 2; | |
461 | 1275 reset(s, get_v(bc)); |
426 | 1276 frame_code = get_byte(bc); |
421 | 1277 case 0: |
461 | 1278 if(decode_frame(nut, pkt, frame_code, frame_type, pos)>=0) |
421 | 1279 return 0; |
1280 default: | |
1281 resync: | |
456 | 1282 av_log(s, AV_LOG_DEBUG, "syncing from %lld\n", nut->packet_start[2]+1); |
1283 tmp= find_any_startcode(bc, nut->packet_start[2]+1); | |
421 | 1284 if(tmp==0) |
1285 return -1; | |
1286 av_log(s, AV_LOG_DEBUG, "sync\n"); | |
456 | 1287 nut->next_startcode= tmp; |
426 | 1288 } |
1289 } | |
1290 } | |
1291 | |
437
50bae308f71e
moving nearly identical binary search code from nut/mpeg/asf to utils.c
michael
parents:
432
diff
changeset
|
1292 static int64_t nut_read_timestamp(AVFormatContext *s, int stream_index, int64_t *pos_arg, int64_t pos_limit){ |
426 | 1293 NUTContext *nut = s->priv_data; |
437
50bae308f71e
moving nearly identical binary search code from nut/mpeg/asf to utils.c
michael
parents:
432
diff
changeset
|
1294 StreamContext *stream; |
426 | 1295 ByteIOContext *bc = &s->pb; |
1296 int64_t pos, pts; | |
1297 uint64_t code; | |
456 | 1298 int frame_code,step, stream_id, i,size, key_frame; |
426 | 1299 av_log(s, AV_LOG_DEBUG, "read_timestamp(X,%d,%lld,%lld)\n", stream_index, *pos_arg, pos_limit); |
1300 | |
1301 if(*pos_arg < 0) | |
1302 return AV_NOPTS_VALUE; | |
1303 | |
1304 pos= *pos_arg; | |
1305 step= FFMIN(16*1024, pos); | |
1306 do{ | |
1307 pos-= step; | |
1308 code= find_any_startcode(bc, pos); | |
1309 | |
456 | 1310 if(code && url_ftell(bc) - 8 <= *pos_arg) |
426 | 1311 break; |
1312 step= FFMIN(2*step, pos); | |
1313 }while(step); | |
1314 | |
1315 if(!code) //nothing found, not even after pos_arg | |
1316 return AV_NOPTS_VALUE; | |
1317 | |
1318 url_fseek(bc, -8, SEEK_CUR); | |
1319 for(i=0; i<s->nb_streams; i++) | |
1320 nut->stream[i].last_sync_pos= url_ftell(bc); | |
1321 | |
1322 for(;;){ | |
456 | 1323 int frame_type=0; |
426 | 1324 int64_t pos= url_ftell(bc); |
1325 uint64_t tmp=0; | |
1326 | |
456 | 1327 if(pos > pos_limit || url_feof(bc)) |
426 | 1328 return AV_NOPTS_VALUE; |
1329 | |
1330 frame_code = get_byte(bc); | |
1331 if(frame_code == 'N'){ | |
1332 tmp= frame_code; | |
1333 for(i=1; i<8; i++) | |
1334 tmp = (tmp<<8) + get_byte(bc); | |
1335 } | |
1336 //av_log(s, AV_LOG_DEBUG, "before switch %llX at=%lld\n", tmp, pos); | |
1337 | |
1338 switch(tmp){ | |
1339 case MAIN_STARTCODE: | |
1340 case STREAM_STARTCODE: | |
1341 case INDEX_STARTCODE: | |
1342 case INFO_STARTCODE: | |
456 | 1343 get_packetheader(nut, bc, 0); |
1344 assert(nut->packet_start[2]==pos); | |
1345 url_fseek(bc, nut->written_packet_size + pos, SEEK_SET); | |
426 | 1346 break; |
1347 case KEYFRAME_STARTCODE: | |
456 | 1348 frame_type=2; |
461 | 1349 reset(s, get_v(bc)); |
426 | 1350 frame_code = get_byte(bc); |
1351 case 0: | |
461 | 1352 size= decode_frame_header(nut, &key_frame, &pts, &stream_id, frame_code, frame_type, pos); |
456 | 1353 if(size < 0) |
426 | 1354 goto resync; |
1355 | |
437
50bae308f71e
moving nearly identical binary search code from nut/mpeg/asf to utils.c
michael
parents:
432
diff
changeset
|
1356 stream= &nut->stream[stream_id]; |
456 | 1357 if(stream_id != stream_index || !key_frame || pos < *pos_arg){ |
1358 url_fseek(bc, size, SEEK_CUR); | |
426 | 1359 break; |
1360 } | |
1361 | |
456 | 1362 *pos_arg= pos; |
426 | 1363 return pts; |
1364 default: | |
1365 resync: | |
456 | 1366 av_log(s, AV_LOG_DEBUG, "syncing from %lld\n", nut->packet_start[2]+1); |
1367 if(!find_any_startcode(bc, nut->packet_start[2]+1)) | |
426 | 1368 return AV_NOPTS_VALUE; |
1369 | |
1370 url_fseek(bc, -8, SEEK_CUR); | |
421 | 1371 } |
1372 } | |
426 | 1373 return AV_NOPTS_VALUE; |
1374 } | |
1375 | |
555 | 1376 static int nut_read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){ |
456 | 1377 // NUTContext *nut = s->priv_data; |
437
50bae308f71e
moving nearly identical binary search code from nut/mpeg/asf to utils.c
michael
parents:
432
diff
changeset
|
1378 int64_t pos; |
426 | 1379 |
555 | 1380 if(av_seek_frame_binary(s, stream_index, target_ts, flags) < 0) |
437
50bae308f71e
moving nearly identical binary search code from nut/mpeg/asf to utils.c
michael
parents:
432
diff
changeset
|
1381 return -1; |
426 | 1382 |
437
50bae308f71e
moving nearly identical binary search code from nut/mpeg/asf to utils.c
michael
parents:
432
diff
changeset
|
1383 pos= url_ftell(&s->pb); |
456 | 1384 nut_read_timestamp(s, stream_index, &pos, pos-1); |
426 | 1385 |
1386 return 0; | |
403 | 1387 } |
1388 | |
1389 static int nut_read_close(AVFormatContext *s) | |
1390 { | |
1391 NUTContext *nut = s->priv_data; | |
1392 int i; | |
1393 | |
1394 for(i=0;i<s->nb_streams;i++) { | |
1395 av_freep(&s->streams[i]->codec.extradata); | |
1396 } | |
1397 av_freep(&nut->stream); | |
219 | 1398 |
1399 return 0; | |
1400 } | |
1401 | |
1402 static AVInputFormat nut_iformat = { | |
1403 "nut", | |
1404 "nut format", | |
1405 sizeof(NUTContext), | |
1406 nut_probe, | |
1407 nut_read_header, | |
1408 nut_read_packet, | |
403 | 1409 nut_read_close, |
426 | 1410 nut_read_seek, |
437
50bae308f71e
moving nearly identical binary search code from nut/mpeg/asf to utils.c
michael
parents:
432
diff
changeset
|
1411 nut_read_timestamp, |
219 | 1412 .extensions = "nut", |
1413 }; | |
1414 | |
277
a313e1080322
disable encoders where appropriate (patch courtesy of BERO
melanson
parents:
272
diff
changeset
|
1415 #ifdef CONFIG_ENCODERS |
219 | 1416 static AVOutputFormat nut_oformat = { |
1417 "nut", | |
1418 "nut format", | |
1419 "video/x-nut", | |
1420 "nut", | |
1421 sizeof(NUTContext), | |
414 | 1422 #ifdef CONFIG_VORBIS |
219 | 1423 CODEC_ID_VORBIS, |
1424 #elif defined(CONFIG_MP3LAME) | |
232 | 1425 CODEC_ID_MP3, |
219 | 1426 #else |
223 | 1427 CODEC_ID_MP2, /* AC3 needs liba52 decoder */ |
219 | 1428 #endif |
1429 CODEC_ID_MPEG4, | |
1430 nut_write_header, | |
1431 nut_write_packet, | |
1432 nut_write_trailer, | |
1433 }; | |
277
a313e1080322
disable encoders where appropriate (patch courtesy of BERO
melanson
parents:
272
diff
changeset
|
1434 #endif //CONFIG_ENCODERS |
219 | 1435 |
1436 int nut_init(void) | |
1437 { | |
1438 av_register_input_format(&nut_iformat); | |
277
a313e1080322
disable encoders where appropriate (patch courtesy of BERO
melanson
parents:
272
diff
changeset
|
1439 #ifdef CONFIG_ENCODERS |
219 | 1440 av_register_output_format(&nut_oformat); |
277
a313e1080322
disable encoders where appropriate (patch courtesy of BERO
melanson
parents:
272
diff
changeset
|
1441 #endif //CONFIG_ENCODERS |
219 | 1442 return 0; |
1443 } |