puk*_*puk 3 ffmpeg seek media-player
问题:
omxplayer的源代码av_seek_frame()使用AVSEEK_FLAG_BACKWARD标志调用ffmpeg 方法.虽然不是100%肯定,但我相信这是寻求最接近的i-frame.相反,我想寻找确切的位置,所以我修改了源代码,使得该av_seek_frame()方法现在使用该AVSEEK_FLAG_ANY标志.现在,当电影加载时,我会得到一个灰色屏幕,通常持续1秒,在此期间我可以听到音频.我在多台计算机上尝试过这种方式(我实际上是同步它们,因此也是同时)因此它不是一个孤立的事件.我的猜测是,寻找非i帧在计算上更昂贵,导致初始灰色屏幕.
问题:如何使用ffmpeg,我可以指示音频等到视频准备好后再继续.
事实上,AVSEEK_FLAG_BACKWARD指示要找到最接近的关键帧具有更小的时间戳比你正在寻找的一个.
通过使用AVSEEK_FLAG_ANY,您将获得与您要求的时间戳完全对应的框架.但是这个帧可能不是关键帧,这意味着它不能被完全解码.这解释了您的"灰色屏幕",直到达到下一个关键帧.
因此,解决方案是使用和从此关键帧向后搜索AVSEEK_FLAG_BACKWARD下一帧(例如使用av_read_frame()),直到找到与您的时间戳相对应的帧.此时,您的帧将被完全解码,并且不再显示为"灰色屏幕".
注意:出于某种原因,当我正在寻找的帧是直接在此关键帧之前的帧时,看起来av_seek_frame()使用AVSEEK_FLAG_BACKWARD返回下一个关键帧.否则它返回前一个关键帧(这就是我想要的).我的解决方案是更改我给出的时间戳,av_seek_frame()以确保它将在我寻找的帧之前返回关键帧.
用一些代码完成 JonesV 答案:
void seekFrame(unsigned frameIndex)
{
// Seek is done on packet dts
int64_t target_dts_usecs = (int64_t)round(frameIndex
* (double)m_video_stream->r_frame_rate.den
/ m_video_stream->r_frame_rate.num * AV_TIME_BASE);
// Remove first dts: when non zero seek should be more accurate
auto first_dts_usecs = (int64_t)round(m_video_stream->first_dts
* (double)m_video_stream->time_base.num
/ m_video_stream->time_base.den * AV_TIME_BASE);
target_dts_usecs += first_dts_usecs;
int rv = av_seek_frame(
m_format_ctx, -1, target_dts_usecs, AVSEEK_FLAG_BACKWARD);
if (rv < 0)
throw exception("Failed to seek");
avcodec_flush_buffers(m_codec_ctx);
}
Run Code Online (Sandbox Code Playgroud)
AVPacket.dts然后您可以开始根据 计算的原始目标 dts 进行解码检查AVStream.time_base。一旦达到目标 dts,下一个解码帧就应该是所需的帧。