我正在写一个 视频编辑器 ,我需要在知道 帧号的情况 下寻求精确的 帧 。
关于stackoverflow的其他帖子告诉我,ffmpeg可能会在搜索后给我造成一些断帧,这对播放不是问题,但对视频编辑器来说是一个大问题。
我需要寻求 通过帧数 , 不 按时间,当转换为帧数,这将变得不准确。
我读过Dranger的书(现在已经过时了),最后得到了:
av_seek_frame(fmt_ctx, video_stream_id, frame, AVSEEK_FLAG_ANY);
它总是寻求框架No. 0,并且总是return 0意味着成功。然后,我尝试阅读Blender的源代码,发现它确实很复杂(也许我应该实现图像缓冲区?)。
No. 0
return 0
那么,有没有一种简单的方法可以通过一个简单的调用来查找一个框架seek(context, frame_number)(例如获得一个完整的框架,而不是损坏的框架)?或者,是否有任何简化此功能的轻量级库?
seek(context, frame_number)
编辑: 感谢 praks411 ,我找到了解决方案:
void AV_seek(AV * av, size_t frame) { int frame_delta = frame - av->frame_id; if (frame_delta < 0 || frame_delta > 5) av_seek_frame(av->fmt_ctx, av->video_stream_id, frame, AVSEEK_FLAG_BACKWARD); while (av->frame_id != frame) AV_read_frame(av); } void AV_read_frame(AV * av) { AVPacket packet; int frame_done; while (av_read_frame(av->fmt_ctx, &packet) >= 0) { if (packet.stream_index == av->video_stream_id) { avcodec_decode_video2(av->codec_ctx, av->frame, &frame_done, &packet); if (frame_done) { ... av->frame_id = packet.dts; av_free_packet(&packet); return; } } av_free_packet(&packet); } }
EDIT2: 事实证明有一个库:FFMS2。daccess-ods.un.org daccess-ods.un.org它是“基于FFmpeg的源库,可轻松准确地进行帧访问”,并且具有可移植性(至少在Windows和Linux上如此)。
av_seek_frame只会根据时间戳记关键帧。由于它寻求关键帧,因此您可能无法获得所需的内容。因此,建议先找到最接近的关键帧,然后逐帧读取,直到达到所需的帧。
av_seek_frame
但是,如果要处理固定的FPS值,则可以轻松地将时间戳映射到帧索引。
AVStream.time_base如果已指定流,在搜索之前,您需要将时间转换为单位。阅读av_seek_framein的ffmpeg文档avformat.h。
AVStream.time_base
avformat.h
例如,如果要寻找1.23剪辑的秒数:
1.23
double m_out_start_time = 1.23; int flgs = AVSEEK_FLAG_ANY; int seek_ts = (m_out_start_time*(m_in_vid_strm->time_base.den))/(m_in_vid_strm->time_base.num); if(av_seek_frame(m_informat, m_in_vid_strm_idx,seek_ts, flgs) < 0) { PRINT_MSG("Failed to seek Video ") }