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