📄 utils.c
字号:
st= s->streams[stream_index]; if(st->index_entries){ AVIndexEntry *e; index= av_index_search_timestamp(st, target_ts, flags | AVSEEK_FLAG_BACKWARD); //FIXME whole func must be checked for non-keyframe entries in index case, especially read_timestamp() index= FFMAX(index, 0); 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%"PRIx64" dts_min=%"PRId64"\n", pos_min,ts_min);#endif }else{ assert(index==0); } index= av_index_search_timestamp(st, target_ts, flags & ~AVSEEK_FLAG_BACKWARD); assert(index < st->nb_index_entries); if(index >= 0){ 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%"PRIx64" pos_limit=0x%"PRIx64" dts_max=%"PRId64"\n", pos_max,pos_limit, ts_max);#endif } } pos= av_gen_search(s, stream_index, target_ts, pos_min, pos_max, pos_limit, ts_min, ts_max, flags, &ts, avif->read_timestamp); if(pos<0) return -1; /* do the seek */ url_fseek(s->pb, pos, SEEK_SET); av_update_cur_dts(s, st, ts); return 0;}int64_t av_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, int64_t pos_min, int64_t pos_max, int64_t pos_limit, int64_t ts_min, int64_t ts_max, int flags, int64_t *ts_ret, int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t )){ int64_t pos, ts; int64_t start_pos, filesize; int no_change;#ifdef DEBUG_SEEK av_log(s, AV_LOG_DEBUG, "gen_seek: %d %"PRId64"\n", stream_index, target_ts);#endif if(ts_min == AV_NOPTS_VALUE){ pos_min = s->data_offset; ts_min = 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; filesize = url_fsize(s->pb); pos_max = filesize - 1; do{ pos_max -= step; ts_max = 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= read_timestamp(s, stream_index, &tmp_pos, INT64_MAX); if(tmp_ts == AV_NOPTS_VALUE) break; ts_max= tmp_ts; pos_max= tmp_pos; if(tmp_pos >= filesize) break; } pos_limit= pos_max; } if(ts_min > ts_max){ return -1; }else if(ts_min == ts_max){ pos_limit= pos_min; } no_change=0; while (pos_min < pos_limit) {#ifdef DEBUG_SEEK av_log(s, AV_LOG_DEBUG, "pos_min=0x%"PRIx64" pos_max=0x%"PRIx64" dts_min=%"PRId64" dts_max=%"PRId64"\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 = av_rescale(target_ts - ts_min, pos_max - pos_min, 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 keyframes 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 = 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, "%"PRId64" %"PRId64" %"PRId64" / %"PRId64" %"PRId64" %"PRId64" target:%"PRId64" limit:%"PRId64" start:%"PRId64" noc:%d\n", pos_min, pos, pos_max, ts_min, ts, ts_max, target_ts, pos_limit, start_pos, no_change);#endif if(ts == AV_NOPTS_VALUE){ av_log(s, AV_LOG_ERROR, "read_timestamp() failed in the middle\n"); return -1; } assert(ts != AV_NOPTS_VALUE); if (target_ts <= ts) { pos_limit = start_pos - 1; pos_max = pos; ts_max = ts; } if (target_ts >= ts) { pos_min = pos; ts_min = ts; } } pos = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max; ts = (flags & AVSEEK_FLAG_BACKWARD) ? ts_min : ts_max;#ifdef DEBUG_SEEK pos_min = pos; ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX); pos_min++; ts_max = read_timestamp(s, stream_index, &pos_min, INT64_MAX); av_log(s, AV_LOG_DEBUG, "pos=0x%"PRIx64" %"PRId64"<=%"PRId64"<=%"PRId64"\n", pos, ts_min, target_ts, ts_max);#endif *ts_ret= ts; return pos;}static int av_seek_frame_byte(AVFormatContext *s, int stream_index, int64_t pos, int flags){ int64_t pos_min, pos_max;#if 0 AVStream *st; if (stream_index < 0) return -1; st= s->streams[stream_index];#endif pos_min = s->data_offset; pos_max = url_fsize(s->pb) - 1; if (pos < pos_min) pos= pos_min; else if(pos > pos_max) pos= pos_max; url_fseek(s->pb, pos, SEEK_SET);#if 0 av_update_cur_dts(s, st, ts);#endif return 0;}static int av_seek_frame_generic(AVFormatContext *s, int stream_index, int64_t timestamp, int flags){ int index; AVStream *st; AVIndexEntry *ie; st = s->streams[stream_index]; index = av_index_search_timestamp(st, timestamp, flags); if(index < 0 || index==st->nb_index_entries-1){ int i; AVPacket pkt; if(st->nb_index_entries){ assert(st->index_entries); ie= &st->index_entries[st->nb_index_entries-1]; url_fseek(s->pb, ie->pos, SEEK_SET); av_update_cur_dts(s, st, ie->timestamp); }else url_fseek(s->pb, 0, SEEK_SET); for(i=0;; i++) { int ret = av_read_frame(s, &pkt); if(ret<0) break; av_free_packet(&pkt); if(stream_index == pkt.stream_index){ if((pkt.flags & PKT_FLAG_KEY) && pkt.dts > timestamp) break; } } index = av_index_search_timestamp(st, timestamp, flags); } if (index < 0) return -1; av_read_frame_flush(s); if (s->iformat->read_seek){ if(s->iformat->read_seek(s, stream_index, timestamp, flags) >= 0) return 0; } ie = &st->index_entries[index]; url_fseek(s->pb, ie->pos, SEEK_SET); av_update_cur_dts(s, st, ie->timestamp); return 0;}int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags){ int ret; AVStream *st; av_read_frame_flush(s); if(flags & AVSEEK_FLAG_BYTE) return av_seek_frame_byte(s, stream_index, timestamp, flags); if(stream_index < 0){ stream_index= av_find_default_stream_index(s); if(stream_index < 0) return -1; st= s->streams[stream_index]; /* timestamp for default must be expressed in AV_TIME_BASE units */ timestamp = av_rescale(timestamp, st->time_base.den, AV_TIME_BASE * (int64_t)st->time_base.num); } st= s->streams[stream_index]; /* first, we try the format specific seek */ if (s->iformat->read_seek) ret = s->iformat->read_seek(s, stream_index, timestamp, flags); else ret = -1; if (ret >= 0) { return 0; } if(s->iformat->read_timestamp) return av_seek_frame_binary(s, stream_index, timestamp, flags); else return av_seek_frame_generic(s, stream_index, timestamp, flags);}/*******************************************************//** * Returns TRUE if the stream has accurate duration in any stream. * * @return TRUE if the stream has accurate duration for at least one component. */static int av_has_duration(AVFormatContext *ic){ int i; AVStream *st; for(i = 0;i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->duration != AV_NOPTS_VALUE) return 1; } return 0;}/** * Estimate the stream timings from the one of each components. * * Also computes the global bitrate if possible. */static void av_update_stream_timings(AVFormatContext *ic){ int64_t start_time, start_time1, end_time, end_time1; int64_t duration, duration1; int i; AVStream *st; start_time = INT64_MAX; end_time = INT64_MIN; duration = INT64_MIN; for(i = 0;i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->start_time != AV_NOPTS_VALUE && st->time_base.den) { start_time1= av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q); if (start_time1 < start_time) start_time = start_time1; if (st->duration != AV_NOPTS_VALUE) { end_time1 = start_time1 + av_rescale_q(st->duration, st->time_base, AV_TIME_BASE_Q); if (end_time1 > end_time) end_time = end_time1; } } if (st->duration != AV_NOPTS_VALUE) { duration1 = av_rescale_q(st->duration, st->time_base, AV_TIME_BASE_Q); if (duration1 > duration) duration = duration1; } } if (start_time != INT64_MAX) { ic->start_time = start_time; if (end_time != INT64_MIN) { if (end_time - start_time > duration) duration = end_time - start_time; } } if (duration != INT64_MIN) { ic->duration = duration; if (ic->file_size > 0) { /* compute the bitrate */ 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) { if(ic->start_time != AV_NOPTS_VALUE) st->start_time = av_rescale_q(ic->start_time, AV_TIME_BASE_Q, st->time_base); if(ic->duration != AV_NOPTS_VALUE) st->duration = av_rescale_q(ic->duration, AV_TIME_BASE_Q, st->time_base); } }}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) { for(i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; duration= av_rescale(8*filesize, st->time_base.den, ic->bit_rate*(int64_t)st->time_base.num); if (st->duration == AV_NOPTS_VALUE) st->duration = duration; } } }}#define DURATION_MAX_READ_SIZE 250000/* only usable for MPEG-PS streams */static void av_estimate_timings_from_pts(AVFormatContext *ic, offset_t old_offset){ AVPacket pkt1, *pkt = &pkt1; AVStream *st; int read_size, i, ret; int64_t end_time; int64_t filesize, offset, duration; /* free previous packet */ if (ic->cur_st && ic->cur_st->parser) av_free_packet(&ic->cur_pkt); ic->cur_st = NULL; /* flush packet queue */ flush_packet_queue(ic); for(i=0;i<ic->nb_streams;i++) { st = ic->streams[i]; if (st->parser) { av_parser_close(st->parser); st->parser= NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -