惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Y
Y Combinator Blog
The GitHub Blog
The GitHub Blog
Vercel News
Vercel News
D
DataBreaches.Net
MongoDB | Blog
MongoDB | Blog
H
Help Net Security
小众软件
小众软件
美团技术团队
T
The Blog of Author Tim Ferriss
爱范儿
爱范儿
D
Docker
Martin Fowler
Martin Fowler
大猫的无限游戏
大猫的无限游戏
博客园 - 聂微东
Blog — PlanetScale
Blog — PlanetScale
H
Hackread – Cybersecurity News, Data Breaches, AI and More
罗磊的独立博客
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
V2EX
S
SegmentFault 最新的问题
云风的 BLOG
云风的 BLOG
B
Blog
雷峰网
雷峰网
The Cloudflare Blog

博客园 - 飘杨......

为ZLMediaKit在windows10编译srtp Windows10安装部署ZLMediaKit SurfaceView+EGL+OpenGL ES+ffmpeg播放视频并解决黑屏不显示画面的问题 SurfaceView+ANativeWindow+ffmpeg播放视频并解决花屏问题 SDL播放音频工具类封装 Qt QWidget中dropEvent(QDropEvent* e)拖拽放开不接收事件/不执行,且拖拽到目标后鼠标显示禁用符号 ffmpeg视频转码遇到H264黑屏问题 ffmpeg将视频流录制下来并保存到本地 ffmpeg解封装mp4并解码渲染(SDL2) Qt+ffmpeg+SDL硬件解码并渲染 ffmpeg+sdl播放H264/H265文件 FFmpeg实战:录制Windows屏幕并用FFmpeg压缩成H.264/H.265并保存 ffmpeg SwsContext像素格式转换BGRA转YUV420P H264/H265 NALU的nalu_unit_type解析 ffmpeg码率控制模式详解 ffmpeg-H264/H265常用编解码预设参数 Qt+FFmpeg+SDL 实现多路多格式原始视频播放工具:从像素处理到实时渲染 Qt+SDL 实战:多格式视频播放工具开发 —— 支持 RGBA/ARGB/RGB24/YUV420P 的完整实现 SDL将YUV视频渲染到Qt窗口播放
ffmpeg根据输入的参数截取视频
飘杨...... · 2025-05-28 · via 博客园 - 飘杨......

一、概述

  在日常的开发中,经常会遇到视频截取的需求,如:视频编辑。用ffmpeg的视频截取功能非常简单,只需要调用av_frame_seek函数即可。

但是需要理解av_frame_seek参数的含义,其主要功能是对音视频流的位置进行定位。

int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags); 

  功能:
  将文件指针定位到指定时间戳(timestamp)附近的关键帧,为后续的解码操作做准备。

  参数说明:

    • s:输入的媒体格式上下文(AVFormatContext)。
    • stream_index:目标流的索引(例如视频流或音频流)。若设为 -1,则会尝试在所有流中寻找时间戳最接近的关键帧。
    • timestamp:目标时间戳,其单位由 AVStream.time_base 决定。
    • flags:控制定位行为的标志,常用标志如下:
      • AVSEEK_FLAG_BACKWARD:向后查找最近的关键帧(适用于定位到指定时间之前)。
      • AVSEEK_FLAG_ANY:允许定位到非关键帧(可能会导致解码错误,需谨慎使用)。
      • AVSEEK_FLAG_FRAME:基于帧号而非时间戳进行定位(需配合 AVSEEK_FLAG_BYTE 使用)。

    返回值:
      成功时返回 0,失败时返回负错误码

二、代码示例

  • 计算开始pts和结束pts。计算公式为pts=要移动的时间/timebase。av_seek_frame是使用pts移动位置的
    if (begin_seconds > 0 && end_seconds > 0)
    {
        //计算开始的pts和结束的pts
       //pts = seconds/(num/den)=seconds*(den/num)
        if (vs && vs->time_base.num > 0)
        {
            double t = (double)vs->time_base.den / (double)vs->time_base.num;//den分母/num分子
            begin_pts = begin_seconds * t;
            end_pts = end_seconds * t;
        }
        if (as && as->time_base.num > 0)
        {
            begin_audio_pts = begin_seconds * ((double)as->time_base.den / (double)as->time_base.num);
        }
      
    }
  • 使用av_seek_frame集合pts进行音视频位置移动
      //移动到关键帧seek
        if (vs)
        {
            re = av_seek_frame(ic, vs->index, begin_pts, AVSEEK_FLAG_FRAME | AVSEEK_FLAG_BACKWARD);
            PrintError(re, "av_seek_frame");
        }
  • 截取到结尾
    if (begin_seconds > 0 && end_seconds > 0)
    {
        AVStream* in_stream = ic->streams[pkt.stream_index];
        AVStream* out_stream = nullptr;
        long long offset_pts = 0; //偏移pts,用于截断的开头pts运算
        if (vs && pkt.stream_index == vs->index)
        {
            qDebug() << "视频:";
            //超过设定的时间就退出
            if (pkt.pts > end_pts)
            {
                av_packet_unref(&pkt);
                break;
            }
            out_stream = oc->streams[0];
            offset_pts = begin_pts;
        }
        else if (as && pkt.stream_index == as->index)
        {
            qDebug() << "音频:";
            out_stream = oc->streams[1];
            offset_pts = begin_audio_pts;
        }
        //重新计算pts dts duration
        //`a * bq(输入basetime) / cq(输出basetime)`
        if (out_stream)
        {
            pkt.pts = av_rescale_q_rnd(pkt.pts - offset_pts, in_stream->time_base,
                out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)
            );
            pkt.dts = av_rescale_q_rnd(pkt.dts - offset_pts, in_stream->time_base,
                out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)
            );
            pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
        }
        pkt.pos = -1;
    }