annotate ffmpeg/libavformat/nutdec.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents f445c3017523
children
rev   line source
yading@11 1 /*
yading@11 2 * "NUT" Container Format demuxer
yading@11 3 * Copyright (c) 2004-2006 Michael Niedermayer
yading@11 4 * Copyright (c) 2003 Alex Beregszaszi
yading@11 5 *
yading@11 6 * This file is part of FFmpeg.
yading@11 7 *
yading@11 8 * FFmpeg is free software; you can redistribute it and/or
yading@11 9 * modify it under the terms of the GNU Lesser General Public
yading@11 10 * License as published by the Free Software Foundation; either
yading@11 11 * version 2.1 of the License, or (at your option) any later version.
yading@11 12 *
yading@11 13 * FFmpeg is distributed in the hope that it will be useful,
yading@11 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@11 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@11 16 * Lesser General Public License for more details.
yading@11 17 *
yading@11 18 * You should have received a copy of the GNU Lesser General Public
yading@11 19 * License along with FFmpeg; if not, write to the Free Software
yading@11 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@11 21 */
yading@11 22
yading@11 23 #include "libavutil/avstring.h"
yading@11 24 #include "libavutil/avassert.h"
yading@11 25 #include "libavutil/bswap.h"
yading@11 26 #include "libavutil/dict.h"
yading@11 27 #include "libavutil/mathematics.h"
yading@11 28 #include "libavutil/tree.h"
yading@11 29 #include "avio_internal.h"
yading@11 30 #include "nut.h"
yading@11 31 #include "riff.h"
yading@11 32
yading@11 33 #define NUT_MAX_STREAMS 256 /* arbitrary sanity check value */
yading@11 34
yading@11 35 static int64_t nut_read_timestamp(AVFormatContext *s, int stream_index,
yading@11 36 int64_t *pos_arg, int64_t pos_limit);
yading@11 37
yading@11 38 static int get_str(AVIOContext *bc, char *string, unsigned int maxlen)
yading@11 39 {
yading@11 40 unsigned int len = ffio_read_varlen(bc);
yading@11 41
yading@11 42 if (len && maxlen)
yading@11 43 avio_read(bc, string, FFMIN(len, maxlen));
yading@11 44 while (len > maxlen) {
yading@11 45 avio_r8(bc);
yading@11 46 len--;
yading@11 47 }
yading@11 48
yading@11 49 if (maxlen)
yading@11 50 string[FFMIN(len, maxlen - 1)] = 0;
yading@11 51
yading@11 52 if (maxlen == len)
yading@11 53 return -1;
yading@11 54 else
yading@11 55 return 0;
yading@11 56 }
yading@11 57
yading@11 58 static int64_t get_s(AVIOContext *bc)
yading@11 59 {
yading@11 60 int64_t v = ffio_read_varlen(bc) + 1;
yading@11 61
yading@11 62 if (v & 1)
yading@11 63 return -(v >> 1);
yading@11 64 else
yading@11 65 return (v >> 1);
yading@11 66 }
yading@11 67
yading@11 68 static uint64_t get_fourcc(AVIOContext *bc)
yading@11 69 {
yading@11 70 unsigned int len = ffio_read_varlen(bc);
yading@11 71
yading@11 72 if (len == 2)
yading@11 73 return avio_rl16(bc);
yading@11 74 else if (len == 4)
yading@11 75 return avio_rl32(bc);
yading@11 76 else {
yading@11 77 av_log(NULL, AV_LOG_ERROR, "Unsupported fourcc length %d\n", len);
yading@11 78 return -1;
yading@11 79 }
yading@11 80 }
yading@11 81
yading@11 82 #ifdef TRACE
yading@11 83 static inline uint64_t get_v_trace(AVIOContext *bc, const char *file,
yading@11 84 const char *func, int line)
yading@11 85 {
yading@11 86 uint64_t v = ffio_read_varlen(bc);
yading@11 87
yading@11 88 av_log(NULL, AV_LOG_DEBUG, "get_v %5"PRId64" / %"PRIX64" in %s %s:%d\n",
yading@11 89 v, v, file, func, line);
yading@11 90 return v;
yading@11 91 }
yading@11 92
yading@11 93 static inline int64_t get_s_trace(AVIOContext *bc, const char *file,
yading@11 94 const char *func, int line)
yading@11 95 {
yading@11 96 int64_t v = get_s(bc);
yading@11 97
yading@11 98 av_log(NULL, AV_LOG_DEBUG, "get_s %5"PRId64" / %"PRIX64" in %s %s:%d\n",
yading@11 99 v, v, file, func, line);
yading@11 100 return v;
yading@11 101 }
yading@11 102
yading@11 103 static inline uint64_t get_4cc_trace(AVIOContext *bc, char *file,
yading@11 104 char *func, int line)
yading@11 105 {
yading@11 106 uint64_t v = get_fourcc(bc);
yading@11 107
yading@11 108 av_log(NULL, AV_LOG_DEBUG, "get_fourcc %5"PRId64" / %"PRIX64" in %s %s:%d\n",
yading@11 109 v, v, file, func, line);
yading@11 110 return v;
yading@11 111 }
yading@11 112 #define ffio_read_varlen(bc) get_v_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
yading@11 113 #define get_s(bc) get_s_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
yading@11 114 #define get_fourcc(bc) get_4cc_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
yading@11 115 #endif
yading@11 116
yading@11 117 static int get_packetheader(NUTContext *nut, AVIOContext *bc,
yading@11 118 int calculate_checksum, uint64_t startcode)
yading@11 119 {
yading@11 120 int64_t size;
yading@11 121 // start = avio_tell(bc) - 8;
yading@11 122
yading@11 123 startcode = av_be2ne64(startcode);
yading@11 124 startcode = ff_crc04C11DB7_update(0, (uint8_t*) &startcode, 8);
yading@11 125
yading@11 126 ffio_init_checksum(bc, ff_crc04C11DB7_update, startcode);
yading@11 127 size = ffio_read_varlen(bc);
yading@11 128 if (size > 4096)
yading@11 129 avio_rb32(bc);
yading@11 130 if (ffio_get_checksum(bc) && size > 4096)
yading@11 131 return -1;
yading@11 132
yading@11 133 ffio_init_checksum(bc, calculate_checksum ? ff_crc04C11DB7_update : NULL, 0);
yading@11 134
yading@11 135 return size;
yading@11 136 }
yading@11 137
yading@11 138 static uint64_t find_any_startcode(AVIOContext *bc, int64_t pos)
yading@11 139 {
yading@11 140 uint64_t state = 0;
yading@11 141
yading@11 142 if (pos >= 0)
yading@11 143 /* Note, this may fail if the stream is not seekable, but that should
yading@11 144 * not matter, as in this case we simply start where we currently are */
yading@11 145 avio_seek(bc, pos, SEEK_SET);
yading@11 146 while (!url_feof(bc)) {
yading@11 147 state = (state << 8) | avio_r8(bc);
yading@11 148 if ((state >> 56) != 'N')
yading@11 149 continue;
yading@11 150 switch (state) {
yading@11 151 case MAIN_STARTCODE:
yading@11 152 case STREAM_STARTCODE:
yading@11 153 case SYNCPOINT_STARTCODE:
yading@11 154 case INFO_STARTCODE:
yading@11 155 case INDEX_STARTCODE:
yading@11 156 return state;
yading@11 157 }
yading@11 158 }
yading@11 159
yading@11 160 return 0;
yading@11 161 }
yading@11 162
yading@11 163 /**
yading@11 164 * Find the given startcode.
yading@11 165 * @param code the startcode
yading@11 166 * @param pos the start position of the search, or -1 if the current position
yading@11 167 * @return the position of the startcode or -1 if not found
yading@11 168 */
yading@11 169 static int64_t find_startcode(AVIOContext *bc, uint64_t code, int64_t pos)
yading@11 170 {
yading@11 171 for (;;) {
yading@11 172 uint64_t startcode = find_any_startcode(bc, pos);
yading@11 173 if (startcode == code)
yading@11 174 return avio_tell(bc) - 8;
yading@11 175 else if (startcode == 0)
yading@11 176 return -1;
yading@11 177 pos = -1;
yading@11 178 }
yading@11 179 }
yading@11 180
yading@11 181 static int nut_probe(AVProbeData *p)
yading@11 182 {
yading@11 183 int i;
yading@11 184 uint64_t code = 0;
yading@11 185
yading@11 186 for (i = 0; i < p->buf_size; i++) {
yading@11 187 code = (code << 8) | p->buf[i];
yading@11 188 if (code == MAIN_STARTCODE)
yading@11 189 return AVPROBE_SCORE_MAX;
yading@11 190 }
yading@11 191 return 0;
yading@11 192 }
yading@11 193
yading@11 194 #define GET_V(dst, check) \
yading@11 195 do { \
yading@11 196 tmp = ffio_read_varlen(bc); \
yading@11 197 if (!(check)) { \
yading@11 198 av_log(s, AV_LOG_ERROR, "Error " #dst " is (%"PRId64")\n", tmp); \
yading@11 199 return -1; \
yading@11 200 } \
yading@11 201 dst = tmp; \
yading@11 202 } while (0)
yading@11 203
yading@11 204 static int skip_reserved(AVIOContext *bc, int64_t pos)
yading@11 205 {
yading@11 206 pos -= avio_tell(bc);
yading@11 207 if (pos < 0) {
yading@11 208 avio_seek(bc, pos, SEEK_CUR);
yading@11 209 return -1;
yading@11 210 } else {
yading@11 211 while (pos--)
yading@11 212 avio_r8(bc);
yading@11 213 return 0;
yading@11 214 }
yading@11 215 }
yading@11 216
yading@11 217 static int decode_main_header(NUTContext *nut)
yading@11 218 {
yading@11 219 AVFormatContext *s = nut->avf;
yading@11 220 AVIOContext *bc = s->pb;
yading@11 221 uint64_t tmp, end;
yading@11 222 unsigned int stream_count;
yading@11 223 int i, j, count;
yading@11 224 int tmp_stream, tmp_mul, tmp_pts, tmp_size, tmp_res, tmp_head_idx;
yading@11 225
yading@11 226 end = get_packetheader(nut, bc, 1, MAIN_STARTCODE);
yading@11 227 end += avio_tell(bc);
yading@11 228
yading@11 229 GET_V(tmp, tmp >= 2 && tmp <= 3);
yading@11 230 GET_V(stream_count, tmp > 0 && tmp <= NUT_MAX_STREAMS);
yading@11 231
yading@11 232 nut->max_distance = ffio_read_varlen(bc);
yading@11 233 if (nut->max_distance > 65536) {
yading@11 234 av_log(s, AV_LOG_DEBUG, "max_distance %d\n", nut->max_distance);
yading@11 235 nut->max_distance = 65536;
yading@11 236 }
yading@11 237
yading@11 238 GET_V(nut->time_base_count, tmp > 0 && tmp < INT_MAX / sizeof(AVRational));
yading@11 239 nut->time_base = av_malloc(nut->time_base_count * sizeof(AVRational));
yading@11 240
yading@11 241 for (i = 0; i < nut->time_base_count; i++) {
yading@11 242 GET_V(nut->time_base[i].num, tmp > 0 && tmp < (1ULL << 31));
yading@11 243 GET_V(nut->time_base[i].den, tmp > 0 && tmp < (1ULL << 31));
yading@11 244 if (av_gcd(nut->time_base[i].num, nut->time_base[i].den) != 1) {
yading@11 245 av_log(s, AV_LOG_ERROR, "time base invalid\n");
yading@11 246 return AVERROR_INVALIDDATA;
yading@11 247 }
yading@11 248 }
yading@11 249 tmp_pts = 0;
yading@11 250 tmp_mul = 1;
yading@11 251 tmp_stream = 0;
yading@11 252 tmp_head_idx = 0;
yading@11 253 for (i = 0; i < 256;) {
yading@11 254 int tmp_flags = ffio_read_varlen(bc);
yading@11 255 int tmp_fields = ffio_read_varlen(bc);
yading@11 256
yading@11 257 if (tmp_fields > 0)
yading@11 258 tmp_pts = get_s(bc);
yading@11 259 if (tmp_fields > 1)
yading@11 260 tmp_mul = ffio_read_varlen(bc);
yading@11 261 if (tmp_fields > 2)
yading@11 262 tmp_stream = ffio_read_varlen(bc);
yading@11 263 if (tmp_fields > 3)
yading@11 264 tmp_size = ffio_read_varlen(bc);
yading@11 265 else
yading@11 266 tmp_size = 0;
yading@11 267 if (tmp_fields > 4)
yading@11 268 tmp_res = ffio_read_varlen(bc);
yading@11 269 else
yading@11 270 tmp_res = 0;
yading@11 271 if (tmp_fields > 5)
yading@11 272 count = ffio_read_varlen(bc);
yading@11 273 else
yading@11 274 count = tmp_mul - tmp_size;
yading@11 275 if (tmp_fields > 6)
yading@11 276 get_s(bc);
yading@11 277 if (tmp_fields > 7)
yading@11 278 tmp_head_idx = ffio_read_varlen(bc);
yading@11 279
yading@11 280 while (tmp_fields-- > 8)
yading@11 281 ffio_read_varlen(bc);
yading@11 282
yading@11 283 if (count == 0 || i + count > 256) {
yading@11 284 av_log(s, AV_LOG_ERROR, "illegal count %d at %d\n", count, i);
yading@11 285 return AVERROR_INVALIDDATA;
yading@11 286 }
yading@11 287 if (tmp_stream >= stream_count) {
yading@11 288 av_log(s, AV_LOG_ERROR, "illegal stream number\n");
yading@11 289 return AVERROR_INVALIDDATA;
yading@11 290 }
yading@11 291
yading@11 292 for (j = 0; j < count; j++, i++) {
yading@11 293 if (i == 'N') {
yading@11 294 nut->frame_code[i].flags = FLAG_INVALID;
yading@11 295 j--;
yading@11 296 continue;
yading@11 297 }
yading@11 298 nut->frame_code[i].flags = tmp_flags;
yading@11 299 nut->frame_code[i].pts_delta = tmp_pts;
yading@11 300 nut->frame_code[i].stream_id = tmp_stream;
yading@11 301 nut->frame_code[i].size_mul = tmp_mul;
yading@11 302 nut->frame_code[i].size_lsb = tmp_size + j;
yading@11 303 nut->frame_code[i].reserved_count = tmp_res;
yading@11 304 nut->frame_code[i].header_idx = tmp_head_idx;
yading@11 305 }
yading@11 306 }
yading@11 307 av_assert0(nut->frame_code['N'].flags == FLAG_INVALID);
yading@11 308
yading@11 309 if (end > avio_tell(bc) + 4) {
yading@11 310 int rem = 1024;
yading@11 311 GET_V(nut->header_count, tmp < 128U);
yading@11 312 nut->header_count++;
yading@11 313 for (i = 1; i < nut->header_count; i++) {
yading@11 314 uint8_t *hdr;
yading@11 315 GET_V(nut->header_len[i], tmp > 0 && tmp < 256);
yading@11 316 rem -= nut->header_len[i];
yading@11 317 if (rem < 0) {
yading@11 318 av_log(s, AV_LOG_ERROR, "invalid elision header\n");
yading@11 319 return AVERROR_INVALIDDATA;
yading@11 320 }
yading@11 321 hdr = av_malloc(nut->header_len[i]);
yading@11 322 if (!hdr)
yading@11 323 return AVERROR(ENOMEM);
yading@11 324 avio_read(bc, hdr, nut->header_len[i]);
yading@11 325 nut->header[i] = hdr;
yading@11 326 }
yading@11 327 av_assert0(nut->header_len[0] == 0);
yading@11 328 }
yading@11 329
yading@11 330 if (skip_reserved(bc, end) || ffio_get_checksum(bc)) {
yading@11 331 av_log(s, AV_LOG_ERROR, "main header checksum mismatch\n");
yading@11 332 return AVERROR_INVALIDDATA;
yading@11 333 }
yading@11 334
yading@11 335 nut->stream = av_mallocz(sizeof(StreamContext) * stream_count);
yading@11 336 for (i = 0; i < stream_count; i++)
yading@11 337 avformat_new_stream(s, NULL);
yading@11 338
yading@11 339 return 0;
yading@11 340 }
yading@11 341
yading@11 342 static int decode_stream_header(NUTContext *nut)
yading@11 343 {
yading@11 344 AVFormatContext *s = nut->avf;
yading@11 345 AVIOContext *bc = s->pb;
yading@11 346 StreamContext *stc;
yading@11 347 int class, stream_id;
yading@11 348 uint64_t tmp, end;
yading@11 349 AVStream *st;
yading@11 350
yading@11 351 end = get_packetheader(nut, bc, 1, STREAM_STARTCODE);
yading@11 352 end += avio_tell(bc);
yading@11 353
yading@11 354 GET_V(stream_id, tmp < s->nb_streams && !nut->stream[tmp].time_base);
yading@11 355 stc = &nut->stream[stream_id];
yading@11 356 st = s->streams[stream_id];
yading@11 357 if (!st)
yading@11 358 return AVERROR(ENOMEM);
yading@11 359
yading@11 360 class = ffio_read_varlen(bc);
yading@11 361 tmp = get_fourcc(bc);
yading@11 362 st->codec->codec_tag = tmp;
yading@11 363 switch (class) {
yading@11 364 case 0:
yading@11 365 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
yading@11 366 st->codec->codec_id = av_codec_get_id((const AVCodecTag * const []) {
yading@11 367 ff_nut_video_tags,
yading@11 368 ff_codec_bmp_tags,
yading@11 369 0
yading@11 370 },
yading@11 371 tmp);
yading@11 372 break;
yading@11 373 case 1:
yading@11 374 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
yading@11 375 st->codec->codec_id = av_codec_get_id((const AVCodecTag * const []) {
yading@11 376 ff_nut_audio_tags,
yading@11 377 ff_codec_wav_tags,
yading@11 378 0
yading@11 379 },
yading@11 380 tmp);
yading@11 381 break;
yading@11 382 case 2:
yading@11 383 st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
yading@11 384 st->codec->codec_id = ff_codec_get_id(ff_nut_subtitle_tags, tmp);
yading@11 385 break;
yading@11 386 case 3:
yading@11 387 st->codec->codec_type = AVMEDIA_TYPE_DATA;
yading@11 388 st->codec->codec_id = ff_codec_get_id(ff_nut_data_tags, tmp);
yading@11 389 break;
yading@11 390 default:
yading@11 391 av_log(s, AV_LOG_ERROR, "unknown stream class (%d)\n", class);
yading@11 392 return -1;
yading@11 393 }
yading@11 394 if (class < 3 && st->codec->codec_id == AV_CODEC_ID_NONE)
yading@11 395 av_log(s, AV_LOG_ERROR,
yading@11 396 "Unknown codec tag '0x%04x' for stream number %d\n",
yading@11 397 (unsigned int) tmp, stream_id);
yading@11 398
yading@11 399 GET_V(stc->time_base_id, tmp < nut->time_base_count);
yading@11 400 GET_V(stc->msb_pts_shift, tmp < 16);
yading@11 401 stc->max_pts_distance = ffio_read_varlen(bc);
yading@11 402 GET_V(stc->decode_delay, tmp < 1000); // sanity limit, raise this if Moore's law is true
yading@11 403 st->codec->has_b_frames = stc->decode_delay;
yading@11 404 ffio_read_varlen(bc); // stream flags
yading@11 405
yading@11 406 GET_V(st->codec->extradata_size, tmp < (1 << 30));
yading@11 407 if (st->codec->extradata_size) {
yading@11 408 st->codec->extradata = av_mallocz(st->codec->extradata_size +
yading@11 409 FF_INPUT_BUFFER_PADDING_SIZE);
yading@11 410 avio_read(bc, st->codec->extradata, st->codec->extradata_size);
yading@11 411 }
yading@11 412
yading@11 413 if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
yading@11 414 GET_V(st->codec->width, tmp > 0);
yading@11 415 GET_V(st->codec->height, tmp > 0);
yading@11 416 st->sample_aspect_ratio.num = ffio_read_varlen(bc);
yading@11 417 st->sample_aspect_ratio.den = ffio_read_varlen(bc);
yading@11 418 if ((!st->sample_aspect_ratio.num) != (!st->sample_aspect_ratio.den)) {
yading@11 419 av_log(s, AV_LOG_ERROR, "invalid aspect ratio %d/%d\n",
yading@11 420 st->sample_aspect_ratio.num, st->sample_aspect_ratio.den);
yading@11 421 return -1;
yading@11 422 }
yading@11 423 ffio_read_varlen(bc); /* csp type */
yading@11 424 } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
yading@11 425 GET_V(st->codec->sample_rate, tmp > 0);
yading@11 426 ffio_read_varlen(bc); // samplerate_den
yading@11 427 GET_V(st->codec->channels, tmp > 0);
yading@11 428 }
yading@11 429 if (skip_reserved(bc, end) || ffio_get_checksum(bc)) {
yading@11 430 av_log(s, AV_LOG_ERROR,
yading@11 431 "stream header %d checksum mismatch\n", stream_id);
yading@11 432 return -1;
yading@11 433 }
yading@11 434 stc->time_base = &nut->time_base[stc->time_base_id];
yading@11 435 avpriv_set_pts_info(s->streams[stream_id], 63, stc->time_base->num,
yading@11 436 stc->time_base->den);
yading@11 437 return 0;
yading@11 438 }
yading@11 439
yading@11 440 static void set_disposition_bits(AVFormatContext *avf, char *value,
yading@11 441 int stream_id)
yading@11 442 {
yading@11 443 int flag = 0, i;
yading@11 444
yading@11 445 for (i = 0; ff_nut_dispositions[i].flag; ++i)
yading@11 446 if (!strcmp(ff_nut_dispositions[i].str, value))
yading@11 447 flag = ff_nut_dispositions[i].flag;
yading@11 448 if (!flag)
yading@11 449 av_log(avf, AV_LOG_INFO, "unknown disposition type '%s'\n", value);
yading@11 450 for (i = 0; i < avf->nb_streams; ++i)
yading@11 451 if (stream_id == i || stream_id == -1)
yading@11 452 avf->streams[i]->disposition |= flag;
yading@11 453 }
yading@11 454
yading@11 455 static int decode_info_header(NUTContext *nut)
yading@11 456 {
yading@11 457 AVFormatContext *s = nut->avf;
yading@11 458 AVIOContext *bc = s->pb;
yading@11 459 uint64_t tmp, chapter_start, chapter_len;
yading@11 460 unsigned int stream_id_plus1, count;
yading@11 461 int chapter_id, i;
yading@11 462 int64_t value, end;
yading@11 463 char name[256], str_value[1024], type_str[256];
yading@11 464 const char *type;
yading@11 465 AVChapter *chapter = NULL;
yading@11 466 AVStream *st = NULL;
yading@11 467 AVDictionary **metadata = NULL;
yading@11 468
yading@11 469 end = get_packetheader(nut, bc, 1, INFO_STARTCODE);
yading@11 470 end += avio_tell(bc);
yading@11 471
yading@11 472 GET_V(stream_id_plus1, tmp <= s->nb_streams);
yading@11 473 chapter_id = get_s(bc);
yading@11 474 chapter_start = ffio_read_varlen(bc);
yading@11 475 chapter_len = ffio_read_varlen(bc);
yading@11 476 count = ffio_read_varlen(bc);
yading@11 477
yading@11 478 if (chapter_id && !stream_id_plus1) {
yading@11 479 int64_t start = chapter_start / nut->time_base_count;
yading@11 480 chapter = avpriv_new_chapter(s, chapter_id,
yading@11 481 nut->time_base[chapter_start %
yading@11 482 nut->time_base_count],
yading@11 483 start, start + chapter_len, NULL);
yading@11 484 metadata = &chapter->metadata;
yading@11 485 } else if (stream_id_plus1) {
yading@11 486 st = s->streams[stream_id_plus1 - 1];
yading@11 487 metadata = &st->metadata;
yading@11 488 } else
yading@11 489 metadata = &s->metadata;
yading@11 490
yading@11 491 for (i = 0; i < count; i++) {
yading@11 492 get_str(bc, name, sizeof(name));
yading@11 493 value = get_s(bc);
yading@11 494 if (value == -1) {
yading@11 495 type = "UTF-8";
yading@11 496 get_str(bc, str_value, sizeof(str_value));
yading@11 497 } else if (value == -2) {
yading@11 498 get_str(bc, type_str, sizeof(type_str));
yading@11 499 type = type_str;
yading@11 500 get_str(bc, str_value, sizeof(str_value));
yading@11 501 } else if (value == -3) {
yading@11 502 type = "s";
yading@11 503 value = get_s(bc);
yading@11 504 } else if (value == -4) {
yading@11 505 type = "t";
yading@11 506 value = ffio_read_varlen(bc);
yading@11 507 } else if (value < -4) {
yading@11 508 type = "r";
yading@11 509 get_s(bc);
yading@11 510 } else {
yading@11 511 type = "v";
yading@11 512 }
yading@11 513
yading@11 514 if (stream_id_plus1 > s->nb_streams) {
yading@11 515 av_log(s, AV_LOG_ERROR, "invalid stream id for info packet\n");
yading@11 516 continue;
yading@11 517 }
yading@11 518
yading@11 519 if (!strcmp(type, "UTF-8")) {
yading@11 520 if (chapter_id == 0 && !strcmp(name, "Disposition")) {
yading@11 521 set_disposition_bits(s, str_value, stream_id_plus1 - 1);
yading@11 522 continue;
yading@11 523 }
yading@11 524
yading@11 525 if (stream_id_plus1 && !strcmp(name, "r_frame_rate")) {
yading@11 526 sscanf(str_value, "%d/%d", &st->r_frame_rate.num, &st->r_frame_rate.den);
yading@11 527 if (st->r_frame_rate.num >= 1000LL*st->r_frame_rate.den)
yading@11 528 st->r_frame_rate.num = st->r_frame_rate.den = 0;
yading@11 529 continue;
yading@11 530 }
yading@11 531
yading@11 532 if (metadata && av_strcasecmp(name, "Uses") &&
yading@11 533 av_strcasecmp(name, "Depends") && av_strcasecmp(name, "Replaces"))
yading@11 534 av_dict_set(metadata, name, str_value, 0);
yading@11 535 }
yading@11 536 }
yading@11 537
yading@11 538 if (skip_reserved(bc, end) || ffio_get_checksum(bc)) {
yading@11 539 av_log(s, AV_LOG_ERROR, "info header checksum mismatch\n");
yading@11 540 return -1;
yading@11 541 }
yading@11 542 return 0;
yading@11 543 }
yading@11 544
yading@11 545 static int decode_syncpoint(NUTContext *nut, int64_t *ts, int64_t *back_ptr)
yading@11 546 {
yading@11 547 AVFormatContext *s = nut->avf;
yading@11 548 AVIOContext *bc = s->pb;
yading@11 549 int64_t end;
yading@11 550 uint64_t tmp;
yading@11 551
yading@11 552 nut->last_syncpoint_pos = avio_tell(bc) - 8;
yading@11 553
yading@11 554 end = get_packetheader(nut, bc, 1, SYNCPOINT_STARTCODE);
yading@11 555 end += avio_tell(bc);
yading@11 556
yading@11 557 tmp = ffio_read_varlen(bc);
yading@11 558 *back_ptr = nut->last_syncpoint_pos - 16 * ffio_read_varlen(bc);
yading@11 559 if (*back_ptr < 0)
yading@11 560 return AVERROR_INVALIDDATA;
yading@11 561
yading@11 562 ff_nut_reset_ts(nut, nut->time_base[tmp % nut->time_base_count],
yading@11 563 tmp / nut->time_base_count);
yading@11 564
yading@11 565 if (skip_reserved(bc, end) || ffio_get_checksum(bc)) {
yading@11 566 av_log(s, AV_LOG_ERROR, "sync point checksum mismatch\n");
yading@11 567 return AVERROR_INVALIDDATA;
yading@11 568 }
yading@11 569
yading@11 570 *ts = tmp / nut->time_base_count *
yading@11 571 av_q2d(nut->time_base[tmp % nut->time_base_count]) * AV_TIME_BASE;
yading@11 572 ff_nut_add_sp(nut, nut->last_syncpoint_pos, *back_ptr, *ts);
yading@11 573
yading@11 574 return 0;
yading@11 575 }
yading@11 576
yading@11 577 //FIXME calculate exactly, this is just a good approximation.
yading@11 578 static int64_t find_duration(NUTContext *nut, int64_t filesize)
yading@11 579 {
yading@11 580 AVFormatContext *s = nut->avf;
yading@11 581 int64_t duration = 0;
yading@11 582
yading@11 583 int64_t pos = FFMAX(0, filesize - 2*nut->max_distance);
yading@11 584 for(;;){
yading@11 585 int64_t ts = nut_read_timestamp(s, -1, &pos, INT64_MAX);
yading@11 586 if(ts < 0)
yading@11 587 break;
yading@11 588 duration = FFMAX(duration, ts);
yading@11 589 pos++;
yading@11 590 }
yading@11 591 if(duration > 0)
yading@11 592 s->duration_estimation_method = AVFMT_DURATION_FROM_PTS;
yading@11 593 return duration;
yading@11 594 }
yading@11 595
yading@11 596 static int find_and_decode_index(NUTContext *nut)
yading@11 597 {
yading@11 598 AVFormatContext *s = nut->avf;
yading@11 599 AVIOContext *bc = s->pb;
yading@11 600 uint64_t tmp, end;
yading@11 601 int i, j, syncpoint_count;
yading@11 602 int64_t filesize = avio_size(bc);
yading@11 603 int64_t *syncpoints;
yading@11 604 int8_t *has_keyframe;
yading@11 605 int ret = -1;
yading@11 606
yading@11 607 if(filesize <= 0)
yading@11 608 return -1;
yading@11 609
yading@11 610 avio_seek(bc, filesize - 12, SEEK_SET);
yading@11 611 avio_seek(bc, filesize - avio_rb64(bc), SEEK_SET);
yading@11 612 if (avio_rb64(bc) != INDEX_STARTCODE) {
yading@11 613 av_log(s, AV_LOG_ERROR, "no index at the end\n");
yading@11 614
yading@11 615 if(s->duration<=0)
yading@11 616 s->duration = find_duration(nut, filesize);
yading@11 617 return -1;
yading@11 618 }
yading@11 619
yading@11 620 end = get_packetheader(nut, bc, 1, INDEX_STARTCODE);
yading@11 621 end += avio_tell(bc);
yading@11 622
yading@11 623 ffio_read_varlen(bc); // max_pts
yading@11 624 GET_V(syncpoint_count, tmp < INT_MAX / 8 && tmp > 0);
yading@11 625 syncpoints = av_malloc(sizeof(int64_t) * syncpoint_count);
yading@11 626 has_keyframe = av_malloc(sizeof(int8_t) * (syncpoint_count + 1));
yading@11 627 for (i = 0; i < syncpoint_count; i++) {
yading@11 628 syncpoints[i] = ffio_read_varlen(bc);
yading@11 629 if (syncpoints[i] <= 0)
yading@11 630 goto fail;
yading@11 631 if (i)
yading@11 632 syncpoints[i] += syncpoints[i - 1];
yading@11 633 }
yading@11 634
yading@11 635 for (i = 0; i < s->nb_streams; i++) {
yading@11 636 int64_t last_pts = -1;
yading@11 637 for (j = 0; j < syncpoint_count;) {
yading@11 638 uint64_t x = ffio_read_varlen(bc);
yading@11 639 int type = x & 1;
yading@11 640 int n = j;
yading@11 641 x >>= 1;
yading@11 642 if (type) {
yading@11 643 int flag = x & 1;
yading@11 644 x >>= 1;
yading@11 645 if (n + x >= syncpoint_count + 1) {
yading@11 646 av_log(s, AV_LOG_ERROR, "index overflow A %d + %"PRIu64" >= %d\n", n, x, syncpoint_count + 1);
yading@11 647 goto fail;
yading@11 648 }
yading@11 649 while (x--)
yading@11 650 has_keyframe[n++] = flag;
yading@11 651 has_keyframe[n++] = !flag;
yading@11 652 } else {
yading@11 653 while (x != 1) {
yading@11 654 if (n >= syncpoint_count + 1) {
yading@11 655 av_log(s, AV_LOG_ERROR, "index overflow B\n");
yading@11 656 goto fail;
yading@11 657 }
yading@11 658 has_keyframe[n++] = x & 1;
yading@11 659 x >>= 1;
yading@11 660 }
yading@11 661 }
yading@11 662 if (has_keyframe[0]) {
yading@11 663 av_log(s, AV_LOG_ERROR, "keyframe before first syncpoint in index\n");
yading@11 664 goto fail;
yading@11 665 }
yading@11 666 av_assert0(n <= syncpoint_count + 1);
yading@11 667 for (; j < n && j < syncpoint_count; j++) {
yading@11 668 if (has_keyframe[j]) {
yading@11 669 uint64_t B, A = ffio_read_varlen(bc);
yading@11 670 if (!A) {
yading@11 671 A = ffio_read_varlen(bc);
yading@11 672 B = ffio_read_varlen(bc);
yading@11 673 // eor_pts[j][i] = last_pts + A + B
yading@11 674 } else
yading@11 675 B = 0;
yading@11 676 av_add_index_entry(s->streams[i], 16 * syncpoints[j - 1],
yading@11 677 last_pts + A, 0, 0, AVINDEX_KEYFRAME);
yading@11 678 last_pts += A + B;
yading@11 679 }
yading@11 680 }
yading@11 681 }
yading@11 682 }
yading@11 683
yading@11 684 if (skip_reserved(bc, end) || ffio_get_checksum(bc)) {
yading@11 685 av_log(s, AV_LOG_ERROR, "index checksum mismatch\n");
yading@11 686 goto fail;
yading@11 687 }
yading@11 688 ret = 0;
yading@11 689
yading@11 690 fail:
yading@11 691 av_free(syncpoints);
yading@11 692 av_free(has_keyframe);
yading@11 693 return ret;
yading@11 694 }
yading@11 695
yading@11 696 static int nut_read_header(AVFormatContext *s)
yading@11 697 {
yading@11 698 NUTContext *nut = s->priv_data;
yading@11 699 AVIOContext *bc = s->pb;
yading@11 700 int64_t pos;
yading@11 701 int initialized_stream_count;
yading@11 702
yading@11 703 nut->avf = s;
yading@11 704
yading@11 705 /* main header */
yading@11 706 pos = 0;
yading@11 707 do {
yading@11 708 pos = find_startcode(bc, MAIN_STARTCODE, pos) + 1;
yading@11 709 if (pos < 0 + 1) {
yading@11 710 av_log(s, AV_LOG_ERROR, "No main startcode found.\n");
yading@11 711 return AVERROR_INVALIDDATA;
yading@11 712 }
yading@11 713 } while (decode_main_header(nut) < 0);
yading@11 714
yading@11 715 /* stream headers */
yading@11 716 pos = 0;
yading@11 717 for (initialized_stream_count = 0; initialized_stream_count < s->nb_streams;) {
yading@11 718 pos = find_startcode(bc, STREAM_STARTCODE, pos) + 1;
yading@11 719 if (pos < 0 + 1) {
yading@11 720 av_log(s, AV_LOG_ERROR, "Not all stream headers found.\n");
yading@11 721 return AVERROR_INVALIDDATA;
yading@11 722 }
yading@11 723 if (decode_stream_header(nut) >= 0)
yading@11 724 initialized_stream_count++;
yading@11 725 }
yading@11 726
yading@11 727 /* info headers */
yading@11 728 pos = 0;
yading@11 729 for (;;) {
yading@11 730 uint64_t startcode = find_any_startcode(bc, pos);
yading@11 731 pos = avio_tell(bc);
yading@11 732
yading@11 733 if (startcode == 0) {
yading@11 734 av_log(s, AV_LOG_ERROR, "EOF before video frames\n");
yading@11 735 return AVERROR_INVALIDDATA;
yading@11 736 } else if (startcode == SYNCPOINT_STARTCODE) {
yading@11 737 nut->next_startcode = startcode;
yading@11 738 break;
yading@11 739 } else if (startcode != INFO_STARTCODE) {
yading@11 740 continue;
yading@11 741 }
yading@11 742
yading@11 743 decode_info_header(nut);
yading@11 744 }
yading@11 745
yading@11 746 s->data_offset = pos - 8;
yading@11 747
yading@11 748 if (bc->seekable) {
yading@11 749 int64_t orig_pos = avio_tell(bc);
yading@11 750 find_and_decode_index(nut);
yading@11 751 avio_seek(bc, orig_pos, SEEK_SET);
yading@11 752 }
yading@11 753 av_assert0(nut->next_startcode == SYNCPOINT_STARTCODE);
yading@11 754
yading@11 755 ff_metadata_conv_ctx(s, NULL, ff_nut_metadata_conv);
yading@11 756
yading@11 757 return 0;
yading@11 758 }
yading@11 759
yading@11 760 static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id,
yading@11 761 uint8_t *header_idx, int frame_code)
yading@11 762 {
yading@11 763 AVFormatContext *s = nut->avf;
yading@11 764 AVIOContext *bc = s->pb;
yading@11 765 StreamContext *stc;
yading@11 766 int size, flags, size_mul, pts_delta, i, reserved_count;
yading@11 767 uint64_t tmp;
yading@11 768
yading@11 769 if (avio_tell(bc) > nut->last_syncpoint_pos + nut->max_distance) {
yading@11 770 av_log(s, AV_LOG_ERROR,
yading@11 771 "Last frame must have been damaged %"PRId64" > %"PRId64" + %d\n",
yading@11 772 avio_tell(bc), nut->last_syncpoint_pos, nut->max_distance);
yading@11 773 return AVERROR_INVALIDDATA;
yading@11 774 }
yading@11 775
yading@11 776 flags = nut->frame_code[frame_code].flags;
yading@11 777 size_mul = nut->frame_code[frame_code].size_mul;
yading@11 778 size = nut->frame_code[frame_code].size_lsb;
yading@11 779 *stream_id = nut->frame_code[frame_code].stream_id;
yading@11 780 pts_delta = nut->frame_code[frame_code].pts_delta;
yading@11 781 reserved_count = nut->frame_code[frame_code].reserved_count;
yading@11 782 *header_idx = nut->frame_code[frame_code].header_idx;
yading@11 783
yading@11 784 if (flags & FLAG_INVALID)
yading@11 785 return AVERROR_INVALIDDATA;
yading@11 786 if (flags & FLAG_CODED)
yading@11 787 flags ^= ffio_read_varlen(bc);
yading@11 788 if (flags & FLAG_STREAM_ID) {
yading@11 789 GET_V(*stream_id, tmp < s->nb_streams);
yading@11 790 }
yading@11 791 stc = &nut->stream[*stream_id];
yading@11 792 if (flags & FLAG_CODED_PTS) {
yading@11 793 int coded_pts = ffio_read_varlen(bc);
yading@11 794 // FIXME check last_pts validity?
yading@11 795 if (coded_pts < (1 << stc->msb_pts_shift)) {
yading@11 796 *pts = ff_lsb2full(stc, coded_pts);
yading@11 797 } else
yading@11 798 *pts = coded_pts - (1LL << stc->msb_pts_shift);
yading@11 799 } else
yading@11 800 *pts = stc->last_pts + pts_delta;
yading@11 801 if (flags & FLAG_SIZE_MSB)
yading@11 802 size += size_mul * ffio_read_varlen(bc);
yading@11 803 if (flags & FLAG_MATCH_TIME)
yading@11 804 get_s(bc);
yading@11 805 if (flags & FLAG_HEADER_IDX)
yading@11 806 *header_idx = ffio_read_varlen(bc);
yading@11 807 if (flags & FLAG_RESERVED)
yading@11 808 reserved_count = ffio_read_varlen(bc);
yading@11 809 for (i = 0; i < reserved_count; i++)
yading@11 810 ffio_read_varlen(bc);
yading@11 811
yading@11 812 if (*header_idx >= (unsigned)nut->header_count) {
yading@11 813 av_log(s, AV_LOG_ERROR, "header_idx invalid\n");
yading@11 814 return AVERROR_INVALIDDATA;
yading@11 815 }
yading@11 816 if (size > 4096)
yading@11 817 *header_idx = 0;
yading@11 818 size -= nut->header_len[*header_idx];
yading@11 819
yading@11 820 if (flags & FLAG_CHECKSUM) {
yading@11 821 avio_rb32(bc); // FIXME check this
yading@11 822 } else if (size > 2 * nut->max_distance || FFABS(stc->last_pts - *pts) >
yading@11 823 stc->max_pts_distance) {
yading@11 824 av_log(s, AV_LOG_ERROR, "frame size > 2max_distance and no checksum\n");
yading@11 825 return AVERROR_INVALIDDATA;
yading@11 826 }
yading@11 827
yading@11 828 stc->last_pts = *pts;
yading@11 829 stc->last_flags = flags;
yading@11 830
yading@11 831 return size;
yading@11 832 }
yading@11 833
yading@11 834 static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code)
yading@11 835 {
yading@11 836 AVFormatContext *s = nut->avf;
yading@11 837 AVIOContext *bc = s->pb;
yading@11 838 int size, stream_id, discard;
yading@11 839 int64_t pts, last_IP_pts;
yading@11 840 StreamContext *stc;
yading@11 841 uint8_t header_idx;
yading@11 842
yading@11 843 size = decode_frame_header(nut, &pts, &stream_id, &header_idx, frame_code);
yading@11 844 if (size < 0)
yading@11 845 return size;
yading@11 846
yading@11 847 stc = &nut->stream[stream_id];
yading@11 848
yading@11 849 if (stc->last_flags & FLAG_KEY)
yading@11 850 stc->skip_until_key_frame = 0;
yading@11 851
yading@11 852 discard = s->streams[stream_id]->discard;
yading@11 853 last_IP_pts = s->streams[stream_id]->last_IP_pts;
yading@11 854 if ((discard >= AVDISCARD_NONKEY && !(stc->last_flags & FLAG_KEY)) ||
yading@11 855 (discard >= AVDISCARD_BIDIR && last_IP_pts != AV_NOPTS_VALUE &&
yading@11 856 last_IP_pts > pts) ||
yading@11 857 discard >= AVDISCARD_ALL ||
yading@11 858 stc->skip_until_key_frame) {
yading@11 859 avio_skip(bc, size);
yading@11 860 return 1;
yading@11 861 }
yading@11 862
yading@11 863 if (av_new_packet(pkt, size + nut->header_len[header_idx]) < 0)
yading@11 864 return AVERROR(ENOMEM);
yading@11 865 memcpy(pkt->data, nut->header[header_idx], nut->header_len[header_idx]);
yading@11 866 pkt->pos = avio_tell(bc); // FIXME
yading@11 867 avio_read(bc, pkt->data + nut->header_len[header_idx], size);
yading@11 868
yading@11 869 pkt->stream_index = stream_id;
yading@11 870 if (stc->last_flags & FLAG_KEY)
yading@11 871 pkt->flags |= AV_PKT_FLAG_KEY;
yading@11 872 pkt->pts = pts;
yading@11 873
yading@11 874 return 0;
yading@11 875 }
yading@11 876
yading@11 877 static int nut_read_packet(AVFormatContext *s, AVPacket *pkt)
yading@11 878 {
yading@11 879 NUTContext *nut = s->priv_data;
yading@11 880 AVIOContext *bc = s->pb;
yading@11 881 int i, frame_code = 0, ret, skip;
yading@11 882 int64_t ts, back_ptr;
yading@11 883
yading@11 884 for (;;) {
yading@11 885 int64_t pos = avio_tell(bc);
yading@11 886 uint64_t tmp = nut->next_startcode;
yading@11 887 nut->next_startcode = 0;
yading@11 888
yading@11 889 if (tmp) {
yading@11 890 pos -= 8;
yading@11 891 } else {
yading@11 892 frame_code = avio_r8(bc);
yading@11 893 if (url_feof(bc))
yading@11 894 return -1;
yading@11 895 if (frame_code == 'N') {
yading@11 896 tmp = frame_code;
yading@11 897 for (i = 1; i < 8; i++)
yading@11 898 tmp = (tmp << 8) + avio_r8(bc);
yading@11 899 }
yading@11 900 }
yading@11 901 switch (tmp) {
yading@11 902 case MAIN_STARTCODE:
yading@11 903 case STREAM_STARTCODE:
yading@11 904 case INDEX_STARTCODE:
yading@11 905 skip = get_packetheader(nut, bc, 0, tmp);
yading@11 906 avio_skip(bc, skip);
yading@11 907 break;
yading@11 908 case INFO_STARTCODE:
yading@11 909 if (decode_info_header(nut) < 0)
yading@11 910 goto resync;
yading@11 911 break;
yading@11 912 case SYNCPOINT_STARTCODE:
yading@11 913 if (decode_syncpoint(nut, &ts, &back_ptr) < 0)
yading@11 914 goto resync;
yading@11 915 frame_code = avio_r8(bc);
yading@11 916 case 0:
yading@11 917 ret = decode_frame(nut, pkt, frame_code);
yading@11 918 if (ret == 0)
yading@11 919 return 0;
yading@11 920 else if (ret == 1) // OK but discard packet
yading@11 921 break;
yading@11 922 default:
yading@11 923 resync:
yading@11 924 av_log(s, AV_LOG_DEBUG, "syncing from %"PRId64"\n", pos);
yading@11 925 tmp = find_any_startcode(bc, nut->last_syncpoint_pos + 1);
yading@11 926 if (tmp == 0)
yading@11 927 return AVERROR_INVALIDDATA;
yading@11 928 av_log(s, AV_LOG_DEBUG, "sync\n");
yading@11 929 nut->next_startcode = tmp;
yading@11 930 }
yading@11 931 }
yading@11 932 }
yading@11 933
yading@11 934 static int64_t nut_read_timestamp(AVFormatContext *s, int stream_index,
yading@11 935 int64_t *pos_arg, int64_t pos_limit)
yading@11 936 {
yading@11 937 NUTContext *nut = s->priv_data;
yading@11 938 AVIOContext *bc = s->pb;
yading@11 939 int64_t pos, pts, back_ptr;
yading@11 940 av_log(s, AV_LOG_DEBUG, "read_timestamp(X,%d,%"PRId64",%"PRId64")\n",
yading@11 941 stream_index, *pos_arg, pos_limit);
yading@11 942
yading@11 943 pos = *pos_arg;
yading@11 944 do {
yading@11 945 pos = find_startcode(bc, SYNCPOINT_STARTCODE, pos) + 1;
yading@11 946 if (pos < 1) {
yading@11 947 av_log(s, AV_LOG_ERROR, "read_timestamp failed.\n");
yading@11 948 return AV_NOPTS_VALUE;
yading@11 949 }
yading@11 950 } while (decode_syncpoint(nut, &pts, &back_ptr) < 0);
yading@11 951 *pos_arg = pos - 1;
yading@11 952 av_assert0(nut->last_syncpoint_pos == *pos_arg);
yading@11 953
yading@11 954 av_log(s, AV_LOG_DEBUG, "return %"PRId64" %"PRId64"\n", pts, back_ptr);
yading@11 955 if (stream_index == -2)
yading@11 956 return back_ptr;
yading@11 957 av_assert0(stream_index == -1);
yading@11 958 return pts;
yading@11 959 }
yading@11 960
yading@11 961 static int read_seek(AVFormatContext *s, int stream_index,
yading@11 962 int64_t pts, int flags)
yading@11 963 {
yading@11 964 NUTContext *nut = s->priv_data;
yading@11 965 AVStream *st = s->streams[stream_index];
yading@11 966 Syncpoint dummy = { .ts = pts * av_q2d(st->time_base) * AV_TIME_BASE };
yading@11 967 Syncpoint nopts_sp = { .ts = AV_NOPTS_VALUE, .back_ptr = AV_NOPTS_VALUE };
yading@11 968 Syncpoint *sp, *next_node[2] = { &nopts_sp, &nopts_sp };
yading@11 969 int64_t pos, pos2, ts;
yading@11 970 int i;
yading@11 971
yading@11 972 if (st->index_entries) {
yading@11 973 int index = av_index_search_timestamp(st, pts, flags);
yading@11 974 if (index < 0)
yading@11 975 index = av_index_search_timestamp(st, pts, flags ^ AVSEEK_FLAG_BACKWARD);
yading@11 976 if (index < 0)
yading@11 977 return -1;
yading@11 978
yading@11 979 pos2 = st->index_entries[index].pos;
yading@11 980 ts = st->index_entries[index].timestamp;
yading@11 981 } else {
yading@11 982 av_tree_find(nut->syncpoints, &dummy, (void *) ff_nut_sp_pts_cmp,
yading@11 983 (void **) next_node);
yading@11 984 av_log(s, AV_LOG_DEBUG, "%"PRIu64"-%"PRIu64" %"PRId64"-%"PRId64"\n",
yading@11 985 next_node[0]->pos, next_node[1]->pos, next_node[0]->ts,
yading@11 986 next_node[1]->ts);
yading@11 987 pos = ff_gen_search(s, -1, dummy.ts, next_node[0]->pos,
yading@11 988 next_node[1]->pos, next_node[1]->pos,
yading@11 989 next_node[0]->ts, next_node[1]->ts,
yading@11 990 AVSEEK_FLAG_BACKWARD, &ts, nut_read_timestamp);
yading@11 991
yading@11 992 if (!(flags & AVSEEK_FLAG_BACKWARD)) {
yading@11 993 dummy.pos = pos + 16;
yading@11 994 next_node[1] = &nopts_sp;
yading@11 995 av_tree_find(nut->syncpoints, &dummy, (void *) ff_nut_sp_pos_cmp,
yading@11 996 (void **) next_node);
yading@11 997 pos2 = ff_gen_search(s, -2, dummy.pos, next_node[0]->pos,
yading@11 998 next_node[1]->pos, next_node[1]->pos,
yading@11 999 next_node[0]->back_ptr, next_node[1]->back_ptr,
yading@11 1000 flags, &ts, nut_read_timestamp);
yading@11 1001 if (pos2 >= 0)
yading@11 1002 pos = pos2;
yading@11 1003 // FIXME dir but I think it does not matter
yading@11 1004 }
yading@11 1005 dummy.pos = pos;
yading@11 1006 sp = av_tree_find(nut->syncpoints, &dummy, (void *) ff_nut_sp_pos_cmp,
yading@11 1007 NULL);
yading@11 1008
yading@11 1009 av_assert0(sp);
yading@11 1010 pos2 = sp->back_ptr - 15;
yading@11 1011 }
yading@11 1012 av_log(NULL, AV_LOG_DEBUG, "SEEKTO: %"PRId64"\n", pos2);
yading@11 1013 pos = find_startcode(s->pb, SYNCPOINT_STARTCODE, pos2);
yading@11 1014 avio_seek(s->pb, pos, SEEK_SET);
yading@11 1015 av_log(NULL, AV_LOG_DEBUG, "SP: %"PRId64"\n", pos);
yading@11 1016 if (pos2 > pos || pos2 + 15 < pos)
yading@11 1017 av_log(NULL, AV_LOG_ERROR, "no syncpoint at backptr pos\n");
yading@11 1018 for (i = 0; i < s->nb_streams; i++)
yading@11 1019 nut->stream[i].skip_until_key_frame = 1;
yading@11 1020
yading@11 1021 return 0;
yading@11 1022 }
yading@11 1023
yading@11 1024 static int nut_read_close(AVFormatContext *s)
yading@11 1025 {
yading@11 1026 NUTContext *nut = s->priv_data;
yading@11 1027 int i;
yading@11 1028
yading@11 1029 av_freep(&nut->time_base);
yading@11 1030 av_freep(&nut->stream);
yading@11 1031 ff_nut_free_sp(nut);
yading@11 1032 for (i = 1; i < nut->header_count; i++)
yading@11 1033 av_freep(&nut->header[i]);
yading@11 1034
yading@11 1035 return 0;
yading@11 1036 }
yading@11 1037
yading@11 1038 AVInputFormat ff_nut_demuxer = {
yading@11 1039 .name = "nut",
yading@11 1040 .long_name = NULL_IF_CONFIG_SMALL("NUT"),
yading@11 1041 .flags = AVFMT_SEEK_TO_PTS,
yading@11 1042 .priv_data_size = sizeof(NUTContext),
yading@11 1043 .read_probe = nut_probe,
yading@11 1044 .read_header = nut_read_header,
yading@11 1045 .read_packet = nut_read_packet,
yading@11 1046 .read_close = nut_read_close,
yading@11 1047 .read_seek = read_seek,
yading@11 1048 .extensions = "nut",
yading@11 1049 .codec_tag = ff_nut_codec_tags,
yading@11 1050 };