ffmpeg # How to seek in mp4/mkv/
2018-10-08 本文已影响102人
FlyingPenguin
调用堆栈
seek的秘密
s->iformat->read_seek
static int seek_frame_internal(AVFormatContext *s, int stream_index,
int64_t timestamp, int flags)
{
...
/* first, we try the format specific seek */
if (s->iformat->read_seek) {
ff_read_frame_flush(s);
ret = s->iformat->read_seek(s, stream_index, timestamp, flags);
} else
ret = -1;
if (ret >= 0)
return 0;
...
}
mp4
mkv
ff_seek_frame_binary
static int seek_frame_internal(AVFormatContext *s, int stream_index,
int64_t timestamp, int flags)
{
...
if (s->iformat->read_timestamp &&
!(s->iformat->flags & AVFMT_NOBINSEARCH)) {
ff_read_frame_flush(s);
return ff_seek_frame_binary(s, stream_index, timestamp, flags);
}
...
}
ts
seek_frame_generic
flv with keyframe list
static int seek_frame_generic(AVFormatContext *s, int stream_index,
int64_t timestamp, int flags)
{
int index;
int64_t ret;
AVStream *st;
AVIndexEntry *ie;
st = s->streams[stream_index];
index = av_index_search_timestamp(st, timestamp, flags); // 成功 找到目标关键帧
...
}
flv without keyframe list
static int seek_frame_generic(AVFormatContext *s, int stream_index,
int64_t timestamp, int flags)
{
int index;
int64_t ret;
AVStream *st;
AVIndexEntry *ie;
st = s->streams[stream_index];
index = av_index_search_timestamp(st, timestamp, flags); // 失败
...
// 逐帧读取
for (;;) {
int read_status;
do {
read_status = av_read_frame(s, &pkt); // 读取一帧
} while (read_status == AVERROR(EAGAIN));
if (read_status < 0)
break;
// 如果获取的dts大于目标timestamp
if (stream_index == pkt.stream_index && pkt.dts > timestamp) {
if (pkt.flags & AV_PKT_FLAG_KEY) { // 并且是关键帧
av_packet_unref(&pkt);
break;
}
if (nonkey++ > 1000 && st->codecpar->codec_id != AV_CODEC_ID_CDGRAPHICS) {
av_log(s, AV_LOG_ERROR,"seek_frame_generic failed as this stream seems to contain no keyframes after the target timestamp, %d non keyframes found\n", nonkey);
av_packet_unref(&pkt);
break;
}
}
av_packet_unref(&pkt);
}
index = av_index_search_timestamp(st, timestamp, flags); // 找到目标关键帧
}
注: ffmpeg的版本如下:
ffmpeg version N-92079-gab492f9322 Copyright (c) 2000-2018 the FFmpeg developers
built with Apple LLVM version 10.0.0 (clang-1000.11.45.2)
configuration: --pkg-config-flags=--static --disable-doc --enable-version3 --enable-debug=3 --enable-gpl --disable-optimizations --disable-stripping --disable-ffplay --disable-ffprobe --disable-decoder=vp9
libavutil 56. 19.101 / 56. 19.101
libavcodec 58. 31.101 / 58. 31.101
libavformat 58. 18.103 / 58. 18.103
libavdevice 58. 4.104 / 58. 4.104
libavfilter 7. 33.100 / 7. 33.100
libswscale 5. 2.100 / 5. 2.100
libswresample 3. 2.100 / 3. 2.100
libpostproc 55. 2.100 / 55. 2.100