C 无法使用avformat_seek_文件获取第一帧

C 无法使用avformat_seek_文件获取第一帧,c,ffmpeg,libavformat,C,Ffmpeg,Libavformat,我想使用libav查找视频中的任意帧。更准确地说,使用函数avformat\u seek\u file,它显然在内部使用av\u seek\u frame 我想进行反向搜索(即,在我搜索的帧之前获得最接近的帧),这样我就可以向前搜索,直到准确地找到我想要的帧。为此,我使用以下函数: avformat_seek_file(..., ..., std::numeric_limits<boost::int64_t>::min(),

我想使用
libav
查找视频中的任意帧。更准确地说,使用函数
avformat\u seek\u file
,它显然在内部使用
av\u seek\u frame

我想进行反向搜索(即,在我搜索的帧之前获得最接近的帧),这样我就可以向前搜索,直到准确地找到我想要的帧。为此,我使用以下函数:

avformat_seek_file(..., ...,
                   std::numeric_limits<boost::int64_t>::min(),
                   target_pts,
                   target_pts,
                   ...);
avformat_seek_文件(。。。,
标准::数值限制::最小(),
目标,
目标,
...);
这意味着我不能容忍在我的目标点之后找到一个帧,但我对之前的任何帧都很满意

我正在用这个软件进行测试。使用480p H.264视频,我可以毫无问题地搜索任何
pts
。但是使用480p的OGG视频,我不能。实际上,我可以在
pts=73
之后查找任何帧,但不能在之前。搜索
pts=0
将视频设置为
pts=73

有人可能认为流实际上从
pts=73
开始,但这不是
.start\u time
返回的结果。此外,如果我只加载视频并按顺序读取帧,我可以毫无问题地获得前73帧。问题是,我无法使用
avformat\u seek\u file
返回到这些帧之一

最后一点:如果我使用标志
AVSEEK\u flag\u ANY
,那么它可以工作。但这可能会导致我只解码我想要的帧的一部分,这对我来说不是一个解决方案


有人能解释这种奇怪的行为吗?

这可能是个老问题,但这个答案适用于有同样问题的人

旧的
av_seek_frame
功能使用
AVSEEK_FLAG_BACKWARD
标志查找时间戳小于或等于目标时间戳的帧。默认情况下,此函数将查找时间戳等于或大于目标时间戳的帧。新的
avformat_seek_file
函数的文档表明此标志被忽略

如果标志包含AVSEEK_FLAG_ANY,则非关键帧将被视为 关键帧(并非所有解复用器都支持此功能)。如果旗帜 向后包含AVSEEK_标志_,将忽略它

正如我们在下面的源代码中看到的

2156     if (s->seek2any>0)
2157         flags |= AVSEEK_FLAG_ANY; 
2158     flags &= ~AVSEEK_FLAG_BACKWARD;
如您所述,
avformat\u seek\u file
函数返回到
av\u seek\u帧
,需要再次设置
AVSEEK\u向后
标志时,就会出现问题。仅当目标时间戳和最小时间戳之间的差值大于最大时间戳和目标时间戳之间的差值时,才会发生这种情况

 2187     // Fall back on old API if new is not implemented but old is.
 2188     // Note the old API has somewhat different semantics.
 2189     if (s->iformat->read_seek || 1) {
 2190         int dir = (ts - (uint64_t)min_ts > (uint64_t)max_ts - ts ? AVSEEK_FLAG_BACKWARD : 0);
 2191         int ret = av_seek_frame(s, stream_index, ts, flags | dir);
 2192         if (ret<0 && ts != min_ts && max_ts != ts) {
 2193             ret = av_seek_frame(s, stream_index, dir ? max_ts : min_ts, flags | dir);
 2194             if (ret >= 0)
 2195                 ret = av_seek_frame(s, stream_index, ts, flags | (dir^AVSEEK_FLAG_BACKWARD));
 2196         }
 2197         return ret;
 2198     }
2187//如果新API没有实现,但旧API已经实现,那么就使用旧API。
2188//注意,旧API的语义有些不同。
2189如果(s->iformat->read|u seek | 1){
2190 int dir=(ts-(uint64)最小值>(uint64)最大值ts-ts?AVSEEK标志向后:0);
2191 int ret=av seek帧(s、流索引、ts、标志dir);
2192如果(ret=0)
2195 ret=av_seek_帧(s、流索引、ts、标志|(dir^AVSEEK_FLAG_BACKWARD));
2196         }
2197返回ret;
2198     }

换句话说,
ts-min\u ts
溢出,因为您使用的是最小的int64值,这确保了永远不会设置
AVSEEK\u标志\u BACKWARD
标志。为什么不改用零呢?

你有没有找到解决方案/解释?我也有类似的问题。不幸的是,我没有。但这显然与许多人无关:6个月内有262次意见,0票。