2 * "NUT" Container Format demuxer
3 * Copyright (c) 2004-2006 Michael Niedermayer
4 * Copyright (c) 2003 Alex Beregszaszi
6 * This file is part of FFmpeg.
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.
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.
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
30 static int get_str(ByteIOContext
*bc
, char *string
, unsigned int maxlen
){
31 unsigned int len
= ff_get_v(bc
);
34 get_buffer(bc
, string
, FFMIN(len
, maxlen
));
41 string
[FFMIN(len
, maxlen
-1)]= 0;
49 static int64_t get_s(ByteIOContext
*bc
){
50 int64_t v
= ff_get_v(bc
) + 1;
52 if (v
&1) return -(v
>>1);
56 static uint64_t get_fourcc(ByteIOContext
*bc
){
57 unsigned int len
= ff_get_v(bc
);
59 if (len
==2) return get_le16(bc
);
60 else if(len
==4) return get_le32(bc
);
65 static inline uint64_t get_v_trace(ByteIOContext
*bc
, char *file
, char *func
, int line
){
66 uint64_t v
= ff_get_v(bc
);
68 av_log(NULL
, AV_LOG_DEBUG
, "get_v %5"PRId64
" / %"PRIX64
" in %s %s:%d\n", v
, v
, file
, func
, line
);
72 static inline int64_t get_s_trace(ByteIOContext
*bc
, char *file
, char *func
, int line
){
75 av_log(NULL
, AV_LOG_DEBUG
, "get_s %5"PRId64
" / %"PRIX64
" in %s %s:%d\n", v
, v
, file
, func
, line
);
79 static inline uint64_t get_vb_trace(ByteIOContext
*bc
, char *file
, char *func
, int line
){
80 uint64_t v
= get_vb(bc
);
82 av_log(NULL
, AV_LOG_DEBUG
, "get_vb %5"PRId64
" / %"PRIX64
" in %s %s:%d\n", v
, v
, file
, func
, line
);
85 #define ff_get_v(bc) get_v_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
86 #define get_s(bc) get_s_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
87 #define get_vb(bc) get_vb_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
90 static int get_packetheader(NUTContext
*nut
, ByteIOContext
*bc
, int calculate_checksum
, uint64_t startcode
)
93 // start= url_ftell(bc) - 8;
95 startcode
= be2me_64(startcode
);
96 startcode
= ff_crc04C11DB7_update(0, &startcode
, 8);
98 init_checksum(bc
, ff_crc04C11DB7_update
, startcode
);
102 if(get_checksum(bc
) && size
> 4096)
105 init_checksum(bc
, calculate_checksum ? ff_crc04C11DB7_update
: NULL
, 0);
110 static uint64_t find_any_startcode(ByteIOContext
*bc
, int64_t pos
){
114 url_fseek(bc
, pos
, SEEK_SET
); //note, this may fail if the stream is not seekable, but that should not matter, as in this case we simply start where we are currently
116 while(!url_feof(bc
)){
117 state
= (state
<<8) | get_byte(bc
);
118 if((state
>>56) != 'N')
122 case STREAM_STARTCODE
:
123 case SYNCPOINT_STARTCODE
:
125 case INDEX_STARTCODE
:
134 * Find the given startcode.
135 * @param code the startcode
136 * @param pos the start position of the search, or -1 if the current position
137 * @returns the position of the startcode or -1 if not found
139 static int64_t find_startcode(ByteIOContext
*bc
, uint64_t code
, int64_t pos
){
141 uint64_t startcode
= find_any_startcode(bc
, pos
);
142 if(startcode
== code
)
143 return url_ftell(bc
) - 8;
144 else if(startcode
== 0)
150 static int nut_probe(AVProbeData
*p
){
154 for (i
= 0; i
< p
->buf_size
; i
++) {
155 code
= (code
<< 8) | p
->buf
[i
];
156 if (code
== MAIN_STARTCODE
)
157 return AVPROBE_SCORE_MAX
;
162 #define GET_V(dst, check) \
165 av_log(s, AV_LOG_ERROR, "Error " #dst " is (%"PRId64")\n", tmp);\
170 static int skip_reserved(ByteIOContext
*bc
, int64_t pos
){
171 pos
-= url_ftell(bc
);
173 url_fseek(bc
, pos
, SEEK_CUR
);
182 static int decode_main_header(NUTContext
*nut
){
183 AVFormatContext
*s
= nut
->avf
;
184 ByteIOContext
*bc
= s
->pb
;
186 unsigned int stream_count
;
187 int i
, j
, tmp_stream
, tmp_mul
, tmp_pts
, tmp_size
, count
, tmp_res
;
189 end
= get_packetheader(nut
, bc
, 1, MAIN_STARTCODE
);
190 end
+= url_ftell(bc
);
192 GET_V(tmp
, tmp
>=2 && tmp
<= 3)
193 GET_V(stream_count
, tmp
> 0 && tmp
<=MAX_STREAMS
)
195 nut
->max_distance
= ff_get_v(bc
);
196 if(nut
->max_distance
> 65536){
197 av_log(s
, AV_LOG_DEBUG
, "max_distance %d\n", nut
->max_distance
);
198 nut
->max_distance
= 65536;
201 GET_V(nut
->time_base_count
, tmp
>0 && tmp
<INT_MAX
/ sizeof(AVRational
))
202 nut
->time_base
= av_malloc(nut
->time_base_count
* sizeof(AVRational
));
204 for(i
=0; i
<nut
->time_base_count
; i
++){
205 GET_V(nut
->time_base
[i
].num
, tmp
>0 && tmp
<(1ULL<<31))
206 GET_V(nut
->time_base
[i
].den
, tmp
>0 && tmp
<(1ULL<<31))
207 if(ff_gcd(nut
->time_base
[i
].num
, nut
->time_base
[i
].den
) != 1){
208 av_log(s
, AV_LOG_ERROR
, "time base invalid\n");
216 int tmp_flags
= ff_get_v(bc
);
217 int tmp_fields
= ff_get_v(bc
);
218 if(tmp_fields
>0) tmp_pts
= get_s(bc
);
219 if(tmp_fields
>1) tmp_mul
= ff_get_v(bc
);
220 if(tmp_fields
>2) tmp_stream
= ff_get_v(bc
);
221 if(tmp_fields
>3) tmp_size
= ff_get_v(bc
);
223 if(tmp_fields
>4) tmp_res
= ff_get_v(bc
);
225 if(tmp_fields
>5) count
= ff_get_v(bc
);
226 else count
= tmp_mul
- tmp_size
;
228 while(tmp_fields
-- > 6)
231 if(count
== 0 || i
+count
> 256){
232 av_log(s
, AV_LOG_ERROR
, "illegal count %d at %d\n", count
, i
);
235 if(tmp_stream
>= stream_count
){
236 av_log(s
, AV_LOG_ERROR
, "illegal stream number\n");
240 for(j
=0; j
<count
; j
++,i
++){
242 nut
->frame_code
[i
].flags
= FLAG_INVALID
;
246 nut
->frame_code
[i
].flags
= tmp_flags
;
247 nut
->frame_code
[i
].pts_delta
= tmp_pts
;
248 nut
->frame_code
[i
].stream_id
= tmp_stream
;
249 nut
->frame_code
[i
].size_mul
= tmp_mul
;
250 nut
->frame_code
[i
].size_lsb
= tmp_size
+j
;
251 nut
->frame_code
[i
].reserved_count
= tmp_res
;
254 assert(nut
->frame_code
['N'].flags
== FLAG_INVALID
);
256 if(skip_reserved(bc
, end
) || get_checksum(bc
)){
257 av_log(s
, AV_LOG_ERROR
, "main header checksum mismatch\n");
261 nut
->stream
= av_mallocz(sizeof(StreamContext
)*stream_count
);
262 for(i
=0; i
<stream_count
; i
++){
269 static int decode_stream_header(NUTContext
*nut
){
270 AVFormatContext
*s
= nut
->avf
;
271 ByteIOContext
*bc
= s
->pb
;
273 int class, stream_id
;
277 end
= get_packetheader(nut
, bc
, 1, STREAM_STARTCODE
);
278 end
+= url_ftell(bc
);
280 GET_V(stream_id
, tmp
< s
->nb_streams
&& !nut
->stream
[tmp
].time_base
);
281 stc
= &nut
->stream
[stream_id
];
283 st
= s
->streams
[stream_id
];
285 return AVERROR(ENOMEM
);
287 class = ff_get_v(bc
);
288 tmp
= get_fourcc(bc
);
289 st
->codec
->codec_tag
= tmp
;
293 st
->codec
->codec_type
= CODEC_TYPE_VIDEO
;
294 st
->codec
->codec_id
= codec_get_id(codec_bmp_tags
, tmp
);
295 if (st
->codec
->codec_id
== CODEC_ID_NONE
)
296 av_log(s
, AV_LOG_ERROR
, "Unknown codec?!\n");
299 st
->codec
->codec_type
= CODEC_TYPE_AUDIO
;
300 st
->codec
->codec_id
= codec_get_id(codec_wav_tags
, tmp
);
301 if (st
->codec
->codec_id
== CODEC_ID_NONE
)
302 av_log(s
, AV_LOG_ERROR
, "Unknown codec?!\n");
305 // st->codec->codec_type = CODEC_TYPE_TEXT;
308 st
->codec
->codec_type
= CODEC_TYPE_DATA
;
311 av_log(s
, AV_LOG_ERROR
, "unknown stream class (%d)\n", class);
314 GET_V(stc
->time_base_id
, tmp
< nut
->time_base_count
);
315 GET_V(stc
->msb_pts_shift
, tmp
< 16);
316 stc
->max_pts_distance
= ff_get_v(bc
);
317 GET_V(stc
->decode_delay
, tmp
< 1000); //sanity limit, raise this if Moore's law is true
318 st
->codec
->has_b_frames
= stc
->decode_delay
;
319 ff_get_v(bc
); //stream flags
321 GET_V(st
->codec
->extradata_size
, tmp
< (1<<30));
322 if(st
->codec
->extradata_size
){
323 st
->codec
->extradata
= av_mallocz(st
->codec
->extradata_size
+ FF_INPUT_BUFFER_PADDING_SIZE
);
324 get_buffer(bc
, st
->codec
->extradata
, st
->codec
->extradata_size
);
327 if (st
->codec
->codec_type
== CODEC_TYPE_VIDEO
){
328 GET_V(st
->codec
->width
, tmp
> 0)
329 GET_V(st
->codec
->height
, tmp
> 0)
330 st
->codec
->sample_aspect_ratio
.num
= ff_get_v(bc
);
331 st
->codec
->sample_aspect_ratio
.den
= ff_get_v(bc
);
332 if((!st
->codec
->sample_aspect_ratio
.num
) != (!st
->codec
->sample_aspect_ratio
.den
)){
333 av_log(s
, AV_LOG_ERROR
, "invalid aspect ratio %d/%d\n", st
->codec
->sample_aspect_ratio
.num
, st
->codec
->sample_aspect_ratio
.den
);
336 ff_get_v(bc
); /* csp type */
337 }else if (st
->codec
->codec_type
== CODEC_TYPE_AUDIO
){
338 GET_V(st
->codec
->sample_rate
, tmp
> 0)
339 ff_get_v(bc
); // samplerate_den
340 GET_V(st
->codec
->channels
, tmp
> 0)
342 if(skip_reserved(bc
, end
) || get_checksum(bc
)){
343 av_log(s
, AV_LOG_ERROR
, "stream header %d checksum mismatch\n", stream_id
);
346 stc
->time_base
= &nut
->time_base
[stc
->time_base_id
];
347 av_set_pts_info(s
->streams
[stream_id
], 63, stc
->time_base
->num
, stc
->time_base
->den
);
351 static int decode_info_header(NUTContext
*nut
){
352 AVFormatContext
*s
= nut
->avf
;
353 ByteIOContext
*bc
= s
->pb
;
355 unsigned int stream_id_plus1
, chapter_start
, chapter_len
, count
;
358 char name
[256], str_value
[1024], type_str
[256];
361 end
= get_packetheader(nut
, bc
, 1, INFO_STARTCODE
);
362 end
+= url_ftell(bc
);
364 GET_V(stream_id_plus1
, tmp
<= s
->nb_streams
)
365 chapter_id
= get_s(bc
);
366 chapter_start
= ff_get_v(bc
);
367 chapter_len
= ff_get_v(bc
);
368 count
= ff_get_v(bc
);
369 for(i
=0; i
<count
; i
++){
370 get_str(bc
, name
, sizeof(name
));
374 get_str(bc
, str_value
, sizeof(str_value
));
375 }else if(value
== -2){
376 get_str(bc
, type_str
, sizeof(type_str
));
378 get_str(bc
, str_value
, sizeof(str_value
));
379 }else if(value
== -3){
382 }else if(value
== -4){
385 }else if(value
< -4){
392 if(chapter_id
==0 && !strcmp(type
, "UTF-8")){
393 if (!strcmp(name
, "Author"))
394 av_strlcpy(s
->author
, str_value
, sizeof(s
->author
));
395 else if(!strcmp(name
, "Title"))
396 av_strlcpy(s
->title
, str_value
, sizeof(s
->title
));
397 else if(!strcmp(name
, "Copyright"))
398 av_strlcpy(s
->copyright
, str_value
, sizeof(s
->copyright
));
399 else if(!strcmp(name
, "Description"))
400 av_strlcpy(s
->comment
, str_value
, sizeof(s
->comment
));
404 if(skip_reserved(bc
, end
) || get_checksum(bc
)){
405 av_log(s
, AV_LOG_ERROR
, "info header checksum mismatch\n");
411 static int decode_syncpoint(NUTContext
*nut
, int64_t *ts
, int64_t *back_ptr
){
412 AVFormatContext
*s
= nut
->avf
;
413 ByteIOContext
*bc
= s
->pb
;
416 nut
->last_syncpoint_pos
= url_ftell(bc
)-8;
418 end
= get_packetheader(nut
, bc
, 1, SYNCPOINT_STARTCODE
);
419 end
+= url_ftell(bc
);
422 *back_ptr
= nut
->last_syncpoint_pos
- 16*ff_get_v(bc
);
426 ff_nut_reset_ts(nut
, nut
->time_base
[tmp
% nut
->time_base_count
], tmp
/ nut
->time_base_count
);
428 if(skip_reserved(bc
, end
) || get_checksum(bc
)){
429 av_log(s
, AV_LOG_ERROR
, "sync point checksum mismatch\n");
433 *ts
= tmp
/ s
->nb_streams
* av_q2d(nut
->time_base
[tmp
% s
->nb_streams
])*AV_TIME_BASE
;
434 ff_nut_add_sp(nut
, nut
->last_syncpoint_pos
, *back_ptr
, *ts
);
439 static int find_and_decode_index(NUTContext
*nut
){
440 AVFormatContext
*s
= nut
->avf
;
441 ByteIOContext
*bc
= s
->pb
;
443 int i
, j
, syncpoint_count
;
444 int64_t filesize
= url_fsize(bc
);
446 int8_t *has_keyframe
;
448 url_fseek(bc
, filesize
-12, SEEK_SET
);
449 url_fseek(bc
, filesize
-get_be64(bc
), SEEK_SET
);
450 if(get_be64(bc
) != INDEX_STARTCODE
){
451 av_log(s
, AV_LOG_ERROR
, "no index at the end\n");
455 end
= get_packetheader(nut
, bc
, 1, INDEX_STARTCODE
);
456 end
+= url_ftell(bc
);
458 ff_get_v(bc
); //max_pts
459 GET_V(syncpoint_count
, tmp
< INT_MAX
/8 && tmp
> 0)
460 syncpoints
= av_malloc(sizeof(int64_t)*syncpoint_count
);
461 has_keyframe
= av_malloc(sizeof(int8_t)*(syncpoint_count
+1));
462 for(i
=0; i
<syncpoint_count
; i
++){
463 GET_V(syncpoints
[i
], tmp
>0)
465 syncpoints
[i
] += syncpoints
[i
-1];
468 for(i
=0; i
<s
->nb_streams
; i
++){
469 int64_t last_pts
= -1;
470 for(j
=0; j
<syncpoint_count
;){
471 uint64_t x
= ff_get_v(bc
);
478 if(n
+x
>= syncpoint_count
+ 1){
479 av_log(s
, AV_LOG_ERROR
, "index overflow A\n");
483 has_keyframe
[n
++]= flag
;
484 has_keyframe
[n
++]= !flag
;
487 if(n
>=syncpoint_count
+ 1){
488 av_log(s
, AV_LOG_ERROR
, "index overflow B\n");
491 has_keyframe
[n
++]= x
&1;
496 av_log(s
, AV_LOG_ERROR
, "keyframe before first syncpoint in index\n");
499 assert(n
<=syncpoint_count
+1);
500 for(; j
<n
&& j
<syncpoint_count
; j
++){
502 uint64_t B
, A
= ff_get_v(bc
);
506 //eor_pts[j][i] = last_pts + A + B
522 if(skip_reserved(bc
, end
) || get_checksum(bc
)){
523 av_log(s
, AV_LOG_ERROR
, "index checksum mismatch\n");
529 static int nut_read_header(AVFormatContext
*s
, AVFormatParameters
*ap
)
531 NUTContext
*nut
= s
->priv_data
;
532 ByteIOContext
*bc
= s
->pb
;
534 int initialized_stream_count
;
541 pos
= find_startcode(bc
, MAIN_STARTCODE
, pos
)+1;
543 av_log(s
, AV_LOG_ERROR
, "No main startcode found.\n");
546 }while(decode_main_header(nut
) < 0);
550 for(initialized_stream_count
=0; initialized_stream_count
< s
->nb_streams
;){
551 pos
= find_startcode(bc
, STREAM_STARTCODE
, pos
)+1;
553 av_log(s
, AV_LOG_ERROR
, "Not all stream headers found.\n");
556 if(decode_stream_header(nut
) >= 0)
557 initialized_stream_count
++;
563 uint64_t startcode
= find_any_startcode(bc
, pos
);
567 av_log(s
, AV_LOG_ERROR
, "EOF before video frames\n");
569 }else if(startcode
== SYNCPOINT_STARTCODE
){
570 nut
->next_startcode
= startcode
;
572 }else if(startcode
!= INFO_STARTCODE
){
576 decode_info_header(nut
);
579 s
->data_offset
= pos
-8;
581 if(!url_is_streamed(bc
)){
582 int64_t orig_pos
= url_ftell(bc
);
583 find_and_decode_index(nut
);
584 url_fseek(bc
, orig_pos
, SEEK_SET
);
586 assert(nut
->next_startcode
== SYNCPOINT_STARTCODE
);
591 static int decode_frame_header(NUTContext
*nut
, int64_t *pts
, int *stream_id
, int frame_code
){
592 AVFormatContext
*s
= nut
->avf
;
593 ByteIOContext
*bc
= s
->pb
;
595 int size
, flags
, size_mul
, pts_delta
, i
, reserved_count
;
598 if(url_ftell(bc
) > nut
->last_syncpoint_pos
+ nut
->max_distance
){
599 av_log(s
, AV_LOG_ERROR
, "Last frame must have been damaged %"PRId64
" > %"PRId64
" + %d\n", url_ftell(bc
), nut
->last_syncpoint_pos
, nut
->max_distance
);
603 flags
= nut
->frame_code
[frame_code
].flags
;
604 size_mul
= nut
->frame_code
[frame_code
].size_mul
;
605 size
= nut
->frame_code
[frame_code
].size_lsb
;
606 *stream_id
= nut
->frame_code
[frame_code
].stream_id
;
607 pts_delta
= nut
->frame_code
[frame_code
].pts_delta
;
608 reserved_count
= nut
->frame_code
[frame_code
].reserved_count
;
610 if(flags
& FLAG_INVALID
)
612 if(flags
& FLAG_CODED
)
613 flags
^= ff_get_v(bc
);
614 if(flags
& FLAG_STREAM_ID
){
615 GET_V(*stream_id
, tmp
< s
->nb_streams
)
617 stc
= &nut
->stream
[*stream_id
];
618 if(flags
&FLAG_CODED_PTS
){
619 int coded_pts
= ff_get_v(bc
);
620 //FIXME check last_pts validity?
621 if(coded_pts
< (1<<stc
->msb_pts_shift
)){
622 *pts
=ff_lsb2full(stc
, coded_pts
);
624 *pts
=coded_pts
- (1<<stc
->msb_pts_shift
);
626 *pts
= stc
->last_pts
+ pts_delta
;
627 if(flags
&FLAG_SIZE_MSB
){
628 size
+= size_mul
*ff_get_v(bc
);
630 if(flags
&FLAG_RESERVED
)
631 reserved_count
= ff_get_v(bc
);
632 for(i
=0; i
<reserved_count
; i
++)
634 if(flags
&FLAG_CHECKSUM
){
635 get_be32(bc
); //FIXME check this
636 }else if(size
> 2*nut
->max_distance
|| FFABS(stc
->last_pts
- *pts
) > stc
->max_pts_distance
){
637 av_log(s
, AV_LOG_ERROR
, "frame size > 2max_distance and no checksum\n");
642 stc
->last_flags
= flags
;
647 static int decode_frame(NUTContext
*nut
, AVPacket
*pkt
, int frame_code
){
648 AVFormatContext
*s
= nut
->avf
;
649 ByteIOContext
*bc
= s
->pb
;
650 int size
, stream_id
, discard
;
651 int64_t pts
, last_IP_pts
;
654 size
= decode_frame_header(nut
, &pts
, &stream_id
, frame_code
);
658 stc
= &nut
->stream
[stream_id
];
660 if (stc
->last_flags
& FLAG_KEY
)
661 stc
->skip_until_key_frame
=0;
663 discard
= s
->streams
[ stream_id
]->discard
;
664 last_IP_pts
= s
->streams
[ stream_id
]->last_IP_pts
;
665 if( (discard
>= AVDISCARD_NONKEY
&& !(stc
->last_flags
& FLAG_KEY
))
666 ||(discard
>= AVDISCARD_BIDIR
&& last_IP_pts
!= AV_NOPTS_VALUE
&& last_IP_pts
> pts
)
667 || discard
>= AVDISCARD_ALL
668 || stc
->skip_until_key_frame
){
673 av_get_packet(bc
, pkt
, size
);
674 pkt
->stream_index
= stream_id
;
675 if (stc
->last_flags
& FLAG_KEY
)
676 pkt
->flags
|= PKT_FLAG_KEY
;
682 static int nut_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
684 NUTContext
*nut
= s
->priv_data
;
685 ByteIOContext
*bc
= s
->pb
;
686 int i
, frame_code
=0, ret
, skip
;
687 int64_t ts
, back_ptr
;
690 int64_t pos
= url_ftell(bc
);
691 uint64_t tmp
= nut
->next_startcode
;
692 nut
->next_startcode
=0;
697 frame_code
= get_byte(bc
);
700 if(frame_code
== 'N'){
703 tmp
= (tmp
<<8) + get_byte(bc
);
708 case STREAM_STARTCODE
:
709 case INDEX_STARTCODE
:
710 skip
= get_packetheader(nut
, bc
, 0, tmp
);
711 url_fseek(bc
, skip
, SEEK_CUR
);
714 if(decode_info_header(nut
)<0)
717 case SYNCPOINT_STARTCODE
:
718 if(decode_syncpoint(nut
, &ts
, &back_ptr
)<0)
720 frame_code
= get_byte(bc
);
722 ret
= decode_frame(nut
, pkt
, frame_code
);
725 else if(ret
==1) //ok but discard packet
729 av_log(s
, AV_LOG_DEBUG
, "syncing from %"PRId64
"\n", pos
);
730 tmp
= find_any_startcode(bc
, nut
->last_syncpoint_pos
+1);
733 av_log(s
, AV_LOG_DEBUG
, "sync\n");
734 nut
->next_startcode
= tmp
;
739 static int64_t nut_read_timestamp(AVFormatContext
*s
, int stream_index
, int64_t *pos_arg
, int64_t pos_limit
){
740 NUTContext
*nut
= s
->priv_data
;
741 ByteIOContext
*bc
= s
->pb
;
742 int64_t pos
, pts
, back_ptr
;
743 av_log(s
, AV_LOG_DEBUG
, "read_timestamp(X,%d,%"PRId64
",%"PRId64
")\n", stream_index
, *pos_arg
, pos_limit
);
747 pos
= find_startcode(bc
, SYNCPOINT_STARTCODE
, pos
)+1;
749 assert(nut
->next_startcode
== 0);
750 av_log(s
, AV_LOG_ERROR
, "read_timestamp failed.\n");
751 return AV_NOPTS_VALUE
;
753 }while(decode_syncpoint(nut
, &pts
, &back_ptr
) < 0);
755 assert(nut
->last_syncpoint_pos
== *pos_arg
);
757 av_log(s
, AV_LOG_DEBUG
, "return %"PRId64
" %"PRId64
"\n", pts
,back_ptr
);
758 if (stream_index
== -1) return pts
;
759 else if(stream_index
== -2) return back_ptr
;
764 static int read_seek(AVFormatContext
*s
, int stream_index
, int64_t pts
, int flags
){
765 NUTContext
*nut
= s
->priv_data
;
766 AVStream
*st
= s
->streams
[stream_index
];
767 syncpoint_t dummy
={.ts
= pts
*av_q2d(st
->time_base
)*AV_TIME_BASE
};
768 syncpoint_t nopts_sp
= {.ts
= AV_NOPTS_VALUE
, .back_ptr
= AV_NOPTS_VALUE
};
769 syncpoint_t
*sp
, *next_node
[2]= {&nopts_sp
, &nopts_sp
};
770 int64_t pos
, pos2
, ts
;
773 if(st
->index_entries
){
774 int index
= av_index_search_timestamp(st
, pts
, flags
);
778 pos2
= st
->index_entries
[index
].pos
;
779 ts
= st
->index_entries
[index
].timestamp
;
781 av_tree_find(nut
->syncpoints
, &dummy
, ff_nut_sp_pts_cmp
, next_node
);
782 av_log(s
, AV_LOG_DEBUG
, "%"PRIu64
"-%"PRIu64
" %"PRId64
"-%"PRId64
"\n", next_node
[0]->pos
, next_node
[1]->pos
,
783 next_node
[0]->ts
, next_node
[1]->ts
);
784 pos
= av_gen_search(s
, -1, dummy
.ts
, next_node
[0]->pos
, next_node
[1]->pos
, next_node
[1]->pos
,
785 next_node
[0]->ts
, next_node
[1]->ts
, AVSEEK_FLAG_BACKWARD
, &ts
, nut_read_timestamp
);
787 if(!(flags
& AVSEEK_FLAG_BACKWARD
)){
789 next_node
[1]= &nopts_sp
;
790 av_tree_find(nut
->syncpoints
, &dummy
, ff_nut_sp_pos_cmp
, next_node
);
791 pos2
= av_gen_search(s
, -2, dummy
.pos
, next_node
[0]->pos
, next_node
[1]->pos
, next_node
[1]->pos
,
792 next_node
[0]->back_ptr
, next_node
[1]->back_ptr
, flags
, &ts
, nut_read_timestamp
);
795 //FIXME dir but i think it does not matter
798 sp
= av_tree_find(nut
->syncpoints
, &dummy
, ff_nut_sp_pos_cmp
, NULL
);
801 pos2
= sp
->back_ptr
- 15;
803 av_log(NULL
, AV_LOG_DEBUG
, "SEEKTO: %"PRId64
"\n", pos2
);
804 pos
= find_startcode(s
->pb
, SYNCPOINT_STARTCODE
, pos2
);
805 url_fseek(s
->pb
, pos
, SEEK_SET
);
806 av_log(NULL
, AV_LOG_DEBUG
, "SP: %"PRId64
"\n", pos
);
807 if(pos2
> pos
|| pos2
+ 15 < pos
){
808 av_log(NULL
, AV_LOG_ERROR
, "no syncpoint at backptr pos\n");
810 for(i
=0; i
<s
->nb_streams
; i
++)
811 nut
->stream
[i
].skip_until_key_frame
=1;
816 static int nut_read_close(AVFormatContext
*s
)
818 NUTContext
*nut
= s
->priv_data
;
820 av_freep(&nut
->time_base
);
821 av_freep(&nut
->stream
);
826 #ifdef CONFIG_NUT_DEMUXER
827 AVInputFormat nut_demuxer
= {