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