4

我正在尝试使用 ffmpeg 以毫秒为单位搜索视频。我一直在尝试使用这个问题中的代码,它使用avformat_seek_file(我将它与 -1 一起用于流号和 AVSEEK_FLAG_ANY 标志)。

调用之后,我尝试读取下一帧,即:

if (av_read_frame(fmt_ctx, &pkt) >= 0)
{
    int ret = 0;

    if (pkt.stream_index == video_stream_idx) {
        /* decode video frame */
        ret = avcodec_decode_video2(video_dec_ctx, frame, got_frame, &pkt);
        if (ret < 0) {
            fprintf(stderr, "Error decoding video frame\n");
            return ret;
        }
//do something with frame
}

但是,frame->pts检索到的帧的时间总是保持紧接在查找之前读取的最后一帧之后的帧的时间。

编辑:尽管 frame->pts 形成完整的序列,但确实会发生搜索。出于某种奇怪的原因,我读到的下一帧是第一帧。事实上,在我运行之后:

   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*av_q2d(video_dec_ctx->time_base) * 1000 < tsms);

我读到的下一帧总是第一帧。

4

1 回答 1

1

最后,我能够使用以下代码进行搜索:

/*!
 * \brief ffmpeg_reader::seekMs seek to millisecond
 * \param tsms timestamp
 * \return success of seeking
 */
bool ffmpeg_reader::seekFrame(int s_frame)
{
    if (!isOk())
        return false;

   printf("\t avformat_seek_file to %d\n",s_frame);
   int flags = AVSEEK_FLAG_FRAME;
   if (s_frame < this->frame->pkt_dts)
   {
       flags |= AVSEEK_FLAG_BACKWARD;
   }

   if(av_seek_frame(fmt_ctx,video_stream_idx,s_frame,flags))
   {
       printf("\nFailed to seek for time %d",s_frame);
      return false;
   }

   avcodec_flush_buffers(video_dec_ctx);
   /*read frame without converting it*/
   int got_frame = 0;
   do
   if (av_read_frame(fmt_ctx, &pkt) == 0) {
       decode_packet(&got_frame, 0, false);
       av_free_packet(&pkt);
   }
   else
   {
       read_cache = true;
       pkt.data = NULL;
       pkt.size = 0;
       break;
   }
   while(!(got_frame && this->frame->pkt_dts >= s_frame));
   return true;
}

我自己没有想出它,但我(遗憾地)不记得功劳归于何处。

于 2014-05-26T09:01:39.027 回答