📄 utils.c
字号:
index++; //index points to next instead of previous entry, maybe nonexistant ie= &st->index_entries[index]; }else assert(index==0); if(index != st->nb_index_entries){ assert(index < st->nb_index_entries); memmove(entries + index + 1, entries + index, sizeof(AVIndexEntry)*(st->nb_index_entries - index)); } st->nb_index_entries++; }else{ if(ie->pos == pos && distance < ie->min_distance) //dont reduce the distance distance= ie->min_distance; } }else{ index= st->nb_index_entries++; ie= &entries[index]; } ie->pos = pos; ie->timestamp = timestamp; ie->min_distance= distance; ie->flags = flags; return index;}/* build an index for raw streams using a parser */static void av_build_index_raw(AVFormatContext *s){ AVPacket pkt1, *pkt = &pkt1; int ret; AVStream *st; st = s->streams[0]; av_read_frame_flush(s); url_fseek(&s->pb, s->data_offset, SEEK_SET); for(;;) { ret = av_read_frame(s, pkt); if (ret < 0) break; if (pkt->stream_index == 0 && st->parser && (pkt->flags & PKT_FLAG_KEY)) { int64_t dts= av_rescale(pkt->dts, st->time_base.den, AV_TIME_BASE*(int64_t)st->time_base.num); av_add_index_entry(st, st->parser->frame_offset, dts, 0, AVINDEX_KEYFRAME); } av_free_packet(pkt); }}/* return TRUE if we deal with a raw stream (raw codec data and parsing needed) */static int is_raw_stream(AVFormatContext *s){ AVStream *st; if (s->nb_streams != 1) return 0; st = s->streams[0]; if (!st->need_parsing) return 0; return 1;}/* return the largest index entry whose timestamp is <= wanted_timestamp */int av_index_search_timestamp(AVStream *st, int wanted_timestamp){ AVIndexEntry *entries= st->index_entries; int nb_entries= st->nb_index_entries; int a, b, m; int64_t timestamp; if (nb_entries <= 0) return -1; a = 0; b = nb_entries - 1; while (a < b) { m = (a + b + 1) >> 1; timestamp = entries[m].timestamp; if (timestamp > wanted_timestamp) { b = m - 1; } else { a = m; } } return a;}#define DEBUG_SEEK/** * Does a binary search using av_index_search_timestamp() and AVCodec.read_timestamp(). * this isnt supposed to be called directly by a user application, but by demuxers * @param target_ts target timestamp in the time base of the given stream * @param stream_index stream number */int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts){ AVInputFormat *avif= s->iformat; int64_t pos_min, pos_max, pos, pos_limit; int64_t ts_min, ts_max, ts; int64_t start_pos; int index, no_change, i; AVStream *st; if (stream_index < 0) return -1; #ifdef DEBUG_SEEK av_log(s, AV_LOG_DEBUG, "read_seek: %d %lld\n", stream_index, target_ts);#endif ts_max= ts_min= AV_NOPTS_VALUE; pos_limit= -1; //gcc falsely says it may be uninitalized st= s->streams[stream_index]; if(st->index_entries){ AVIndexEntry *e; index= av_index_search_timestamp(st, target_ts); e= &st->index_entries[index]; if(e->timestamp <= target_ts || e->pos == e->min_distance){ pos_min= e->pos; ts_min= e->timestamp;#ifdef DEBUG_SEEK av_log(s, AV_LOG_DEBUG, "using cached pos_min=0x%llx dts_min=%lld\n", pos_min,ts_min);#endif }else{ assert(index==0); } index++; if(index < st->nb_index_entries){ e= &st->index_entries[index]; assert(e->timestamp >= target_ts); pos_max= e->pos; ts_max= e->timestamp; pos_limit= pos_max - e->min_distance;#ifdef DEBUG_SEEK av_log(s, AV_LOG_DEBUG, "using cached pos_max=0x%llx pos_limit=0x%llx dts_max=%lld\n", pos_max,pos_limit, ts_max);#endif } } if(ts_min == AV_NOPTS_VALUE){ pos_min = s->data_offset; ts_min = avif->read_timestamp(s, stream_index, &pos_min, INT64_MAX); if (ts_min == AV_NOPTS_VALUE) return -1; } if(ts_max == AV_NOPTS_VALUE){ int step= 1024; pos_max = url_filesize(url_fileno(&s->pb)) - 1; do{ pos_max -= step; ts_max = avif->read_timestamp(s, stream_index, &pos_max, pos_max + step); step += step; }while(ts_max == AV_NOPTS_VALUE && pos_max >= step); if (ts_max == AV_NOPTS_VALUE) return -1; for(;;){ int64_t tmp_pos= pos_max + 1; int64_t tmp_ts= avif->read_timestamp(s, stream_index, &tmp_pos, INT64_MAX); if(tmp_ts == AV_NOPTS_VALUE) break; ts_max= tmp_ts; pos_max= tmp_pos; } pos_limit= pos_max; } no_change=0; while (pos_min < pos_limit) {#ifdef DEBUG_SEEK av_log(s, AV_LOG_DEBUG, "pos_min=0x%llx pos_max=0x%llx dts_min=%lld dts_max=%lld\n", pos_min, pos_max, ts_min, ts_max);#endif assert(pos_limit <= pos_max); if(no_change==0){ int64_t approximate_keyframe_distance= pos_max - pos_limit; // interpolate position (better than dichotomy) pos = (int64_t)((double)(pos_max - pos_min) * (double)(target_ts - ts_min) / (double)(ts_max - ts_min)) + pos_min - approximate_keyframe_distance; }else if(no_change==1){ // bisection, if interpolation failed to change min or max pos last time pos = (pos_min + pos_limit)>>1; }else{ // linear search if bisection failed, can only happen if there are very few or no keframes between min/max pos=pos_min; } if(pos <= pos_min) pos= pos_min + 1; else if(pos > pos_limit) pos= pos_limit; start_pos= pos; ts = avif->read_timestamp(s, stream_index, &pos, INT64_MAX); //may pass pos_limit instead of -1 if(pos == pos_max) no_change++; else no_change=0;#ifdef DEBUG_SEEKav_log(s, AV_LOG_DEBUG, "%Ld %Ld %Ld / %Ld %Ld %Ld target:%Ld limit:%Ld start:%Ld noc:%d\n", pos_min, pos, pos_max, ts_min, ts, ts_max, target_ts, pos_limit, start_pos, no_change);#endif assert(ts != AV_NOPTS_VALUE); if (target_ts < ts) { pos_limit = start_pos - 1; pos_max = pos; ts_max = ts; } else { pos_min = pos; ts_min = ts; /* check if we are lucky */ if (target_ts == ts) break; } } pos = pos_min;#ifdef DEBUG_SEEK pos_min = pos; ts_min = avif->read_timestamp(s, stream_index, &pos_min, INT64_MAX); pos_min++; ts_max = avif->read_timestamp(s, stream_index, &pos_min, INT64_MAX); av_log(s, AV_LOG_DEBUG, "pos=0x%llx %lld<=%lld<=%lld\n", pos, ts_min, target_ts, ts_max);#endif /* do the seek */ url_fseek(&s->pb, pos, SEEK_SET); ts= av_rescale(ts_min, AV_TIME_BASE*(int64_t)st->time_base.num, st->time_base.den); for(i = 0; i < s->nb_streams; i++) { st = s->streams[i]; st->cur_dts = av_rescale(ts, st->time_base.den, AV_TIME_BASE*(int64_t)st->time_base.num); } return 0;}static int av_seek_frame_generic(AVFormatContext *s, int stream_index, int64_t timestamp){ int index, i; AVStream *st; AVIndexEntry *ie; if (!s->index_built) { if (is_raw_stream(s)) { av_build_index_raw(s); } else { return -1; } s->index_built = 1; } st = s->streams[stream_index]; index = av_index_search_timestamp(st, timestamp); if (index < 0) return -1; /* now we have found the index, we can seek */ ie = &st->index_entries[index]; av_read_frame_flush(s); url_fseek(&s->pb, ie->pos, SEEK_SET); timestamp= av_rescale(ie->timestamp, AV_TIME_BASE*(int64_t)st->time_base.num, st->time_base.den); for(i = 0; i < s->nb_streams; i++) { st = s->streams[i]; st->cur_dts = av_rescale(timestamp, st->time_base.den, AV_TIME_BASE*(int64_t)st->time_base.num); } return 0;}/** * Seek to the key frame just before the frame at timestamp * 'timestamp' in 'stream_index'. * @param stream_index If stream_index is (-1), a default * stream is selected * @param timestamp timestamp in AV_TIME_BASE units * @return >= 0 on success */int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp){ int ret; AVStream *st; av_read_frame_flush(s); if(stream_index < 0){ stream_index= av_find_default_stream_index(s); if(stream_index < 0) return -1; } st= s->streams[stream_index]; timestamp = av_rescale(timestamp, st->time_base.den, AV_TIME_BASE * (int64_t)st->time_base.num); /* first, we try the format specific seek */ if (s->iformat->read_seek) ret = s->iformat->read_seek(s, stream_index, timestamp); else ret = -1; if (ret >= 0) { return 0; } if(s->iformat->read_timestamp) return av_seek_frame_binary(s, stream_index, timestamp); else return av_seek_frame_generic(s, stream_index, timestamp);}/*******************************************************//* return TRUE if the stream has accurate timings for at least one component */static int av_has_timings(AVFormatContext *ic){ int i; AVStream *st; for(i = 0;i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->start_time != AV_NOPTS_VALUE && st->duration != AV_NOPTS_VALUE) return 1; } return 0;}/* estimate the stream timings from the one of each components. Also compute the global bitrate if possible */static void av_update_stream_timings(AVFormatContext *ic){ int64_t start_time, end_time, end_time1; int i; AVStream *st; start_time = MAXINT64; end_time = MININT64; for(i = 0;i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->start_time != AV_NOPTS_VALUE) { if (st->start_time < start_time) start_time = st->start_time; if (st->duration != AV_NOPTS_VALUE) { end_time1 = st->start_time + st->duration; if (end_time1 > end_time) end_time = end_time1; } } } if (start_time != MAXINT64) { ic->start_time = start_time; if (end_time != MAXINT64) { ic->duration = end_time - start_time; if (ic->file_size > 0) { /* compute the bit rate */ ic->bit_rate = (double)ic->file_size * 8.0 * AV_TIME_BASE / (double)ic->duration; } } }}static void fill_all_stream_timings(AVFormatContext *ic){ int i; AVStream *st; av_update_stream_timings(ic); for(i = 0;i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->start_time == AV_NOPTS_VALUE) { st->start_time = ic->start_time; st->duration = ic->duration; } }}static void av_estimate_timings_from_bit_rate(AVFormatContext *ic){ int64_t filesize, duration; int bit_rate, i; AVStream *st; /* if bit_rate is already set, we believe it */ if (ic->bit_rate == 0) { bit_rate = 0; for(i=0;i<ic->nb_streams;i++) { st = ic->streams[i]; bit_rate += st->codec.bit_rate; } ic->bit_rate = bit_rate; } /* if duration is already set, we believe it */ if (ic->duration == AV_NOPTS_VALUE && ic->bit_rate != 0 && ic->file_size != 0) { filesize = ic->file_size; if (filesize > 0) { duration = (int64_t)((8 * AV_TIME_BASE * (double)filesize) / (double)ic->bit_rate); for(i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->start_time == AV_NOPTS_VALUE || st->duration == AV_NOPTS_VALUE) { st->start_time = 0; st->duration = duration; } } } }}#define DURATION_MAX_READ_SIZE 250000/* only usable for MPEG-PS streams */static void av_estimate_timings_from_pts(AVFormatContext *ic){ AVPacket pkt1, *pkt = &pkt1; AVStream *st; int read_size, i, ret; int64_t start_time, end_time, end_time1; int64_t filesize, offset, duration;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -