Mercurial > libavformat.hg
annotate nutdec.c @ 3343:201853ef633e libavformat
Make av_fifo*_read() ignore the available amount of data.
This is more efficient as in practice the check is redundant most of the
time. Callers which do not know if enough data is available have to check
it with av_fifo_size(). Doing the check in *read() means the caller has
no choice to skip the check when its known to be redundant.
Also the return value was never documented in a public header so
changing it should not break the API. Besides this fixes the case where
read() failed on a 100% full fifo.
author | michael |
---|---|
date | Sun, 25 May 2008 22:20:39 +0000 |
parents | 7a823a401282 |
children | 7b34cd9dfe85 |
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 | |
3286 | 23 #include "libavutil/avstring.h" |
24 #include "libavutil/tree.h" | |
1477 | 25 #include "nut.h" |
26 | |
27 #undef NDEBUG | |
28 #include <assert.h> | |
29 | |
30 static int get_str(ByteIOContext *bc, char *string, unsigned int maxlen){ | |
2700 | 31 unsigned int len= ff_get_v(bc); |
1477 | 32 |
33 if(len && maxlen) | |
34 get_buffer(bc, string, FFMIN(len, maxlen)); | |
35 while(len > maxlen){ | |
36 get_byte(bc); | |
37 len--; | |
38 } | |
39 | |
40 if(maxlen) | |
41 string[FFMIN(len, maxlen-1)]= 0; | |
42 | |
43 if(maxlen == len) | |
44 return -1; | |
45 else | |
46 return 0; | |
47 } | |
48 | |
49 static int64_t get_s(ByteIOContext *bc){ | |
2700 | 50 int64_t v = ff_get_v(bc) + 1; |
1477 | 51 |
52 if (v&1) return -(v>>1); | |
53 else return (v>>1); | |
54 } | |
55 | |
56 static uint64_t get_fourcc(ByteIOContext *bc){ | |
2700 | 57 unsigned int len= ff_get_v(bc); |
1477 | 58 |
59 if (len==2) return get_le16(bc); | |
60 else if(len==4) return get_le32(bc); | |
61 else return -1; | |
62 } | |
63 | |
64 #ifdef TRACE | |
65 static inline uint64_t get_v_trace(ByteIOContext *bc, char *file, char *func, int line){ | |
2700 | 66 uint64_t v= ff_get_v(bc); |
1477 | 67 |
2344 | 68 av_log(NULL, AV_LOG_DEBUG, "get_v %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); |
1477 | 69 return v; |
70 } | |
71 | |
72 static inline int64_t get_s_trace(ByteIOContext *bc, char *file, char *func, int line){ | |
73 int64_t v= get_s(bc); | |
74 | |
2344 | 75 av_log(NULL, AV_LOG_DEBUG, "get_s %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); |
1477 | 76 return v; |
77 } | |
78 | |
79 static inline uint64_t get_vb_trace(ByteIOContext *bc, char *file, char *func, int line){ | |
80 uint64_t v= get_vb(bc); | |
81 | |
2344 | 82 av_log(NULL, AV_LOG_DEBUG, "get_vb %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); |
1477 | 83 return v; |
84 } | |
2700 | 85 #define ff_get_v(bc) get_v_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__) |
1477 | 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__) | |
88 #endif | |
89 | |
2348 | 90 static int get_packetheader(NUTContext *nut, ByteIOContext *bc, int calculate_checksum, uint64_t startcode) |
1477 | 91 { |
2035 | 92 int64_t size; |
1477 | 93 // start= url_ftell(bc) - 8; |
94 | |
2348 | 95 startcode= be2me_64(startcode); |
2683
153d6efc05b8
rename av_crc04C11DB7_update to ff_crc04C11DB7_update and move it to aviobuf.c so it can be reused by other (de)muxers
bcoudurier
parents:
2553
diff
changeset
|
96 startcode= ff_crc04C11DB7_update(0, &startcode, 8); |
2348 | 97 |
2683
153d6efc05b8
rename av_crc04C11DB7_update to ff_crc04C11DB7_update and move it to aviobuf.c so it can be reused by other (de)muxers
bcoudurier
parents:
2553
diff
changeset
|
98 init_checksum(bc, ff_crc04C11DB7_update, startcode); |
2700 | 99 size= ff_get_v(bc); |
1820
ec025d5fbbe2
get_packetheader() forgot to read the header_checksum in big packets
lu_zero
parents:
1682
diff
changeset
|
100 if(size > 4096) |
2333 | 101 get_be32(bc); |
102 if(get_checksum(bc) && size > 4096) | |
103 return -1; | |
1477 | 104 |
2683
153d6efc05b8
rename av_crc04C11DB7_update to ff_crc04C11DB7_update and move it to aviobuf.c so it can be reused by other (de)muxers
bcoudurier
parents:
2553
diff
changeset
|
105 init_checksum(bc, calculate_checksum ? ff_crc04C11DB7_update : NULL, 0); |
1477 | 106 |
107 return size; | |
108 } | |
109 | |
110 static uint64_t find_any_startcode(ByteIOContext *bc, int64_t pos){ | |
111 uint64_t state=0; | |
112 | |
113 if(pos >= 0) | |
3142 | 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 currently are |
1477 | 115 |
116 while(!url_feof(bc)){ | |
117 state= (state<<8) | get_byte(bc); | |
118 if((state>>56) != 'N') | |
119 continue; | |
120 switch(state){ | |
121 case MAIN_STARTCODE: | |
122 case STREAM_STARTCODE: | |
123 case SYNCPOINT_STARTCODE: | |
124 case INFO_STARTCODE: | |
125 case INDEX_STARTCODE: | |
126 return state; | |
127 } | |
128 } | |
129 | |
130 return 0; | |
131 } | |
132 | |
133 /** | |
2393 | 134 * Find the given startcode. |
1477 | 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 | |
138 */ | |
139 static int64_t find_startcode(ByteIOContext *bc, uint64_t code, int64_t pos){ | |
140 for(;;){ | |
141 uint64_t startcode= find_any_startcode(bc, pos); | |
142 if(startcode == code) | |
143 return url_ftell(bc) - 8; | |
144 else if(startcode == 0) | |
145 return -1; | |
146 pos=-1; | |
147 } | |
148 } | |
149 | |
150 static int nut_probe(AVProbeData *p){ | |
151 int i; | |
152 uint64_t code= 0; | |
153 | |
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; | |
158 } | |
159 return 0; | |
160 } | |
161 | |
162 #define GET_V(dst, check) \ | |
2700 | 163 tmp= ff_get_v(bc);\ |
1477 | 164 if(!(check)){\ |
165 av_log(s, AV_LOG_ERROR, "Error " #dst " is (%"PRId64")\n", tmp);\ | |
166 return -1;\ | |
167 }\ | |
168 dst= tmp; | |
169 | |
170 static int skip_reserved(ByteIOContext *bc, int64_t pos){ | |
171 pos -= url_ftell(bc); | |
172 if(pos<0){ | |
173 url_fseek(bc, pos, SEEK_CUR); | |
174 return -1; | |
175 }else{ | |
176 while(pos--) | |
177 get_byte(bc); | |
178 return 0; | |
179 } | |
180 } | |
181 | |
182 static int decode_main_header(NUTContext *nut){ | |
183 AVFormatContext *s= nut->avf; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2700
diff
changeset
|
184 ByteIOContext *bc = s->pb; |
1477 | 185 uint64_t tmp, end; |
186 unsigned int stream_count; | |
3045 | 187 int i, j, tmp_stream, tmp_mul, tmp_pts, tmp_size, count, tmp_res, tmp_head_idx; |
3043 | 188 int64_t tmp_match; |
1477 | 189 |
2348 | 190 end= get_packetheader(nut, bc, 1, MAIN_STARTCODE); |
1485 | 191 end += url_ftell(bc); |
1477 | 192 |
193 GET_V(tmp , tmp >=2 && tmp <= 3) | |
194 GET_V(stream_count , tmp > 0 && tmp <=MAX_STREAMS) | |
195 | |
2700 | 196 nut->max_distance = ff_get_v(bc); |
1477 | 197 if(nut->max_distance > 65536){ |
198 av_log(s, AV_LOG_DEBUG, "max_distance %d\n", nut->max_distance); | |
199 nut->max_distance= 65536; | |
200 } | |
201 | |
202 GET_V(nut->time_base_count, tmp>0 && tmp<INT_MAX / sizeof(AVRational)) | |
203 nut->time_base= av_malloc(nut->time_base_count * sizeof(AVRational)); | |
204 | |
205 for(i=0; i<nut->time_base_count; i++){ | |
206 GET_V(nut->time_base[i].num, tmp>0 && tmp<(1ULL<<31)) | |
207 GET_V(nut->time_base[i].den, tmp>0 && tmp<(1ULL<<31)) | |
208 if(ff_gcd(nut->time_base[i].num, nut->time_base[i].den) != 1){ | |
209 av_log(s, AV_LOG_ERROR, "time base invalid\n"); | |
210 return -1; | |
211 } | |
212 } | |
213 tmp_pts=0; | |
214 tmp_mul=1; | |
215 tmp_stream=0; | |
3043 | 216 tmp_match= 1-(1LL<<62); |
3045 | 217 tmp_head_idx= 0; |
1477 | 218 for(i=0; i<256;){ |
2700 | 219 int tmp_flags = ff_get_v(bc); |
220 int tmp_fields= ff_get_v(bc); | |
1477 | 221 if(tmp_fields>0) tmp_pts = get_s(bc); |
2700 | 222 if(tmp_fields>1) tmp_mul = ff_get_v(bc); |
223 if(tmp_fields>2) tmp_stream= ff_get_v(bc); | |
224 if(tmp_fields>3) tmp_size = ff_get_v(bc); | |
1477 | 225 else tmp_size = 0; |
2700 | 226 if(tmp_fields>4) tmp_res = ff_get_v(bc); |
1477 | 227 else tmp_res = 0; |
2700 | 228 if(tmp_fields>5) count = ff_get_v(bc); |
1477 | 229 else count = tmp_mul - tmp_size; |
3043 | 230 if(tmp_fields>6) tmp_match = get_s(bc); |
3045 | 231 if(tmp_fields>7) tmp_head_idx= ff_get_v(bc); |
1477 | 232 |
3045 | 233 while(tmp_fields-- > 8) |
2700 | 234 ff_get_v(bc); |
1477 | 235 |
236 if(count == 0 || i+count > 256){ | |
237 av_log(s, AV_LOG_ERROR, "illegal count %d at %d\n", count, i); | |
238 return -1; | |
239 } | |
240 if(tmp_stream >= stream_count){ | |
241 av_log(s, AV_LOG_ERROR, "illegal stream number\n"); | |
242 return -1; | |
243 } | |
244 | |
245 for(j=0; j<count; j++,i++){ | |
246 if (i == 'N') { | |
247 nut->frame_code[i].flags= FLAG_INVALID; | |
248 j--; | |
249 continue; | |
250 } | |
251 nut->frame_code[i].flags = tmp_flags ; | |
252 nut->frame_code[i].pts_delta = tmp_pts ; | |
253 nut->frame_code[i].stream_id = tmp_stream; | |
254 nut->frame_code[i].size_mul = tmp_mul ; | |
255 nut->frame_code[i].size_lsb = tmp_size+j; | |
256 nut->frame_code[i].reserved_count = tmp_res ; | |
3045 | 257 nut->frame_code[i].header_idx = tmp_head_idx; |
1477 | 258 } |
259 } | |
260 assert(nut->frame_code['N'].flags == FLAG_INVALID); | |
261 | |
3045 | 262 if(end > url_ftell(bc) + 4){ |
263 int rem= 1024; | |
264 GET_V(nut->header_count, tmp<128U) | |
265 nut->header_count++; | |
266 for(i=1; i<nut->header_count; i++){ | |
267 GET_V(nut->header_len[i], tmp>0 && tmp<256); | |
268 rem -= nut->header_len[i]; | |
269 if(rem < 0){ | |
270 av_log(s, AV_LOG_ERROR, "invalid elision header\n"); | |
271 return -1; | |
272 } | |
273 nut->header[i]= av_malloc(nut->header_len[i]); | |
274 get_buffer(bc, nut->header[i], nut->header_len[i]); | |
275 } | |
276 assert(nut->header_len[0]==0); | |
277 } | |
278 | |
1485 | 279 if(skip_reserved(bc, end) || get_checksum(bc)){ |
2393 | 280 av_log(s, AV_LOG_ERROR, "main header checksum mismatch\n"); |
1477 | 281 return -1; |
282 } | |
283 | |
284 nut->stream = av_mallocz(sizeof(StreamContext)*stream_count); | |
285 for(i=0; i<stream_count; i++){ | |
286 av_new_stream(s, i); | |
287 } | |
288 | |
289 return 0; | |
290 } | |
291 | |
292 static int decode_stream_header(NUTContext *nut){ | |
293 AVFormatContext *s= nut->avf; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2700
diff
changeset
|
294 ByteIOContext *bc = s->pb; |
1477 | 295 StreamContext *stc; |
1516 | 296 int class, stream_id; |
1477 | 297 uint64_t tmp, end; |
298 AVStream *st; | |
299 | |
2348 | 300 end= get_packetheader(nut, bc, 1, STREAM_STARTCODE); |
1485 | 301 end += url_ftell(bc); |
1477 | 302 |
2327 | 303 GET_V(stream_id, tmp < s->nb_streams && !nut->stream[tmp].time_base); |
1477 | 304 stc= &nut->stream[stream_id]; |
305 | |
306 st = s->streams[stream_id]; | |
307 if (!st) | |
2273
7eb456c4ed8a
Replace all occurrences of AVERROR_NOMEM with AVERROR(ENOMEM).
takis
parents:
2228
diff
changeset
|
308 return AVERROR(ENOMEM); |
1477 | 309 |
2700 | 310 class = ff_get_v(bc); |
1477 | 311 tmp = get_fourcc(bc); |
312 st->codec->codec_tag= tmp; | |
313 switch(class) | |
314 { | |
315 case 0: | |
316 st->codec->codec_type = CODEC_TYPE_VIDEO; | |
2228 | 317 st->codec->codec_id = codec_get_id(codec_bmp_tags, tmp); |
1477 | 318 break; |
319 case 1: | |
320 st->codec->codec_type = CODEC_TYPE_AUDIO; | |
2228 | 321 st->codec->codec_id = codec_get_id(codec_wav_tags, tmp); |
1477 | 322 break; |
323 case 2: | |
3101 | 324 st->codec->codec_type = CODEC_TYPE_SUBTITLE; |
3112 | 325 st->codec->codec_id = codec_get_id(ff_nut_subtitle_tags, tmp); |
3101 | 326 break; |
1477 | 327 case 3: |
328 st->codec->codec_type = CODEC_TYPE_DATA; | |
329 break; | |
330 default: | |
2393 | 331 av_log(s, AV_LOG_ERROR, "unknown stream class (%d)\n", class); |
1477 | 332 return -1; |
333 } | |
3102 | 334 if(class<3 && st->codec->codec_id == CODEC_ID_NONE) |
335 av_log(s, AV_LOG_ERROR, "Unknown codec?!\n"); | |
336 | |
1477 | 337 GET_V(stc->time_base_id , tmp < nut->time_base_count); |
338 GET_V(stc->msb_pts_shift , tmp < 16); | |
2700 | 339 stc->max_pts_distance= ff_get_v(bc); |
2393 | 340 GET_V(stc->decode_delay , tmp < 1000); //sanity limit, raise this if Moore's law is true |
1477 | 341 st->codec->has_b_frames= stc->decode_delay; |
2700 | 342 ff_get_v(bc); //stream flags |
1477 | 343 |
344 GET_V(st->codec->extradata_size, tmp < (1<<30)); | |
345 if(st->codec->extradata_size){ | |
346 st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); | |
347 get_buffer(bc, st->codec->extradata, st->codec->extradata_size); | |
348 } | |
349 | |
350 if (st->codec->codec_type == CODEC_TYPE_VIDEO){ | |
351 GET_V(st->codec->width , tmp > 0) | |
352 GET_V(st->codec->height, tmp > 0) | |
2700 | 353 st->codec->sample_aspect_ratio.num= ff_get_v(bc); |
354 st->codec->sample_aspect_ratio.den= ff_get_v(bc); | |
1477 | 355 if((!st->codec->sample_aspect_ratio.num) != (!st->codec->sample_aspect_ratio.den)){ |
2874 | 356 av_log(s, AV_LOG_ERROR, "invalid aspect ratio %d/%d\n", st->codec->sample_aspect_ratio.num, st->codec->sample_aspect_ratio.den); |
1477 | 357 return -1; |
358 } | |
2700 | 359 ff_get_v(bc); /* csp type */ |
1477 | 360 }else if (st->codec->codec_type == CODEC_TYPE_AUDIO){ |
361 GET_V(st->codec->sample_rate , tmp > 0) | |
3013 | 362 ff_get_v(bc); // samplerate_den |
1477 | 363 GET_V(st->codec->channels, tmp > 0) |
364 } | |
1485 | 365 if(skip_reserved(bc, end) || get_checksum(bc)){ |
2393 | 366 av_log(s, AV_LOG_ERROR, "stream header %d checksum mismatch\n", stream_id); |
1477 | 367 return -1; |
368 } | |
2327 | 369 stc->time_base= &nut->time_base[stc->time_base_id]; |
370 av_set_pts_info(s->streams[stream_id], 63, stc->time_base->num, stc->time_base->den); | |
1477 | 371 return 0; |
372 } | |
373 | |
3120
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
374 static void set_disposition_bits(AVFormatContext* avf, char* value, int stream_id){ |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
375 int flag = 0, i; |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
376 for (i=0; ff_nut_dispositions[i].flag; ++i) { |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
377 if (!strcmp(ff_nut_dispositions[i].str, value)) |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
378 flag = ff_nut_dispositions[i].flag; |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
379 } |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
380 if (!flag) |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
381 av_log(avf, AV_LOG_INFO, "unknown disposition type '%s'\n", value); |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
382 for (i = 0; i < avf->nb_streams; ++i) |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
383 if (stream_id == i || stream_id == -1) |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
384 avf->streams[i]->disposition |= flag; |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
385 } |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
386 |
1477 | 387 static int decode_info_header(NUTContext *nut){ |
388 AVFormatContext *s= nut->avf; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2700
diff
changeset
|
389 ByteIOContext *bc = s->pb; |
1477 | 390 uint64_t tmp; |
391 unsigned int stream_id_plus1, chapter_start, chapter_len, count; | |
392 int chapter_id, i; | |
393 int64_t value, end; | |
3005 | 394 char name[256], str_value[1024], type_str[256]; |
3006
fa2fb523fd6b
Fix info packet type, found by oded as well as the new pedantic const
michael
parents:
3005
diff
changeset
|
395 const char *type; |
3331
f89173ea4c5e
Chapter demuxing support. (untested as I have no nuts with chapters)
michael
parents:
3286
diff
changeset
|
396 AVChapter *chapter= NULL; |
1477 | 397 |
2348 | 398 end= get_packetheader(nut, bc, 1, INFO_STARTCODE); |
1485 | 399 end += url_ftell(bc); |
1477 | 400 |
401 GET_V(stream_id_plus1, tmp <= s->nb_streams) | |
402 chapter_id = get_s(bc); | |
2700 | 403 chapter_start= ff_get_v(bc); |
404 chapter_len = ff_get_v(bc); | |
405 count = ff_get_v(bc); | |
3331
f89173ea4c5e
Chapter demuxing support. (untested as I have no nuts with chapters)
michael
parents:
3286
diff
changeset
|
406 |
f89173ea4c5e
Chapter demuxing support. (untested as I have no nuts with chapters)
michael
parents:
3286
diff
changeset
|
407 if(chapter_id && !stream_id_plus1){ |
f89173ea4c5e
Chapter demuxing support. (untested as I have no nuts with chapters)
michael
parents:
3286
diff
changeset
|
408 int64_t start= chapter_start / nut->time_base_count; |
3334
7a823a401282
Pass time_base as argument to new_chapter() as well.
michael
parents:
3331
diff
changeset
|
409 chapter= ff_new_chapter(s, chapter_id, |
7a823a401282
Pass time_base as argument to new_chapter() as well.
michael
parents:
3331
diff
changeset
|
410 nut->time_base[chapter_start % nut->time_base_count], |
7a823a401282
Pass time_base as argument to new_chapter() as well.
michael
parents:
3331
diff
changeset
|
411 start, start + chapter_len, NULL); |
3331
f89173ea4c5e
Chapter demuxing support. (untested as I have no nuts with chapters)
michael
parents:
3286
diff
changeset
|
412 } |
f89173ea4c5e
Chapter demuxing support. (untested as I have no nuts with chapters)
michael
parents:
3286
diff
changeset
|
413 |
1477 | 414 for(i=0; i<count; i++){ |
415 get_str(bc, name, sizeof(name)); | |
416 value= get_s(bc); | |
417 if(value == -1){ | |
418 type= "UTF-8"; | |
419 get_str(bc, str_value, sizeof(str_value)); | |
420 }else if(value == -2){ | |
3006
fa2fb523fd6b
Fix info packet type, found by oded as well as the new pedantic const
michael
parents:
3005
diff
changeset
|
421 get_str(bc, type_str, sizeof(type_str)); |
fa2fb523fd6b
Fix info packet type, found by oded as well as the new pedantic const
michael
parents:
3005
diff
changeset
|
422 type= type_str; |
1477 | 423 get_str(bc, str_value, sizeof(str_value)); |
424 }else if(value == -3){ | |
425 type= "s"; | |
426 value= get_s(bc); | |
427 }else if(value == -4){ | |
428 type= "t"; | |
2700 | 429 value= ff_get_v(bc); |
1477 | 430 }else if(value < -4){ |
431 type= "r"; | |
432 get_s(bc); | |
433 }else{ | |
434 type= "v"; | |
435 } | |
436 | |
3275 | 437 if (stream_id_plus1 > s->nb_streams) { |
3120
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
438 av_log(s, AV_LOG_ERROR, "invalid stream id for info packet\n"); |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
439 continue; |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
440 } |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
441 |
1477 | 442 if(chapter_id==0 && !strcmp(type, "UTF-8")){ |
443 if (!strcmp(name, "Author")) | |
2189 | 444 av_strlcpy(s->author , str_value, sizeof(s->author)); |
1477 | 445 else if(!strcmp(name, "Title")) |
2189 | 446 av_strlcpy(s->title , str_value, sizeof(s->title)); |
1477 | 447 else if(!strcmp(name, "Copyright")) |
2189 | 448 av_strlcpy(s->copyright, str_value, sizeof(s->copyright)); |
1477 | 449 else if(!strcmp(name, "Description")) |
2189 | 450 av_strlcpy(s->comment , str_value, sizeof(s->comment)); |
3120
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
451 else if(!strcmp(name, "Disposition")) |
ea5623a8efde
Add 'disposition' bitfield to AVStream and use it for both muxing and demuxing
eugeni
parents:
3112
diff
changeset
|
452 set_disposition_bits(s, str_value, stream_id_plus1 - 1); |
1477 | 453 } |
3331
f89173ea4c5e
Chapter demuxing support. (untested as I have no nuts with chapters)
michael
parents:
3286
diff
changeset
|
454 if(chapter && !strcmp(type, "UTF-8")){ |
f89173ea4c5e
Chapter demuxing support. (untested as I have no nuts with chapters)
michael
parents:
3286
diff
changeset
|
455 if(!strcmp(name, "Title")) |
f89173ea4c5e
Chapter demuxing support. (untested as I have no nuts with chapters)
michael
parents:
3286
diff
changeset
|
456 chapter->title= av_strdup(str_value); |
f89173ea4c5e
Chapter demuxing support. (untested as I have no nuts with chapters)
michael
parents:
3286
diff
changeset
|
457 } |
1477 | 458 } |
459 | |
1485 | 460 if(skip_reserved(bc, end) || get_checksum(bc)){ |
2393 | 461 av_log(s, AV_LOG_ERROR, "info header checksum mismatch\n"); |
1477 | 462 return -1; |
463 } | |
464 return 0; | |
465 } | |
466 | |
1500 | 467 static int decode_syncpoint(NUTContext *nut, int64_t *ts, int64_t *back_ptr){ |
1477 | 468 AVFormatContext *s= nut->avf; |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2700
diff
changeset
|
469 ByteIOContext *bc = s->pb; |
1500 | 470 int64_t end, tmp; |
1477 | 471 |
1478 | 472 nut->last_syncpoint_pos= url_ftell(bc)-8; |
1477 | 473 |
2348 | 474 end= get_packetheader(nut, bc, 1, SYNCPOINT_STARTCODE); |
1485 | 475 end += url_ftell(bc); |
1477 | 476 |
2700 | 477 tmp= ff_get_v(bc); |
478 *back_ptr= nut->last_syncpoint_pos - 16*ff_get_v(bc); | |
1500 | 479 if(*back_ptr < 0) |
480 return -1; | |
1477 | 481 |
3011
0439b354e005
ff_nut_reset_ts() expected to get 'ts*time_base_count', but muxer only
ods15
parents:
3006
diff
changeset
|
482 ff_nut_reset_ts(nut, nut->time_base[tmp % nut->time_base_count], tmp / nut->time_base_count); |
1477 | 483 |
1485 | 484 if(skip_reserved(bc, end) || get_checksum(bc)){ |
1478 | 485 av_log(s, AV_LOG_ERROR, "sync point checksum mismatch\n"); |
1477 | 486 return -1; |
487 } | |
1500 | 488 |
489 *ts= tmp / s->nb_streams * av_q2d(nut->time_base[tmp % s->nb_streams])*AV_TIME_BASE; | |
2349 | 490 ff_nut_add_sp(nut, nut->last_syncpoint_pos, *back_ptr, *ts); |
1500 | 491 |
1477 | 492 return 0; |
493 } | |
494 | |
1484 | 495 static int find_and_decode_index(NUTContext *nut){ |
496 AVFormatContext *s= nut->avf; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2700
diff
changeset
|
497 ByteIOContext *bc = s->pb; |
1484 | 498 uint64_t tmp, end; |
499 int i, j, syncpoint_count; | |
500 int64_t filesize= url_fsize(bc); | |
501 int64_t *syncpoints; | |
502 int8_t *has_keyframe; | |
503 | |
504 url_fseek(bc, filesize-12, SEEK_SET); | |
505 url_fseek(bc, filesize-get_be64(bc), SEEK_SET); | |
506 if(get_be64(bc) != INDEX_STARTCODE){ | |
507 av_log(s, AV_LOG_ERROR, "no index at the end\n"); | |
508 return -1; | |
509 } | |
510 | |
2348 | 511 end= get_packetheader(nut, bc, 1, INDEX_STARTCODE); |
1485 | 512 end += url_ftell(bc); |
1484 | 513 |
2700 | 514 ff_get_v(bc); //max_pts |
1484 | 515 GET_V(syncpoint_count, tmp < INT_MAX/8 && tmp > 0) |
516 syncpoints= av_malloc(sizeof(int64_t)*syncpoint_count); | |
517 has_keyframe= av_malloc(sizeof(int8_t)*(syncpoint_count+1)); | |
518 for(i=0; i<syncpoint_count; i++){ | |
519 GET_V(syncpoints[i], tmp>0) | |
520 if(i) | |
521 syncpoints[i] += syncpoints[i-1]; | |
522 } | |
523 | |
524 for(i=0; i<s->nb_streams; i++){ | |
525 int64_t last_pts= -1; | |
526 for(j=0; j<syncpoint_count;){ | |
2700 | 527 uint64_t x= ff_get_v(bc); |
1484 | 528 int type= x&1; |
529 int n= j; | |
530 x>>=1; | |
531 if(type){ | |
532 int flag= x&1; | |
533 x>>=1; | |
534 if(n+x >= syncpoint_count + 1){ | |
535 av_log(s, AV_LOG_ERROR, "index overflow A\n"); | |
536 return -1; | |
537 } | |
538 while(x--) | |
539 has_keyframe[n++]= flag; | |
540 has_keyframe[n++]= !flag; | |
541 }else{ | |
542 while(x != 1){ | |
543 if(n>=syncpoint_count + 1){ | |
544 av_log(s, AV_LOG_ERROR, "index overflow B\n"); | |
545 return -1; | |
546 } | |
547 has_keyframe[n++]= x&1; | |
548 x>>=1; | |
549 } | |
550 } | |
551 if(has_keyframe[0]){ | |
552 av_log(s, AV_LOG_ERROR, "keyframe before first syncpoint in index\n"); | |
553 return -1; | |
554 } | |
555 assert(n<=syncpoint_count+1); | |
3012
2214e8b1cb4d
missing " && j<syncpoint_count" protection in the index parsing, as the
ods15
parents:
3011
diff
changeset
|
556 for(; j<n && j<syncpoint_count; j++){ |
1484 | 557 if(has_keyframe[j]){ |
2700 | 558 uint64_t B, A= ff_get_v(bc); |
1484 | 559 if(!A){ |
2700 | 560 A= ff_get_v(bc); |
561 B= ff_get_v(bc); | |
1484 | 562 //eor_pts[j][i] = last_pts + A + B |
563 }else | |
564 B= 0; | |
565 av_add_index_entry( | |
566 s->streams[i], | |
567 16*syncpoints[j-1], | |
568 last_pts + A, | |
569 0, | |
570 0, | |
571 AVINDEX_KEYFRAME); | |
572 last_pts += A + B; | |
573 } | |
574 } | |
575 } | |
576 } | |
577 | |
1485 | 578 if(skip_reserved(bc, end) || get_checksum(bc)){ |
2393 | 579 av_log(s, AV_LOG_ERROR, "index checksum mismatch\n"); |
1484 | 580 return -1; |
581 } | |
582 return 0; | |
583 } | |
584 | |
1477 | 585 static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap) |
586 { | |
587 NUTContext *nut = s->priv_data; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2700
diff
changeset
|
588 ByteIOContext *bc = s->pb; |
1477 | 589 int64_t pos; |
3035 | 590 int initialized_stream_count; |
1477 | 591 |
592 nut->avf= s; | |
593 | |
594 /* main header */ | |
595 pos=0; | |
1480 | 596 do{ |
1477 | 597 pos= find_startcode(bc, MAIN_STARTCODE, pos)+1; |
598 if (pos<0+1){ | |
2393 | 599 av_log(s, AV_LOG_ERROR, "No main startcode found.\n"); |
1477 | 600 return -1; |
601 } | |
1480 | 602 }while(decode_main_header(nut) < 0); |
1477 | 603 |
604 /* stream headers */ | |
605 pos=0; | |
3035 | 606 for(initialized_stream_count=0; initialized_stream_count < s->nb_streams;){ |
1477 | 607 pos= find_startcode(bc, STREAM_STARTCODE, pos)+1; |
608 if (pos<0+1){ | |
2393 | 609 av_log(s, AV_LOG_ERROR, "Not all stream headers found.\n"); |
1477 | 610 return -1; |
611 } | |
612 if(decode_stream_header(nut) >= 0) | |
3035 | 613 initialized_stream_count++; |
1477 | 614 } |
615 | |
616 /* info headers */ | |
617 pos=0; | |
618 for(;;){ | |
619 uint64_t startcode= find_any_startcode(bc, pos); | |
620 pos= url_ftell(bc); | |
621 | |
622 if(startcode==0){ | |
623 av_log(s, AV_LOG_ERROR, "EOF before video frames\n"); | |
624 return -1; | |
625 }else if(startcode == SYNCPOINT_STARTCODE){ | |
626 nut->next_startcode= startcode; | |
627 break; | |
628 }else if(startcode != INFO_STARTCODE){ | |
629 continue; | |
630 } | |
631 | |
632 decode_info_header(nut); | |
633 } | |
634 | |
1478 | 635 s->data_offset= pos-8; |
636 | |
1501 | 637 if(!url_is_streamed(bc)){ |
1484 | 638 int64_t orig_pos= url_ftell(bc); |
639 find_and_decode_index(nut); | |
640 url_fseek(bc, orig_pos, SEEK_SET); | |
641 } | |
642 assert(nut->next_startcode == SYNCPOINT_STARTCODE); | |
643 | |
1477 | 644 return 0; |
645 } | |
646 | |
3045 | 647 static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, uint8_t *header_idx, int frame_code){ |
1477 | 648 AVFormatContext *s= nut->avf; |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2700
diff
changeset
|
649 ByteIOContext *bc = s->pb; |
1477 | 650 StreamContext *stc; |
651 int size, flags, size_mul, pts_delta, i, reserved_count; | |
652 uint64_t tmp; | |
653 | |
654 if(url_ftell(bc) > nut->last_syncpoint_pos + nut->max_distance){ | |
2393 | 655 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); |
1477 | 656 return -1; |
657 } | |
658 | |
659 flags = nut->frame_code[frame_code].flags; | |
660 size_mul = nut->frame_code[frame_code].size_mul; | |
661 size = nut->frame_code[frame_code].size_lsb; | |
662 *stream_id = nut->frame_code[frame_code].stream_id; | |
663 pts_delta = nut->frame_code[frame_code].pts_delta; | |
664 reserved_count = nut->frame_code[frame_code].reserved_count; | |
3045 | 665 *header_idx = nut->frame_code[frame_code].header_idx; |
1477 | 666 |
667 if(flags & FLAG_INVALID) | |
668 return -1; | |
669 if(flags & FLAG_CODED) | |
2700 | 670 flags ^= ff_get_v(bc); |
1477 | 671 if(flags & FLAG_STREAM_ID){ |
672 GET_V(*stream_id, tmp < s->nb_streams) | |
673 } | |
674 stc= &nut->stream[*stream_id]; | |
675 if(flags&FLAG_CODED_PTS){ | |
2700 | 676 int coded_pts= ff_get_v(bc); |
1477 | 677 //FIXME check last_pts validity? |
678 if(coded_pts < (1<<stc->msb_pts_shift)){ | |
2338 | 679 *pts=ff_lsb2full(stc, coded_pts); |
1477 | 680 }else |
681 *pts=coded_pts - (1<<stc->msb_pts_shift); | |
682 }else | |
683 *pts= stc->last_pts + pts_delta; | |
684 if(flags&FLAG_SIZE_MSB){ | |
2700 | 685 size += size_mul*ff_get_v(bc); |
1477 | 686 } |
3044 | 687 if(flags&FLAG_MATCH_TIME) |
688 get_s(bc); | |
3045 | 689 if(flags&FLAG_HEADER_IDX) |
690 *header_idx= ff_get_v(bc); | |
1477 | 691 if(flags&FLAG_RESERVED) |
2700 | 692 reserved_count= ff_get_v(bc); |
1477 | 693 for(i=0; i<reserved_count; i++) |
2700 | 694 ff_get_v(bc); |
3045 | 695 |
696 if(*header_idx >= (unsigned)nut->header_count){ | |
697 av_log(s, AV_LOG_ERROR, "header_idx invalid\n"); | |
698 return -1; | |
699 } | |
700 if(size > 4096) | |
701 *header_idx=0; | |
702 size -= nut->header_len[*header_idx]; | |
703 | |
1477 | 704 if(flags&FLAG_CHECKSUM){ |
705 get_be32(bc); //FIXME check this | |
1518 | 706 }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
|
707 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
|
708 return -1; |
1477 | 709 } |
710 | |
711 stc->last_pts= *pts; | |
1518 | 712 stc->last_flags= flags; |
1477 | 713 |
714 return size; | |
715 } | |
716 | |
717 static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code){ | |
718 AVFormatContext *s= nut->avf; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2700
diff
changeset
|
719 ByteIOContext *bc = s->pb; |
1518 | 720 int size, stream_id, discard; |
1477 | 721 int64_t pts, last_IP_pts; |
1518 | 722 StreamContext *stc; |
3045 | 723 uint8_t header_idx; |
1477 | 724 |
3045 | 725 size= decode_frame_header(nut, &pts, &stream_id, &header_idx, frame_code); |
1477 | 726 if(size < 0) |
727 return -1; | |
728 | |
1518 | 729 stc= &nut->stream[stream_id]; |
730 | |
731 if (stc->last_flags & FLAG_KEY) | |
732 stc->skip_until_key_frame=0; | |
1517
51b29c17bd1f
skip non keyframes after seeking between syncpoint and the first keyframe
michael
parents:
1516
diff
changeset
|
733 |
1477 | 734 discard= s->streams[ stream_id ]->discard; |
735 last_IP_pts= s->streams[ stream_id ]->last_IP_pts; | |
1518 | 736 if( (discard >= AVDISCARD_NONKEY && !(stc->last_flags & FLAG_KEY)) |
1477 | 737 ||(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
|
738 || discard >= AVDISCARD_ALL |
1518 | 739 || stc->skip_until_key_frame){ |
1477 | 740 url_fskip(bc, size); |
741 return 1; | |
742 } | |
743 | |
3045 | 744 av_new_packet(pkt, size + nut->header_len[header_idx]); |
745 memcpy(pkt->data, nut->header[header_idx], nut->header_len[header_idx]); | |
746 pkt->pos= url_ftell(bc); //FIXME | |
747 get_buffer(bc, pkt->data + nut->header_len[header_idx], size); | |
748 | |
1477 | 749 pkt->stream_index = stream_id; |
1518 | 750 if (stc->last_flags & FLAG_KEY) |
1477 | 751 pkt->flags |= PKT_FLAG_KEY; |
752 pkt->pts = pts; | |
753 | |
754 return 0; | |
755 } | |
756 | |
757 static int nut_read_packet(AVFormatContext *s, AVPacket *pkt) | |
758 { | |
759 NUTContext *nut = s->priv_data; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2700
diff
changeset
|
760 ByteIOContext *bc = s->pb; |
1477 | 761 int i, frame_code=0, ret, skip; |
1500 | 762 int64_t ts, back_ptr; |
1477 | 763 |
764 for(;;){ | |
765 int64_t pos= url_ftell(bc); | |
766 uint64_t tmp= nut->next_startcode; | |
767 nut->next_startcode=0; | |
768 | |
769 if(tmp){ | |
770 pos-=8; | |
771 }else{ | |
772 frame_code = get_byte(bc); | |
1933 | 773 if(url_feof(bc)) |
774 return -1; | |
1477 | 775 if(frame_code == 'N'){ |
776 tmp= frame_code; | |
777 for(i=1; i<8; i++) | |
778 tmp = (tmp<<8) + get_byte(bc); | |
779 } | |
780 } | |
781 switch(tmp){ | |
782 case MAIN_STARTCODE: | |
783 case STREAM_STARTCODE: | |
784 case INDEX_STARTCODE: | |
2348 | 785 skip= get_packetheader(nut, bc, 0, tmp); |
1477 | 786 url_fseek(bc, skip, SEEK_CUR); |
787 break; | |
788 case INFO_STARTCODE: | |
789 if(decode_info_header(nut)<0) | |
790 goto resync; | |
791 break; | |
792 case SYNCPOINT_STARTCODE: | |
1500 | 793 if(decode_syncpoint(nut, &ts, &back_ptr)<0) |
1477 | 794 goto resync; |
795 frame_code = get_byte(bc); | |
796 case 0: | |
797 ret= decode_frame(nut, pkt, frame_code); | |
798 if(ret==0) | |
799 return 0; | |
800 else if(ret==1) //ok but discard packet | |
801 break; | |
802 default: | |
803 resync: | |
804 av_log(s, AV_LOG_DEBUG, "syncing from %"PRId64"\n", pos); | |
1508 | 805 tmp= find_any_startcode(bc, nut->last_syncpoint_pos+1); |
1477 | 806 if(tmp==0) |
807 return -1; | |
808 av_log(s, AV_LOG_DEBUG, "sync\n"); | |
809 nut->next_startcode= tmp; | |
810 } | |
811 } | |
812 } | |
813 | |
1478 | 814 static int64_t nut_read_timestamp(AVFormatContext *s, int stream_index, int64_t *pos_arg, int64_t pos_limit){ |
815 NUTContext *nut = s->priv_data; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2700
diff
changeset
|
816 ByteIOContext *bc = s->pb; |
1500 | 817 int64_t pos, pts, back_ptr; |
1478 | 818 av_log(s, AV_LOG_DEBUG, "read_timestamp(X,%d,%"PRId64",%"PRId64")\n", stream_index, *pos_arg, pos_limit); |
819 | |
820 pos= *pos_arg; | |
821 do{ | |
822 pos= find_startcode(bc, SYNCPOINT_STARTCODE, pos)+1; | |
823 if(pos < 1){ | |
824 assert(nut->next_startcode == 0); | |
2393 | 825 av_log(s, AV_LOG_ERROR, "read_timestamp failed.\n"); |
1478 | 826 return AV_NOPTS_VALUE; |
827 } | |
1500 | 828 }while(decode_syncpoint(nut, &pts, &back_ptr) < 0); |
1478 | 829 *pos_arg = pos-1; |
830 assert(nut->last_syncpoint_pos == *pos_arg); | |
831 | |
2170 | 832 av_log(s, AV_LOG_DEBUG, "return %"PRId64" %"PRId64"\n", pts,back_ptr ); |
1500 | 833 if (stream_index == -1) return pts; |
834 else if(stream_index == -2) return back_ptr; | |
835 | |
836 assert(0); | |
1478 | 837 } |
838 | |
1500 | 839 static int read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flags){ |
840 NUTContext *nut = s->priv_data; | |
841 AVStream *st= s->streams[stream_index]; | |
842 syncpoint_t dummy={.ts= pts*av_q2d(st->time_base)*AV_TIME_BASE}; | |
843 syncpoint_t nopts_sp= {.ts= AV_NOPTS_VALUE, .back_ptr= AV_NOPTS_VALUE}; | |
844 syncpoint_t *sp, *next_node[2]= {&nopts_sp, &nopts_sp}; | |
845 int64_t pos, pos2, ts; | |
1517
51b29c17bd1f
skip non keyframes after seeking between syncpoint and the first keyframe
michael
parents:
1516
diff
changeset
|
846 int i; |
1500 | 847 |
1501 | 848 if(st->index_entries){ |
849 int index= av_index_search_timestamp(st, pts, flags); | |
850 if(index<0) | |
851 return -1; | |
852 | |
853 pos2= st->index_entries[index].pos; | |
854 ts = st->index_entries[index].timestamp; | |
855 }else{ | |
2349 | 856 av_tree_find(nut->syncpoints, &dummy, ff_nut_sp_pts_cmp, next_node); |
2170 | 857 av_log(s, AV_LOG_DEBUG, "%"PRIu64"-%"PRIu64" %"PRId64"-%"PRId64"\n", next_node[0]->pos, next_node[1]->pos, |
1502 | 858 next_node[0]->ts , next_node[1]->ts); |
859 pos= av_gen_search(s, -1, dummy.ts, next_node[0]->pos, next_node[1]->pos, next_node[1]->pos, | |
860 next_node[0]->ts , next_node[1]->ts, AVSEEK_FLAG_BACKWARD, &ts, nut_read_timestamp); | |
1500 | 861 |
1502 | 862 if(!(flags & AVSEEK_FLAG_BACKWARD)){ |
863 dummy.pos= pos+16; | |
864 next_node[1]= &nopts_sp; | |
2349 | 865 av_tree_find(nut->syncpoints, &dummy, ff_nut_sp_pos_cmp, next_node); |
1502 | 866 pos2= av_gen_search(s, -2, dummy.pos, next_node[0]->pos , next_node[1]->pos, next_node[1]->pos, |
867 next_node[0]->back_ptr, next_node[1]->back_ptr, flags, &ts, nut_read_timestamp); | |
868 if(pos2>=0) | |
869 pos= pos2; | |
3139 | 870 //FIXME dir but I think it does not matter |
1502 | 871 } |
872 dummy.pos= pos; | |
2349 | 873 sp= av_tree_find(nut->syncpoints, &dummy, ff_nut_sp_pos_cmp, NULL); |
1500 | 874 |
1502 | 875 assert(sp); |
876 pos2= sp->back_ptr - 15; | |
1501 | 877 } |
878 av_log(NULL, AV_LOG_DEBUG, "SEEKTO: %"PRId64"\n", pos2); | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2700
diff
changeset
|
879 pos= find_startcode(s->pb, SYNCPOINT_STARTCODE, pos2); |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2700
diff
changeset
|
880 url_fseek(s->pb, pos, SEEK_SET); |
1500 | 881 av_log(NULL, AV_LOG_DEBUG, "SP: %"PRId64"\n", pos); |
1501 | 882 if(pos2 > pos || pos2 + 15 < pos){ |
1500 | 883 av_log(NULL, AV_LOG_ERROR, "no syncpoint at backptr pos\n"); |
884 } | |
1517
51b29c17bd1f
skip non keyframes after seeking between syncpoint and the first keyframe
michael
parents:
1516
diff
changeset
|
885 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
|
886 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
|
887 |
1500 | 888 return 0; |
889 } | |
890 | |
1477 | 891 static int nut_read_close(AVFormatContext *s) |
892 { | |
893 NUTContext *nut = s->priv_data; | |
894 | |
895 av_freep(&nut->time_base); | |
896 av_freep(&nut->stream); | |
897 | |
898 return 0; | |
899 } | |
900 | |
901 #ifdef CONFIG_NUT_DEMUXER | |
902 AVInputFormat nut_demuxer = { | |
903 "nut", | |
904 "nut format", | |
905 sizeof(NUTContext), | |
906 nut_probe, | |
907 nut_read_header, | |
908 nut_read_packet, | |
909 nut_read_close, | |
1500 | 910 read_seek, |
1477 | 911 .extensions = "nut", |
912 }; | |
913 #endif |