私はビデオエディタを書いていますが、フレーム番号を知って、正確なフレームを探す必要があります。
Stackoverflowに関する他の投稿によると、ffmpegはシーク後にいくつかの壊れたフレームを表示する可能性があります。これは再生の問題ではありませんが、ビデオ編集者にとっては大きな問題です。
そして、私はフレーム番号で、notを時間で探す必要があります。これは、フレーム番号に変換すると不正確になります。
私はdrangerのtuts(今は時代遅れです)を読みました、そして結局:
_av_seek_frame(fmt_ctx, video_stream_id, frame, AVSEEK_FLAG_ANY);
_
常に_No. 0
_をフレーム化しようとし、常に_return 0
_をフレームに入れます。これは成功を意味します。次に、Blenderのソースコードを読み取ろうとしましたが、非常に複雑であることがわかりました(おそらく、画像バッファーを実装する必要がありますか?)。
それで、seek(context, frame_number)
のような単純な呼び出しでフレームを探す簡単な方法はありますか(壊れたフレームではなく、完全なフレームを取得している間)?または、これを単純化する軽量ライブラリはありますか?
EDIT:ありがとう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 。これは「フレームの正確なアクセスを容易にするFFmpegベースのソースライブラリ[...]」であり、移植可能です(少なくともWindowsとLinux間で)。
av_seek_frame
は、キーフレームへのタイムスタンプに基づいてのみシークします。キーフレームを探しているので、欲しいものが手に入らないかもしれません。したがって、最も近いキーフレームを探してから、目的のフレームに到達するまでフレームごとに読み取ることをお勧めします。
ただし、固定FPS値を扱っている場合は、タイムスタンプをフレームインデックスに簡単にマッピングできます。
ストリームを指定している場合は、シークする前に、時間をAVStream.time_base
単位に変換する必要があります。 av_seek_frame
のavformat.h
のffmpegドキュメントを読んでください。
たとえば、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 ")
}