23

私はビデオエディタを書いています.フレーム番号を知って、正確なフレームを求める必要があります.

stackoverflow に関する他の投稿によると、ffmpeg を使用すると、シーク後にいくつかの壊れたフレームが表示される可能性があります。これは、再生の問題ではなく、ビデオ エディターにとって大きな問題です。

また、フレーム番号に変換すると不正確になる時間ではなく、フレーム番号でシークする必要があります。

私はdranger's tuts(現在は時代遅れです)を読みましたが、最終的には次のようになりました:

av_seek_frame(fmt_ctx, video_stream_id, frame, AVSEEK_FLAG_ANY);

それは常にNo. 0成功return 0を意味します。次に、Blender のソース コードを読み込もうとしたところ、非常に複雑であることがわかりました (画像バッファーを実装する必要があるのではないでしょうか?)。

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。これは「簡単にフレームに正確にアクセスできる FFmpeg ベースのソース ライブラリ [...]」であり、(少なくとも Windows と Linux 間で) 移植可能です。

4

1 に答える 1

11

av_seek_frameキーフレームへのタイムスタンプに基づいてのみシークします。キーフレームをシークするため、必要なものが得られない場合があります。したがって、最も近いキーフレームを探してから、目的のフレームに到達するまでフレームごとに読み取ることをお勧めします。

ただし、固定の FPS 値を扱っている場合は、タイムスタンプをフレーム インデックスに簡単にマッピングできます。

AVStream.time_baseストリームを指定した場合は、シークする前に時間を単位に変換する必要があります。の ffmpeg ドキュメントを参照av_seek_frameしてavformat.hください。

たとえば、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 ")
 }
于 2013-07-09T13:50:12.467 に答える