Mercurial > libavformat.hg
annotate nutdec.c @ 1779:de2cf54eb68f libavformat
mxf aes decryption support, patch by Reimar, simplified to only look for first crypto context, will be extended once we get files with multiple cryptocontext, and hope that they won't have broken container ul
author | bcoudurier |
---|---|
date | Sun, 11 Feb 2007 12:50:33 +0000 |
parents | 1c6ee4cf8a38 |
children | ec025d5fbbe2 |
rev | line source |
---|---|
1477 | 1 /* |
2 * "NUT" Container Format demuxer | |
3 * Copyright (c) 2004-2006 Michael Niedermayer | |
4 * Copyright (c) 2003 Alex Beregszaszi | |
5 * | |
6 * This file is part of FFmpeg. | |
7 * | |
8 * FFmpeg is free software; you can redistribute it and/or | |
9 * modify it under the terms of the GNU Lesser General Public | |
10 * License as published by the Free Software Foundation; either | |
11 * version 2.1 of the License, or (at your option) any later version. | |
12 * | |
13 * FFmpeg is distributed in the hope that it will be useful, | |
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 * | |
18 * You should have received a copy of the GNU Lesser General Public | |
19 * License along with FFmpeg; if not, write to the Free Software | |
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
21 * | |
22 */ | |
23 | |
1500 | 24 #include "tree.h" |
1477 | 25 #include "nut.h" |
26 | |
27 #undef NDEBUG | |
28 #include <assert.h> | |
29 | |
1515 | 30 static uint64_t get_v(ByteIOContext *bc){ |
1477 | 31 uint64_t val = 0; |
1682 | 32 int tmp; |
1477 | 33 |
1682 | 34 do{ |
35 tmp = get_byte(bc); | |
36 val= (val<<7) + (tmp&127); | |
37 }while(tmp&128); | |
38 return val; | |
1477 | 39 } |
40 | |
41 static int get_str(ByteIOContext *bc, char *string, unsigned int maxlen){ | |
42 unsigned int len= get_v(bc); | |
43 | |
44 if(len && maxlen) | |
45 get_buffer(bc, string, FFMIN(len, maxlen)); | |
46 while(len > maxlen){ | |
47 get_byte(bc); | |
48 len--; | |
49 } | |
50 | |
51 if(maxlen) | |
52 string[FFMIN(len, maxlen-1)]= 0; | |
53 | |
54 if(maxlen == len) | |
55 return -1; | |
56 else | |
57 return 0; | |
58 } | |
59 | |
60 static int64_t get_s(ByteIOContext *bc){ | |
61 int64_t v = get_v(bc) + 1; | |
62 | |
63 if (v&1) return -(v>>1); | |
64 else return (v>>1); | |
65 } | |
66 | |
67 static uint64_t get_fourcc(ByteIOContext *bc){ | |
68 unsigned int len= get_v(bc); | |
69 | |
70 if (len==2) return get_le16(bc); | |
71 else if(len==4) return get_le32(bc); | |
72 else return -1; | |
73 } | |
74 | |
75 #ifdef TRACE | |
76 static inline uint64_t get_v_trace(ByteIOContext *bc, char *file, char *func, int line){ | |
77 uint64_t v= get_v(bc); | |
78 | |
79 printf("get_v %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); | |
80 return v; | |
81 } | |
82 | |
83 static inline int64_t get_s_trace(ByteIOContext *bc, char *file, char *func, int line){ | |
84 int64_t v= get_s(bc); | |
85 | |
86 printf("get_s %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); | |
87 return v; | |
88 } | |
89 | |
90 static inline uint64_t get_vb_trace(ByteIOContext *bc, char *file, char *func, int line){ | |
91 uint64_t v= get_vb(bc); | |
92 | |
93 printf("get_vb %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); | |
94 return v; | |
95 } | |
96 #define get_v(bc) get_v_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__) | |
97 #define get_s(bc) get_s_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__) | |
98 #define get_vb(bc) get_vb_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__) | |
99 #endif | |
100 | |
101 static int get_packetheader(NUTContext *nut, ByteIOContext *bc, int calculate_checksum) | |
102 { | |
103 int64_t start, size; | |
104 // start= url_ftell(bc) - 8; | |
105 | |
106 size= get_v(bc); | |
107 | |
1485 | 108 init_checksum(bc, calculate_checksum ? av_crc04C11DB7_update : NULL, 0); |
1477 | 109 |
110 // nut->packet_start[2] = start; | |
111 // nut->written_packet_size= size; | |
112 | |
113 return size; | |
114 } | |
115 | |
116 static uint64_t find_any_startcode(ByteIOContext *bc, int64_t pos){ | |
117 uint64_t state=0; | |
118 | |
119 if(pos >= 0) | |
120 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 | |
121 | |
122 while(!url_feof(bc)){ | |
123 state= (state<<8) | get_byte(bc); | |
124 if((state>>56) != 'N') | |
125 continue; | |
126 switch(state){ | |
127 case MAIN_STARTCODE: | |
128 case STREAM_STARTCODE: | |
129 case SYNCPOINT_STARTCODE: | |
130 case INFO_STARTCODE: | |
131 case INDEX_STARTCODE: | |
132 return state; | |
133 } | |
134 } | |
135 | |
136 return 0; | |
137 } | |
138 | |
139 /** | |
140 * find the given startcode. | |
141 * @param code the startcode | |
142 * @param pos the start position of the search, or -1 if the current position | |
143 * @returns the position of the startcode or -1 if not found | |
144 */ | |
145 static int64_t find_startcode(ByteIOContext *bc, uint64_t code, int64_t pos){ | |
146 for(;;){ | |
147 uint64_t startcode= find_any_startcode(bc, pos); | |
148 if(startcode == code) | |
149 return url_ftell(bc) - 8; | |
150 else if(startcode == 0) | |
151 return -1; | |
152 pos=-1; | |
153 } | |
154 } | |
155 | |
156 static int64_t lsb2full(StreamContext *stream, int64_t lsb){ | |
157 int64_t mask = (1<<stream->msb_pts_shift)-1; | |
158 int64_t delta= stream->last_pts - mask/2; | |
159 return ((lsb - delta)&mask) + delta; | |
160 } | |
161 | |
162 static int nut_probe(AVProbeData *p){ | |
163 int i; | |
164 uint64_t code= 0; | |
165 | |
166 for (i = 0; i < p->buf_size; i++) { | |
167 code = (code << 8) | p->buf[i]; | |
168 if (code == MAIN_STARTCODE) | |
169 return AVPROBE_SCORE_MAX; | |
170 } | |
171 return 0; | |
172 } | |
173 | |
174 #define GET_V(dst, check) \ | |
175 tmp= get_v(bc);\ | |
176 if(!(check)){\ | |
177 av_log(s, AV_LOG_ERROR, "Error " #dst " is (%"PRId64")\n", tmp);\ | |
178 return -1;\ | |
179 }\ | |
180 dst= tmp; | |
181 | |
182 static int skip_reserved(ByteIOContext *bc, int64_t pos){ | |
183 pos -= url_ftell(bc); | |
184 if(pos<0){ | |
185 url_fseek(bc, pos, SEEK_CUR); | |
186 return -1; | |
187 }else{ | |
188 while(pos--) | |
189 get_byte(bc); | |
190 return 0; | |
191 } | |
192 } | |
193 | |
194 static int decode_main_header(NUTContext *nut){ | |
195 AVFormatContext *s= nut->avf; | |
196 ByteIOContext *bc = &s->pb; | |
197 uint64_t tmp, end; | |
198 unsigned int stream_count; | |
199 int i, j, tmp_stream, tmp_mul, tmp_pts, tmp_size, count, tmp_res; | |
200 | |
201 end= get_packetheader(nut, bc, 1); | |
1485 | 202 end += url_ftell(bc); |
1477 | 203 |
204 GET_V(tmp , tmp >=2 && tmp <= 3) | |
205 GET_V(stream_count , tmp > 0 && tmp <=MAX_STREAMS) | |
206 | |
207 nut->max_distance = get_v(bc); | |
208 if(nut->max_distance > 65536){ | |
209 av_log(s, AV_LOG_DEBUG, "max_distance %d\n", nut->max_distance); | |
210 nut->max_distance= 65536; | |
211 } | |
212 | |
213 GET_V(nut->time_base_count, tmp>0 && tmp<INT_MAX / sizeof(AVRational)) | |
214 nut->time_base= av_malloc(nut->time_base_count * sizeof(AVRational)); | |
215 | |
216 for(i=0; i<nut->time_base_count; i++){ | |
217 GET_V(nut->time_base[i].num, tmp>0 && tmp<(1ULL<<31)) | |
218 GET_V(nut->time_base[i].den, tmp>0 && tmp<(1ULL<<31)) | |
219 if(ff_gcd(nut->time_base[i].num, nut->time_base[i].den) != 1){ | |
220 av_log(s, AV_LOG_ERROR, "time base invalid\n"); | |
221 return -1; | |
222 } | |
223 } | |
224 tmp_pts=0; | |
225 tmp_mul=1; | |
226 tmp_stream=0; | |
227 for(i=0; i<256;){ | |
228 int tmp_flags = get_v(bc); | |
229 int tmp_fields= get_v(bc); | |
230 if(tmp_fields>0) tmp_pts = get_s(bc); | |
231 if(tmp_fields>1) tmp_mul = get_v(bc); | |
232 if(tmp_fields>2) tmp_stream= get_v(bc); | |
233 if(tmp_fields>3) tmp_size = get_v(bc); | |
234 else tmp_size = 0; | |
235 if(tmp_fields>4) tmp_res = get_v(bc); | |
236 else tmp_res = 0; | |
237 if(tmp_fields>5) count = get_v(bc); | |
238 else count = tmp_mul - tmp_size; | |
239 | |
240 while(tmp_fields-- > 6) | |
241 get_v(bc); | |
242 | |
243 if(count == 0 || i+count > 256){ | |
244 av_log(s, AV_LOG_ERROR, "illegal count %d at %d\n", count, i); | |
245 return -1; | |
246 } | |
247 if(tmp_stream >= stream_count){ | |
248 av_log(s, AV_LOG_ERROR, "illegal stream number\n"); | |
249 return -1; | |
250 } | |
251 | |
252 for(j=0; j<count; j++,i++){ | |
253 if (i == 'N') { | |
254 nut->frame_code[i].flags= FLAG_INVALID; | |
255 j--; | |
256 continue; | |
257 } | |
258 nut->frame_code[i].flags = tmp_flags ; | |
259 nut->frame_code[i].pts_delta = tmp_pts ; | |
260 nut->frame_code[i].stream_id = tmp_stream; | |
261 nut->frame_code[i].size_mul = tmp_mul ; | |
262 nut->frame_code[i].size_lsb = tmp_size+j; | |
263 nut->frame_code[i].reserved_count = tmp_res ; | |
264 } | |
265 } | |
266 assert(nut->frame_code['N'].flags == FLAG_INVALID); | |
267 | |
1485 | 268 if(skip_reserved(bc, end) || get_checksum(bc)){ |
1477 | 269 av_log(s, AV_LOG_ERROR, "Main header checksum mismatch\n"); |
270 return -1; | |
271 } | |
272 | |
273 nut->stream = av_mallocz(sizeof(StreamContext)*stream_count); | |
274 for(i=0; i<stream_count; i++){ | |
275 av_new_stream(s, i); | |
276 } | |
277 | |
278 return 0; | |
279 } | |
280 | |
281 static int decode_stream_header(NUTContext *nut){ | |
282 AVFormatContext *s= nut->avf; | |
283 ByteIOContext *bc = &s->pb; | |
284 StreamContext *stc; | |
1516 | 285 int class, stream_id; |
1477 | 286 uint64_t tmp, end; |
287 AVStream *st; | |
288 | |
289 end= get_packetheader(nut, bc, 1); | |
1485 | 290 end += url_ftell(bc); |
1477 | 291 |
292 GET_V(stream_id, tmp < s->nb_streams && !nut->stream[tmp].time_base.num); | |
293 stc= &nut->stream[stream_id]; | |
294 | |
295 st = s->streams[stream_id]; | |
296 if (!st) | |
297 return AVERROR_NOMEM; | |
298 | |
299 class = get_v(bc); | |
300 tmp = get_fourcc(bc); | |
301 st->codec->codec_tag= tmp; | |
302 switch(class) | |
303 { | |
304 case 0: | |
305 st->codec->codec_type = CODEC_TYPE_VIDEO; | |
306 st->codec->codec_id = codec_get_bmp_id(tmp); | |
307 if (st->codec->codec_id == CODEC_ID_NONE) | |
308 av_log(s, AV_LOG_ERROR, "Unknown codec?!\n"); | |
309 break; | |
310 case 1: | |
311 st->codec->codec_type = CODEC_TYPE_AUDIO; | |
312 st->codec->codec_id = codec_get_wav_id(tmp); | |
313 if (st->codec->codec_id == CODEC_ID_NONE) | |
314 av_log(s, AV_LOG_ERROR, "Unknown codec?!\n"); | |
315 break; | |
316 case 2: | |
317 // st->codec->codec_type = CODEC_TYPE_TEXT; | |
318 // break; | |
319 case 3: | |
320 st->codec->codec_type = CODEC_TYPE_DATA; | |
321 break; | |
322 default: | |
323 av_log(s, AV_LOG_ERROR, "Unknown stream class (%d)\n", class); | |
324 return -1; | |
325 } | |
326 GET_V(stc->time_base_id , tmp < nut->time_base_count); | |
327 GET_V(stc->msb_pts_shift , tmp < 16); | |
328 stc->max_pts_distance= get_v(bc); | |
329 GET_V(stc->decode_delay , tmp < 1000); //sanity limit, raise this if moors law is true | |
330 st->codec->has_b_frames= stc->decode_delay; | |
331 get_v(bc); //stream flags | |
332 | |
333 GET_V(st->codec->extradata_size, tmp < (1<<30)); | |
334 if(st->codec->extradata_size){ | |
335 st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); | |
336 get_buffer(bc, st->codec->extradata, st->codec->extradata_size); | |
337 } | |
338 | |
339 if (st->codec->codec_type == CODEC_TYPE_VIDEO){ | |
340 GET_V(st->codec->width , tmp > 0) | |
341 GET_V(st->codec->height, tmp > 0) | |
342 st->codec->sample_aspect_ratio.num= get_v(bc); | |
343 st->codec->sample_aspect_ratio.den= get_v(bc); | |
344 if((!st->codec->sample_aspect_ratio.num) != (!st->codec->sample_aspect_ratio.den)){ | |
345 av_log(s, AV_LOG_ERROR, "invalid aspect ratio\n"); | |
346 return -1; | |
347 } | |
348 get_v(bc); /* csp type */ | |
349 }else if (st->codec->codec_type == CODEC_TYPE_AUDIO){ | |
350 GET_V(st->codec->sample_rate , tmp > 0) | |
351 tmp= get_v(bc); // samplerate_den | |
352 if(tmp > st->codec->sample_rate){ | |
353 av_log(s, AV_LOG_ERROR, "bleh, libnut muxed this ;)\n"); | |
354 st->codec->sample_rate= tmp; | |
355 } | |
356 GET_V(st->codec->channels, tmp > 0) | |
357 } | |
1485 | 358 if(skip_reserved(bc, end) || get_checksum(bc)){ |
1477 | 359 av_log(s, AV_LOG_ERROR, "Stream header %d checksum mismatch\n", stream_id); |
360 return -1; | |
361 } | |
362 stc->time_base= nut->time_base[stc->time_base_id]; | |
363 av_set_pts_info(s->streams[stream_id], 63, stc->time_base.num, stc->time_base.den); | |
364 return 0; | |
365 } | |
366 | |
367 static int decode_info_header(NUTContext *nut){ | |
368 AVFormatContext *s= nut->avf; | |
369 ByteIOContext *bc = &s->pb; | |
370 uint64_t tmp; | |
371 unsigned int stream_id_plus1, chapter_start, chapter_len, count; | |
372 int chapter_id, i; | |
373 int64_t value, end; | |
374 char name[256], str_value[1024], type_str[256], *type= type_str; | |
375 | |
376 end= get_packetheader(nut, bc, 1); | |
1485 | 377 end += url_ftell(bc); |
1477 | 378 |
379 GET_V(stream_id_plus1, tmp <= s->nb_streams) | |
380 chapter_id = get_s(bc); | |
381 chapter_start= get_v(bc); | |
382 chapter_len = get_v(bc); | |
383 count = get_v(bc); | |
384 for(i=0; i<count; i++){ | |
385 get_str(bc, name, sizeof(name)); | |
386 value= get_s(bc); | |
387 if(value == -1){ | |
388 type= "UTF-8"; | |
389 get_str(bc, str_value, sizeof(str_value)); | |
390 }else if(value == -2){ | |
391 get_str(bc, type, sizeof(type)); | |
392 get_str(bc, str_value, sizeof(str_value)); | |
393 }else if(value == -3){ | |
394 type= "s"; | |
395 value= get_s(bc); | |
396 }else if(value == -4){ | |
397 type= "t"; | |
398 value= get_v(bc); | |
399 }else if(value < -4){ | |
400 type= "r"; | |
401 get_s(bc); | |
402 }else{ | |
403 type= "v"; | |
404 } | |
405 | |
406 if(chapter_id==0 && !strcmp(type, "UTF-8")){ | |
407 if (!strcmp(name, "Author")) | |
408 pstrcpy(s->author , sizeof(s->author) , str_value); | |
409 else if(!strcmp(name, "Title")) | |
410 pstrcpy(s->title , sizeof(s->title) , str_value); | |
411 else if(!strcmp(name, "Copyright")) | |
412 pstrcpy(s->copyright, sizeof(s->copyright), str_value); | |
413 else if(!strcmp(name, "Description")) | |
414 pstrcpy(s->comment , sizeof(s->comment) , str_value); | |
415 } | |
416 } | |
417 | |
1485 | 418 if(skip_reserved(bc, end) || get_checksum(bc)){ |
1477 | 419 av_log(s, AV_LOG_ERROR, "Info header checksum mismatch\n"); |
420 return -1; | |
421 } | |
422 return 0; | |
423 } | |
424 | |
1500 | 425 int sp_pos_cmp(syncpoint_t *a, syncpoint_t *b){ |
426 return (a->pos - b->pos>>32) - (b->pos - a->pos>>32); | |
427 } | |
428 | |
429 int sp_pts_cmp(syncpoint_t *a, syncpoint_t *b){ | |
430 return (a->ts - b->ts>>32) - (b->ts - a->ts>>32); | |
431 } | |
432 | |
433 static void add_sp(NUTContext *nut, int64_t pos, int64_t back_ptr, int64_t ts){ | |
434 syncpoint_t *sp2, *sp= av_mallocz(sizeof(syncpoint_t)); | |
435 | |
436 sp->pos= pos; | |
437 sp->back_ptr= back_ptr; | |
438 sp->ts= ts; | |
439 sp2= av_tree_insert(&nut->syncpoints, sp, sp_pos_cmp); | |
440 if(sp2 && sp2 != sp) | |
441 av_free(sp); | |
442 } | |
443 | |
444 static int decode_syncpoint(NUTContext *nut, int64_t *ts, int64_t *back_ptr){ | |
1477 | 445 AVFormatContext *s= nut->avf; |
446 ByteIOContext *bc = &s->pb; | |
1500 | 447 int64_t end, tmp; |
1477 | 448 int i; |
449 AVRational time_base; | |
450 | |
1478 | 451 nut->last_syncpoint_pos= url_ftell(bc)-8; |
1477 | 452 |
453 end= get_packetheader(nut, bc, 1); | |
1485 | 454 end += url_ftell(bc); |
1477 | 455 |
456 tmp= get_v(bc); | |
1500 | 457 *back_ptr= nut->last_syncpoint_pos - 16*get_v(bc); |
458 if(*back_ptr < 0) | |
459 return -1; | |
1477 | 460 |
461 time_base= nut->time_base[tmp % nut->time_base_count]; | |
462 for(i=0; i<s->nb_streams; i++){ | |
1484 | 463 nut->stream[i].last_pts= av_rescale_rnd( |
464 tmp / nut->time_base_count, | |
465 time_base.num * (int64_t)nut->stream[i].time_base.den, | |
466 time_base.den * (int64_t)nut->stream[i].time_base.num, | |
467 AV_ROUND_DOWN); | |
1477 | 468 //last_key_frame ? |
469 } | |
470 //FIXME put this in a reset func maybe | |
471 | |
1485 | 472 if(skip_reserved(bc, end) || get_checksum(bc)){ |
1478 | 473 av_log(s, AV_LOG_ERROR, "sync point checksum mismatch\n"); |
1477 | 474 return -1; |
475 } | |
1500 | 476 |
477 *ts= tmp / s->nb_streams * av_q2d(nut->time_base[tmp % s->nb_streams])*AV_TIME_BASE; | |
478 add_sp(nut, nut->last_syncpoint_pos, *back_ptr, *ts); | |
479 | |
1477 | 480 return 0; |
481 } | |
482 | |
1484 | 483 static int find_and_decode_index(NUTContext *nut){ |
484 AVFormatContext *s= nut->avf; | |
485 ByteIOContext *bc = &s->pb; | |
486 uint64_t tmp, end; | |
487 int i, j, syncpoint_count; | |
488 int64_t filesize= url_fsize(bc); | |
489 int64_t *syncpoints; | |
490 int8_t *has_keyframe; | |
491 | |
492 url_fseek(bc, filesize-12, SEEK_SET); | |
493 url_fseek(bc, filesize-get_be64(bc), SEEK_SET); | |
494 if(get_be64(bc) != INDEX_STARTCODE){ | |
495 av_log(s, AV_LOG_ERROR, "no index at the end\n"); | |
496 return -1; | |
497 } | |
498 | |
499 end= get_packetheader(nut, bc, 1); | |
1485 | 500 end += url_ftell(bc); |
1484 | 501 |
502 get_v(bc); //max_pts | |
503 GET_V(syncpoint_count, tmp < INT_MAX/8 && tmp > 0) | |
504 syncpoints= av_malloc(sizeof(int64_t)*syncpoint_count); | |
505 has_keyframe= av_malloc(sizeof(int8_t)*(syncpoint_count+1)); | |
506 for(i=0; i<syncpoint_count; i++){ | |
507 GET_V(syncpoints[i], tmp>0) | |
508 if(i) | |
509 syncpoints[i] += syncpoints[i-1]; | |
510 } | |
511 | |
512 for(i=0; i<s->nb_streams; i++){ | |
513 int64_t last_pts= -1; | |
514 for(j=0; j<syncpoint_count;){ | |
515 uint64_t x= get_v(bc); | |
516 int type= x&1; | |
517 int n= j; | |
518 x>>=1; | |
519 if(type){ | |
520 int flag= x&1; | |
521 x>>=1; | |
522 if(n+x >= syncpoint_count + 1){ | |
523 av_log(s, AV_LOG_ERROR, "index overflow A\n"); | |
524 return -1; | |
525 } | |
526 while(x--) | |
527 has_keyframe[n++]= flag; | |
528 has_keyframe[n++]= !flag; | |
529 }else{ | |
530 while(x != 1){ | |
531 if(n>=syncpoint_count + 1){ | |
532 av_log(s, AV_LOG_ERROR, "index overflow B\n"); | |
533 return -1; | |
534 } | |
535 has_keyframe[n++]= x&1; | |
536 x>>=1; | |
537 } | |
538 } | |
539 if(has_keyframe[0]){ | |
540 av_log(s, AV_LOG_ERROR, "keyframe before first syncpoint in index\n"); | |
541 return -1; | |
542 } | |
543 assert(n<=syncpoint_count+1); | |
544 for(; j<n; j++){ | |
545 if(has_keyframe[j]){ | |
546 uint64_t B, A= get_v(bc); | |
547 if(!A){ | |
548 A= get_v(bc); | |
549 B= get_v(bc); | |
550 //eor_pts[j][i] = last_pts + A + B | |
551 }else | |
552 B= 0; | |
553 av_add_index_entry( | |
554 s->streams[i], | |
555 16*syncpoints[j-1], | |
556 last_pts + A, | |
557 0, | |
558 0, | |
559 AVINDEX_KEYFRAME); | |
560 last_pts += A + B; | |
561 } | |
562 } | |
563 } | |
564 } | |
565 | |
1485 | 566 if(skip_reserved(bc, end) || get_checksum(bc)){ |
1484 | 567 av_log(s, AV_LOG_ERROR, "Index checksum mismatch\n"); |
568 return -1; | |
569 } | |
570 return 0; | |
571 } | |
572 | |
1477 | 573 static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap) |
574 { | |
575 NUTContext *nut = s->priv_data; | |
576 ByteIOContext *bc = &s->pb; | |
577 int64_t pos; | |
578 int inited_stream_count; | |
579 | |
580 nut->avf= s; | |
581 | |
582 /* main header */ | |
583 pos=0; | |
1480 | 584 do{ |
1477 | 585 pos= find_startcode(bc, MAIN_STARTCODE, pos)+1; |
586 if (pos<0+1){ | |
587 av_log(s, AV_LOG_ERROR, "no main startcode found\n"); | |
588 return -1; | |
589 } | |
1480 | 590 }while(decode_main_header(nut) < 0); |
1477 | 591 |
592 /* stream headers */ | |
593 pos=0; | |
594 for(inited_stream_count=0; inited_stream_count < s->nb_streams;){ | |
595 pos= find_startcode(bc, STREAM_STARTCODE, pos)+1; | |
596 if (pos<0+1){ | |
597 av_log(s, AV_LOG_ERROR, "not all stream headers found\n"); | |
598 return -1; | |
599 } | |
600 if(decode_stream_header(nut) >= 0) | |
601 inited_stream_count++; | |
602 } | |
603 | |
604 /* info headers */ | |
605 pos=0; | |
606 for(;;){ | |
607 uint64_t startcode= find_any_startcode(bc, pos); | |
608 pos= url_ftell(bc); | |
609 | |
610 if(startcode==0){ | |
611 av_log(s, AV_LOG_ERROR, "EOF before video frames\n"); | |
612 return -1; | |
613 }else if(startcode == SYNCPOINT_STARTCODE){ | |
614 nut->next_startcode= startcode; | |
615 break; | |
616 }else if(startcode != INFO_STARTCODE){ | |
617 continue; | |
618 } | |
619 | |
620 decode_info_header(nut); | |
621 } | |
622 | |
1478 | 623 s->data_offset= pos-8; |
624 | |
1501 | 625 if(!url_is_streamed(bc)){ |
1484 | 626 int64_t orig_pos= url_ftell(bc); |
627 find_and_decode_index(nut); | |
628 url_fseek(bc, orig_pos, SEEK_SET); | |
629 } | |
630 assert(nut->next_startcode == SYNCPOINT_STARTCODE); | |
631 | |
1477 | 632 return 0; |
633 } | |
634 | |
1518 | 635 static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, int frame_code){ |
1477 | 636 AVFormatContext *s= nut->avf; |
637 ByteIOContext *bc = &s->pb; | |
638 StreamContext *stc; | |
639 int size, flags, size_mul, pts_delta, i, reserved_count; | |
640 uint64_t tmp; | |
641 | |
642 if(url_ftell(bc) > nut->last_syncpoint_pos + nut->max_distance){ | |
1478 | 643 av_log(s, AV_LOG_ERROR, "last frame must have been damaged %Ld > %Ld + %d\n", url_ftell(bc), nut->last_syncpoint_pos, nut->max_distance); |
1477 | 644 return -1; |
645 } | |
646 | |
647 flags = nut->frame_code[frame_code].flags; | |
648 size_mul = nut->frame_code[frame_code].size_mul; | |
649 size = nut->frame_code[frame_code].size_lsb; | |
650 *stream_id = nut->frame_code[frame_code].stream_id; | |
651 pts_delta = nut->frame_code[frame_code].pts_delta; | |
652 reserved_count = nut->frame_code[frame_code].reserved_count; | |
653 | |
654 if(flags & FLAG_INVALID) | |
655 return -1; | |
656 if(flags & FLAG_CODED) | |
657 flags ^= get_v(bc); | |
658 if(flags & FLAG_STREAM_ID){ | |
659 GET_V(*stream_id, tmp < s->nb_streams) | |
660 } | |
661 stc= &nut->stream[*stream_id]; | |
662 if(flags&FLAG_CODED_PTS){ | |
663 int coded_pts= get_v(bc); | |
664 //FIXME check last_pts validity? | |
665 if(coded_pts < (1<<stc->msb_pts_shift)){ | |
666 *pts=lsb2full(stc, coded_pts); | |
667 }else | |
668 *pts=coded_pts - (1<<stc->msb_pts_shift); | |
669 }else | |
670 *pts= stc->last_pts + pts_delta; | |
671 if(flags&FLAG_SIZE_MSB){ | |
672 size += size_mul*get_v(bc); | |
673 } | |
674 if(flags&FLAG_RESERVED) | |
675 reserved_count= get_v(bc); | |
676 for(i=0; i<reserved_count; i++) | |
677 get_v(bc); | |
678 if(flags&FLAG_CHECKSUM){ | |
679 get_be32(bc); //FIXME check this | |
1518 | 680 }else if(size > 2*nut->max_distance || FFABS(stc->last_pts - *pts) > stc->max_pts_distance){ |
1509
edc979a1ecb5
check for frames with 2*size > max_dist and no crc
michael
parents:
1508
diff
changeset
|
681 av_log(s, AV_LOG_ERROR, "frame size > 2max_distance and no checksum\n"); |
edc979a1ecb5
check for frames with 2*size > max_dist and no crc
michael
parents:
1508
diff
changeset
|
682 return -1; |
1477 | 683 } |
684 | |
685 stc->last_pts= *pts; | |
1518 | 686 stc->last_flags= flags; |
1477 | 687 |
688 return size; | |
689 } | |
690 | |
691 static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code){ | |
692 AVFormatContext *s= nut->avf; | |
693 ByteIOContext *bc = &s->pb; | |
1518 | 694 int size, stream_id, discard; |
1477 | 695 int64_t pts, last_IP_pts; |
1518 | 696 StreamContext *stc; |
1477 | 697 |
1518 | 698 size= decode_frame_header(nut, &pts, &stream_id, frame_code); |
1477 | 699 if(size < 0) |
700 return -1; | |
701 | |
1518 | 702 stc= &nut->stream[stream_id]; |
703 | |
704 if (stc->last_flags & FLAG_KEY) | |
705 stc->skip_until_key_frame=0; | |
1517
51b29c17bd1f
skip non keyframes after seeking between syncpoint and the first keyframe
michael
parents:
1516
diff
changeset
|
706 |
1477 | 707 discard= s->streams[ stream_id ]->discard; |
708 last_IP_pts= s->streams[ stream_id ]->last_IP_pts; | |
1518 | 709 if( (discard >= AVDISCARD_NONKEY && !(stc->last_flags & FLAG_KEY)) |
1477 | 710 ||(discard >= AVDISCARD_BIDIR && last_IP_pts != AV_NOPTS_VALUE && last_IP_pts > pts) |
1517
51b29c17bd1f
skip non keyframes after seeking between syncpoint and the first keyframe
michael
parents:
1516
diff
changeset
|
711 || discard >= AVDISCARD_ALL |
1518 | 712 || stc->skip_until_key_frame){ |
1477 | 713 url_fskip(bc, size); |
714 return 1; | |
715 } | |
716 | |
717 av_get_packet(bc, pkt, size); | |
718 pkt->stream_index = stream_id; | |
1518 | 719 if (stc->last_flags & FLAG_KEY) |
1477 | 720 pkt->flags |= PKT_FLAG_KEY; |
721 pkt->pts = pts; | |
722 | |
723 return 0; | |
724 } | |
725 | |
726 static int nut_read_packet(AVFormatContext *s, AVPacket *pkt) | |
727 { | |
728 NUTContext *nut = s->priv_data; | |
729 ByteIOContext *bc = &s->pb; | |
730 int i, frame_code=0, ret, skip; | |
1500 | 731 int64_t ts, back_ptr; |
1477 | 732 |
733 for(;;){ | |
734 int64_t pos= url_ftell(bc); | |
735 uint64_t tmp= nut->next_startcode; | |
736 nut->next_startcode=0; | |
737 | |
738 if (url_feof(bc)) | |
739 return -1; | |
740 | |
741 if(tmp){ | |
742 pos-=8; | |
743 }else{ | |
744 frame_code = get_byte(bc); | |
745 if(frame_code == 'N'){ | |
746 tmp= frame_code; | |
747 for(i=1; i<8; i++) | |
748 tmp = (tmp<<8) + get_byte(bc); | |
749 } | |
750 } | |
751 switch(tmp){ | |
752 case MAIN_STARTCODE: | |
753 case STREAM_STARTCODE: | |
754 case INDEX_STARTCODE: | |
755 skip= get_packetheader(nut, bc, 0); | |
756 url_fseek(bc, skip, SEEK_CUR); | |
757 break; | |
758 case INFO_STARTCODE: | |
759 if(decode_info_header(nut)<0) | |
760 goto resync; | |
761 break; | |
762 case SYNCPOINT_STARTCODE: | |
1500 | 763 if(decode_syncpoint(nut, &ts, &back_ptr)<0) |
1477 | 764 goto resync; |
765 frame_code = get_byte(bc); | |
766 case 0: | |
767 ret= decode_frame(nut, pkt, frame_code); | |
768 if(ret==0) | |
769 return 0; | |
770 else if(ret==1) //ok but discard packet | |
771 break; | |
772 default: | |
773 resync: | |
774 av_log(s, AV_LOG_DEBUG, "syncing from %"PRId64"\n", pos); | |
1508 | 775 tmp= find_any_startcode(bc, nut->last_syncpoint_pos+1); |
1477 | 776 if(tmp==0) |
777 return -1; | |
778 av_log(s, AV_LOG_DEBUG, "sync\n"); | |
779 nut->next_startcode= tmp; | |
780 } | |
781 } | |
782 } | |
783 | |
1478 | 784 static int64_t nut_read_timestamp(AVFormatContext *s, int stream_index, int64_t *pos_arg, int64_t pos_limit){ |
785 NUTContext *nut = s->priv_data; | |
786 ByteIOContext *bc = &s->pb; | |
1500 | 787 int64_t pos, pts, back_ptr; |
1478 | 788 av_log(s, AV_LOG_DEBUG, "read_timestamp(X,%d,%"PRId64",%"PRId64")\n", stream_index, *pos_arg, pos_limit); |
789 | |
790 pos= *pos_arg; | |
791 resync: | |
792 do{ | |
793 pos= find_startcode(bc, SYNCPOINT_STARTCODE, pos)+1; | |
794 if(pos < 1){ | |
795 assert(nut->next_startcode == 0); | |
796 av_log(s, AV_LOG_ERROR, "read_timestamp failed\n"); | |
797 return AV_NOPTS_VALUE; | |
798 } | |
1500 | 799 }while(decode_syncpoint(nut, &pts, &back_ptr) < 0); |
1478 | 800 *pos_arg = pos-1; |
801 assert(nut->last_syncpoint_pos == *pos_arg); | |
802 | |
1500 | 803 av_log(s, AV_LOG_DEBUG, "return %Ld %Ld\n", pts,back_ptr ); |
804 if (stream_index == -1) return pts; | |
805 else if(stream_index == -2) return back_ptr; | |
806 | |
807 assert(0); | |
1478 | 808 } |
809 | |
1500 | 810 static int read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flags){ |
811 NUTContext *nut = s->priv_data; | |
812 AVStream *st= s->streams[stream_index]; | |
813 syncpoint_t dummy={.ts= pts*av_q2d(st->time_base)*AV_TIME_BASE}; | |
814 syncpoint_t nopts_sp= {.ts= AV_NOPTS_VALUE, .back_ptr= AV_NOPTS_VALUE}; | |
815 syncpoint_t *sp, *next_node[2]= {&nopts_sp, &nopts_sp}; | |
816 int64_t pos, pos2, ts; | |
1517
51b29c17bd1f
skip non keyframes after seeking between syncpoint and the first keyframe
michael
parents:
1516
diff
changeset
|
817 int i; |
1500 | 818 |
1501 | 819 if(st->index_entries){ |
820 int index= av_index_search_timestamp(st, pts, flags); | |
821 if(index<0) | |
822 return -1; | |
823 | |
824 pos2= st->index_entries[index].pos; | |
825 ts = st->index_entries[index].timestamp; | |
826 }else{ | |
1502 | 827 av_tree_find(nut->syncpoints, &dummy, sp_pts_cmp, next_node); |
828 av_log(s, AV_LOG_DEBUG, "%Ld-%Ld %Ld-%Ld\n", next_node[0]->pos, next_node[1]->pos, | |
829 next_node[0]->ts , next_node[1]->ts); | |
830 pos= av_gen_search(s, -1, dummy.ts, next_node[0]->pos, next_node[1]->pos, next_node[1]->pos, | |
831 next_node[0]->ts , next_node[1]->ts, AVSEEK_FLAG_BACKWARD, &ts, nut_read_timestamp); | |
1500 | 832 |
1502 | 833 if(!(flags & AVSEEK_FLAG_BACKWARD)){ |
834 dummy.pos= pos+16; | |
835 next_node[1]= &nopts_sp; | |
836 av_tree_find(nut->syncpoints, &dummy, sp_pos_cmp, next_node); | |
837 pos2= av_gen_search(s, -2, dummy.pos, next_node[0]->pos , next_node[1]->pos, next_node[1]->pos, | |
838 next_node[0]->back_ptr, next_node[1]->back_ptr, flags, &ts, nut_read_timestamp); | |
839 if(pos2>=0) | |
840 pos= pos2; | |
841 //FIXME dir but i think it doesnt matter | |
842 } | |
843 dummy.pos= pos; | |
844 sp= av_tree_find(nut->syncpoints, &dummy, sp_pos_cmp, NULL); | |
1500 | 845 |
1502 | 846 assert(sp); |
847 pos2= sp->back_ptr - 15; | |
1501 | 848 } |
849 av_log(NULL, AV_LOG_DEBUG, "SEEKTO: %"PRId64"\n", pos2); | |
850 pos= find_startcode(&s->pb, SYNCPOINT_STARTCODE, pos2); | |
1500 | 851 url_fseek(&s->pb, pos, SEEK_SET); |
852 av_log(NULL, AV_LOG_DEBUG, "SP: %"PRId64"\n", pos); | |
1501 | 853 if(pos2 > pos || pos2 + 15 < pos){ |
1500 | 854 av_log(NULL, AV_LOG_ERROR, "no syncpoint at backptr pos\n"); |
855 } | |
1517
51b29c17bd1f
skip non keyframes after seeking between syncpoint and the first keyframe
michael
parents:
1516
diff
changeset
|
856 for(i=0; i<s->nb_streams; i++) |
51b29c17bd1f
skip non keyframes after seeking between syncpoint and the first keyframe
michael
parents:
1516
diff
changeset
|
857 nut->stream[i].skip_until_key_frame=1; |
51b29c17bd1f
skip non keyframes after seeking between syncpoint and the first keyframe
michael
parents:
1516
diff
changeset
|
858 |
1500 | 859 return 0; |
860 } | |
861 | |
1477 | 862 static int nut_read_close(AVFormatContext *s) |
863 { | |
864 NUTContext *nut = s->priv_data; | |
865 | |
866 av_freep(&nut->time_base); | |
867 av_freep(&nut->stream); | |
868 | |
869 return 0; | |
870 } | |
871 | |
872 #ifdef CONFIG_NUT_DEMUXER | |
873 AVInputFormat nut_demuxer = { | |
874 "nut", | |
875 "nut format", | |
876 sizeof(NUTContext), | |
877 nut_probe, | |
878 nut_read_header, | |
879 nut_read_packet, | |
880 nut_read_close, | |
1500 | 881 read_seek, |
1477 | 882 .extensions = "nut", |
883 }; | |
884 #endif |