私はシークバーを持つ小さなビデオプレーヤーを作ろうとしています (もちろん、ffmpeg を使って)。そのためには、フレームやパケットからのデータを使用して、シーク スライダーで設定する必要があるビデオの現在の時間を取得する機能が必要です。
次のように動作するはずです。
my_time = get_cur_time()
seek(my_time + 10)
assert(my_time+10 == get_cur_time())
seek(my_time - 10)
assert(my_time-10 == get_cur_time())
私は、ffmpeg が正確なシークをサポートしていないことを理解しています。したがって、ここでの同等性は、「合理的にクローエを意味するもの」を意味します。
これまでに使用したコードは次のとおりです。
frame_time = frame->pts*av_q2d(video_dec_ctx->time_base) * 1000;
ここで、frame はAVFrame
、video_dec_ctx はAVCodecContext
です。
そして求めるために:
int fn = ffmpeg::av_rescale(tsms,fmt_ctx->streams[video_stream->index]->time_base.den,
fmt_ctx->streams[video_stream->index]->time_base.num);
int frame = fn/1000;
printf("\t avformat_seek_file to %d\n",frame);
int flags = AVSEEK_FLAG_FRAME;
if (frame < this->frame->pts)
flags |= AVSEEK_FLAG_BACKWARD;
if(ffmpeg::av_seek_frame(fmt_ctx,video_stream->index,frame,flags))
{
printf("\nFailed to seek for time %d",frame);
return false;
}
avcodec_flush_buffers(video_dec_ctx);
int got_frame = 0;
do
if (av_read_frame(fmt_ctx, &pkt) >= 0) {
decode_packet_ro(&got_frame, 0);
av_free_packet(&pkt);
}
else
{
read_cache = true;
pkt.data = NULL;
pkt.size = 0;
break;
}
while(!(got_frame && this->frame->pts >= frame));
コードはまずまずの順方向シークを実行しますが、逆方向シークの試行の後、2 番目のアサーションは失敗します。前の位置にシークした後、時間を取得する私の方法は、シークする前の位置よりも小さい位置を返しません。これにより、シーク スライダーが著しく正しく動作しなくなります。