我怎样才能寻求到帧第X与ffmpeg的? [英] How can I seek to frame No. X with ffmpeg?

查看:520
本文介绍了我怎样才能寻求到帧第X与ffmpeg的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在写的视频编辑的,我需要寻求准确的框架,知道的帧编号

计算器上的其他职位跟我说的ffmpeg可以寻求,这是不播放的问题,但对于视频编辑的一个大问题后,给我几个破碎的帧。

和我需要征求按帧编号的按时间,转换为帧数时将变得不准确。

我读过dranger的TUTS(现在已经过时),以及结了:

 函数av_seek_frame(fmt_ctx,video_stream_id,框架,AVSEEK_FLAG_ANY);

它总是设法帧否。 0 ,始终返回0 ,这意味着成功。
然后我试图读取Blender的源$ C ​​$ c和发现它非常复杂的(也许我应该实现一个图像缓冲区?)。

那么,有没有什么简单的方法来寻求一个帧像只是一个简单的电话寻求(背景下,frame_number)(同​​时获得一个完整的框架,而不是一个破一)?或者,有没有简化了这个的轻量级库?

编辑:
由于 praks411 后,我找到了解决办法:

 无效AV_seek(AV * AV,为size_t帧)
{
    INT frame_delta =架 - AV-GT&; frame_id;
    如果(frame_delta℃,|| frame_delta→5)
        函数av_seek_frame(AV-GT&; fmt_ctx,AV-GT&; video_stream_id,
                框架,AVSEEK_FLAG_BACKWARD);
    而(AV-GT&;!frame_id =帧)
        AV_read_frame(AV);
}无效AV_read_frame(AV * AV)
{
    AVPacket包;
    INT frame_done;    而(av_read_frame(AV-> fmt_ctx,&放大器;分组)GT; = 0){
        如果(packet.stream_index == AV-GT&; video_stream_id){
            AV codec_de code_video2(AV-GT&; codec_ctx,AV-GT&;框架,和放大器; frame_done,&安培;包);
            如果(frame_done){
                ...
                AV-GT&; frame_id = packet.dts;
                av_free_packet(安培;包);
                返回;
            }
        }
        av_free_packet(安培;包);
    }
}


解决方案

函数av_seek_frame 只会基于时间戳的关键帧求。因为它寻求的关键帧,你可能不会得到你想要的。因此,建议寻求最接近的关键帧,然后读一帧一帧UTIL到达所需的帧。

不过,如果你正在处理固定FPS值,那么你可以很容易地映射时间戳帧索引。

求你需要,如果你指定流,你的时间转换为 AVStream.time_base 单位之前。阅读函数av_seek_frame 的ffmpeg的文档中的 avformat.h

例如,如果你想寻求 1.23 剪辑秒:

 双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);
 如果(函数av_seek_frame(m_informat,m_in_vid_strm_idx,seek_ts,FLGS)℃的)
 {
     PRINT_MSG(无法寻求视频)
 }

I'm writing a video editor, and I need to seek to exact frame, knowing the frame number.

Other posts on stackoverflow told me that ffmpeg may give me a few broken frames after seeking, which is not a problem for playback but a big problem for video editors.

And I need to seek by frame number, not by time, which will become inaccurate when converted to frame number.

I've read dranger's tuts (which is outdated now), and end up with:

av_seek_frame(fmt_ctx, video_stream_id, frame, AVSEEK_FLAG_ANY);

It always seek to frame No. 0, and always return 0 which means success. Then I tried to read Blender's source code and found it really complex(maybe I should implement an image buffer?).

So, is there any simple way to seek to a frame with just a simple call like seek(context, frame_number)(while getting a full frame, not a broken one)? Or, is there any lightweight library that simplifies this?

EDIT: Thanks to praks411,I found the solution:

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);
    }
}

解决方案

av_seek_frame will only seek based on timestamp to the key-frame. Since it seeks to the keyframe, you may not get what you want. Hence it is recommended to seek to nearest keyframe and then read frame by frame util you reach the desired frame.

However, if you are dealing with fixed FPS value, then you can easily map timestamp to frame index.

Before seeking you will need to convert your time to AVStream.time_base units if you have specified stream. Read ffmpeg documentation of av_seek_frame in avformat.h.

For example, if you want to seek to 1.23 seconds of clip:

 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 ")
 }

这篇关于我怎样才能寻求到帧第X与ffmpeg的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆