ffmpeg音视频开发从入门到精通——ffmpeg 视频数据抽取

news2024/11/29 0:34:06

文章目录

  • FFmpeg视频处理工具使用总结
    • 环境配置
    • 主函数与参数处理
    • 打开输入文件
    • 获取流信息
    • 分配输出文件上下文
    • 猜测输出文件格式
    • 创建视频流并设置参数
    • 打开输出文件并写入头信息
    • 读取、转换并写入帧数据
    • 写入尾信息并释放资源
    • 运行程序
    • 注意事项
    • 源代码

FFmpeg视频处理工具使用总结

环境配置

在C++程序中使用FFmpeg之前,需要包含相应的头文件,并根据是否使用C++编译器,可能需要添加extern "C"块。


```cpp
#ifdef __cplusplus
extern "C" {
#endif
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/log.h>
#ifdef __cplusplus
}
#endif

主函数与参数处理

程序入口点是main函数,它处理命令行参数并设置日志级别。

int main(int argc, char *argv[]) {
    // 参数检查
    if (argc < 3) {
        av_log(nullptr, AV_LOG_ERROR, "Usage: %s <input file> <output file>\n", argv[0]);
        exit(-1);
    }
    // 输入输出文件路径
    char *src = argv[1];
    char *dst = argv[2];
    // 设置日志级别
    av_log_set_level(AV_LOG_DEBUG);
}

打开输入文件

使用avformat_open_input打开输入文件,并检查返回值。

int ret = avformat_open_input(&pFormatCtx, src, nullptr, nullptr);
if (ret < 0) {
    av_log(nullptr, AV_LOG_ERROR, "Could not open input file: %s\n", src);
    exit(-1);
}

获取流信息

调用av_find_best_stream找到最佳的视频流。

ret = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
if (ret < 0) {
    av_log(nullptr, AV_LOG_ERROR, "Failed to retrieve input stream information\n");
    goto _ERROR;
}

分配输出文件上下文

使用avformat_alloc_context分配输出文件的格式上下文。

oFormatCtx = avformat_alloc_context();
if (oFormatCtx == nullptr) {
    av_log(nullptr, AV_LOG_ERROR, "Failed to allocate output context\n");
    goto _ERROR;
}

猜测输出文件格式

使用av_guess_format猜测输出文件的格式。

outFmt = av_guess_format(nullptr, dst, nullptr);
if (outFmt == nullptr) {
    av_log(nullptr, AV_LOG_ERROR, "Failed to guess output format\n");
    goto _ERROR;
}
oFormatCtx->oformat = outFmt;

创建视频流并设置参数

为输出文件创建视频流,并复制输入视频流的参数。

outStream = avformat_new_stream(oFormatCtx, nullptr);
avcodec_parameters_copy(outStream->codecpar, pFormatCtx->streams[ret]->codecpar);
outStream->codecpar->codec_tag = 0;

打开输出文件并写入头信息

使用avio_open2打开输出文件,并使用avformat_write_header写入文件头信息。

ret = avio_open2(&oFormatCtx->pb, dst, AVIO_FLAG_WRITE, nullptr, nullptr);
if (ret < 0) {
    av_log(nullptr, AV_LOG_ERROR, "Failed to open output file: %s\n", dst);
    goto _ERROR;
}
ret = avformat_write_header(oFormatCtx, nullptr);
if (ret < 0) {
    av_log(nullptr, AV_LOG_ERROR, "Failed to write output file header\n");
    goto _ERROR;
}

读取、转换并写入帧数据

读取输入文件的视频帧,转换时间戳,并使用av_interleaved_write_frame写入输出文件。

while (av_read_frame(pFormatCtx, &pkt) >= 0) {
    if (pkt.stream_index == ret) {
        // 转换时间戳等
        pkt.pts = av_rescale_q_rnd(pkt.pts, inSteam->time_base, outStream->time_base, AV_ROUND_NEAR_INF);
        pkt.dts = av_rescale_q_rnd(pkt.dts, inSteam->time_base, outStream->time_base, AV_ROUND_NEAR_INF);
        pkt.duration = av_rescale_q(pkt.duration, inSteam->time_base, outStream->time_base);
        // 写入帧数据
        av_interleaved_write_frame(oFormatCtx, &pkt);
    }
    av_packet_unref(&pkt);
}

写入尾信息并释放资源

使用av_write_trailer写入文件尾信息,并释放所有资源。

av_write_trailer(oFormatCtx);

_ERROR:
// 清理资源
if (oFormatCtx && oFormatCtx->pb) {
    avio_close(oFormatCtx->pb);
    oFormatCtx->pb = nullptr;
}
if (oFormatCtx) {
    avformat_free_context(oFormatCtx);
    oFormatCtx = nullptr;
}
if (pFormatCtx) {
    avformat_free_context(pFormatCtx);
    pFormatCtx = nullptr;
}

运行程序

程序需要传入两个参数:输入文件路径和输出文件路径。例如:

./my_ffmpeg_tool input.mp4 output.mkv

确保替换为您的实际文件名和所需的输出格式。

注意事项

  • 确保FFmpeg开发库已正确安装且可链接。
  • 检查程序输出的错误信息以进行调试。
  • 程序可能需要适当的读取和写入权限。

源代码

  • cmake 源文件
cmake_minimum_required(VERSION 3.27)
project(FFmpeg_exercise)
set(CMAKE_CXX_STANDARD 14)

# 定义FFmpeg的安装路径变量
set(FFMPEG_INSTALL_DIR "/usr/local/ffmpeg")

# 将FFmpeg的头文件目录添加到包含路径
include_directories(${FFMPEG_INSTALL_DIR}/include)

# 定义FFmpeg库的基础名称(根据你的需要调整)
set(FFMPEG_LIBS "avcodec;avformat;avutil") # 用分号分隔库名

# 寻找并链接FFmpeg库
foreach(FFMPEG_LIB ${FFMPEG_LIBS})
    find_library(${FFMPEG_LIB}_LIBRARY NAMES ${FFMPEG_LIB}
            PATHS ${FFMPEG_INSTALL_DIR}/lib NO_DEFAULT_PATH)
    list(APPEND FFMPEG_LIBRARIES ${${FFMPEG_LIB}_LIBRARY})
endforeach()

add_executable(FFmpeg_exercise
        # main.cpp
       # extra_audic.cpp
        extra_video.cpp

)
# 链接FFmpeg库
target_link_libraries(FFmpeg_exercise ${FFMPEG_LIBRARIES})


  • cpp
//
// Created by 陈伟峰 on 2024/6/22.
//
#ifdef __cplusplus
extern "C" {
#endif
// 包含FFmpeg的头文件
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/log.h>
#ifdef __cplusplus

}
#endif
#include <iostream>

int main(int argc,char *argv[]){
    int ret {-1};
    int idx {-1};

    //1.处理一些参数
    char *src {nullptr};
    char *dst {nullptr};

    AVFormatContext *pFormatCtx {nullptr};
    AVFormatContext *oFormatCtx {nullptr};

    AVOutputFormat *outFmt {nullptr};
    AVStream *outStream {nullptr};
    AVStream *inSteam {nullptr};
    AVPacket pkt {nullptr};

    // 日志信息
    av_log_set_level(AV_LOG_DEBUG);
    if(argc<3){
        av_log(nullptr,AV_LOG_ERROR,"Usage:%s <input file> <output file>\n",argv[0]);
        exit(-1);
    }

    src = argv[1];
    dst = argv[2];

    // 2.打开多媒体输入文件
    ret = avformat_open_input(&pFormatCtx,src,nullptr,nullptr);
    if(ret<0){
        av_log(nullptr,AV_LOG_ERROR,"Could not open input file:%s\n",src);
        exit(-1);
    }

    // 3.获取多媒体文件信息
    ret = av_find_best_stream(pFormatCtx,AVMEDIA_TYPE_VIDEO,-1,-1,nullptr,0);
    if(ret<0){
        av_log(nullptr,AV_LOG_ERROR,"Failed to retrieve input stream information\n");
        goto _ERROR;
    }
    // 打开目的多媒体文件
    oFormatCtx = avformat_alloc_context();
    if(oFormatCtx==nullptr){
        av_log(nullptr,AV_LOG_ERROR,"Failed to allocate output context\n");
        goto _ERROR;
    }

    outFmt = av_guess_format(nullptr,dst,nullptr);
    if(outFmt==nullptr){
        av_log(nullptr,AV_LOG_ERROR,"Failed to guess output format\n");
        goto _ERROR;
    }
    oFormatCtx->oformat = outFmt;

    // 为目的文件,创建一个新的视频流
    outStream = avformat_new_stream(oFormatCtx,nullptr);
    // 设置视频参数
    inSteam = pFormatCtx->streams[idx];
    avcodec_parameters_copy(outStream->codecpar,pFormatCtx->streams[ret]->codecpar);
    outStream->codecpar->codec_tag = 0;

    // 绑定
    ret = avio_open2(&oFormatCtx->pb,dst,AVIO_FLAG_WRITE, nullptr, nullptr);
    if(ret<0){
        av_log(nullptr,AV_LOG_ERROR,"Failed to open output file:%s\n",dst);
        goto _ERROR;
    }
    // 写入头信息
    ret = avformat_write_header(oFormatCtx,nullptr);
    if(ret<0){
        av_log(nullptr,AV_LOG_ERROR,"Failed to write output file header\n");
        goto _ERROR;
    }

    // 写多媒体文件到目的文件
    ret = avformat_write_header(oFormatCtx,nullptr);
    if(ret<0){
        av_log(nullptr,AV_LOG_ERROR,"Failed to write output file header:%s\n", av_err2str(ret));
        goto _ERROR;
    }
    while(av_read_frame(pFormatCtx,&pkt)>=0) {
        if (pkt.stream_index == idx) {

            pkt.pts = av_rescale_q_rnd(pkt.pts, inSteam->time_base, outStream->time_base,
                                       (AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
            pkt.dts = av_rescale_q_rnd(pkt.dts, inSteam->time_base, outStream->time_base,
                                       (AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
            pkt.duration = av_rescale_q(pkt.duration, inSteam->time_base, outStream->time_base);
            pkt.stream_index = 0;
            pkt.pos = -1;
            av_interleaved_write_frame(oFormatCtx, &pkt);
        }
        av_packet_unref(&pkt);
    }
    // 写入尾信息
    av_write_trailer(oFormatCtx);

_ERROR:

    if(oFormatCtx->pb){
        avio_close(oFormatCtx->pb);
        oFormatCtx->pb = nullptr;
    }
    if(oFormatCtx){
        avformat_free_context(oFormatCtx);
        oFormatCtx = nullptr;
    }
    if(pFormatCtx){
        avformat_free_context(pFormatCtx);
        pFormatCtx = nullptr;
    }
    return 0;
}

  • 执行
./main demo.mp4 demo2.h264
  • 运行
ffplay demo2.h264

image-20240622143747704

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1851202.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何获取文件对应的路径

有时我们会把脚本文件复制到其他的路径或者电脑文件夹下&#xff0c;如果采用绝对路径的话&#xff0c;会发生找不到改文件&#xff0c;程序就会报错。那么我们如何避免这个问题呢&#xff1f;我们可以采用相对路径的方法。 可以看到&#xff0c;系统的当前路径"D:\python…

什么是距离选通型水下三维激光扫描仪?(下)

距离选通激光水下成像的发展 距离选通激光成像技术始于上世纪60年代&#xff0c;受制于高性能脉冲激光器和选通成像器件发展的制约&#xff0c;激光距离选通成像技术在随后的二十年发展缓慢&#xff0c;直到20世纪90年代&#xff0c;随着硬件技术的不断成熟&#xff0c;该技术…

VBA:demo大全

VBA常用小代码合集&#xff0c;总有一个是您用得上的~ (qq.com) 如何在各个分表创建返回总表的命令按钮&#xff1f; 今天再来给大家聊一下如何使用VBA代码&#xff0c;只需一键&#xff0c;即可在各个分表生成返回总表的按钮。 示例代码如下&#xff1a; Sub Mybutton()Dim …

房市复兴?新增贷款暴跌九成,房市接盘侠悠着点!

就在各方都认为在诸多利好政策支持下&#xff0c;房市正在复兴&#xff0c;一些分析数据似乎也显示出好转迹象&#xff0c;然而相比起这些数据&#xff0c;新增贷款或许更能证明房市的处境&#xff0c;比其他指标更具说服力。 5月份的数据显示&#xff0c;中国的新增贷款仅514亿…

Mamba: Linear-Time Sequence Modeling with Selective State Spaces论文笔记

文章目录 Mamba: Linear-Time Sequence Modeling with Selective State Spaces摘要引言 相关工作(SSMs)离散化计算线性时间不变性(LTI)结构和尺寸一般状态空间模型SSMs架构S4(补充)离散数据的连续化: 基于零阶保持技术做连续化并采样循环结构表示: 方便快速推理卷积结构表示: 方…

海报设计师的福音来了,微软联合清华北大提出Glyph-ByT5-v2,可支持多国语言图文海报生成,效果惊艳!

清华&北大&微软&利物浦大学联合提出Glyph-ByT5-v2这款工具支持多语言图文生成&#xff0c;包括英语、中文、日文、韩文、法文、德文、西班牙文、意大利文、葡萄牙文和俄文。 以下分别展示中、英、日、韩图文的视觉文本结果一起带大家感受一下。 相关链接 论文地址…

6G时代,即将来临!

日前&#xff0c;由未来移动通信论坛、紫金山实验室主办的2024全球6G技术大会在南京召开。本次大会以“创新预见6G未来”为主题&#xff0c;在大会开幕式上发布了协力推进全球6G统一标准行动的倡议和紫金山科技城加速培育以6G技术引领未来产业行动计划。 在我国已开展第五代移动…

苹果手机safari浏览器的userAgent显示为电脑的userAgent问题解决

目录 1.问题背景 2.userAgent 3.解决 1.问题背景 开发了一个H5&#xff0c;是通过生成二维码&#xff0c;扫描这个二维码后就跳到这个H5&#xff0c;所以需要判断一下扫描的设备是否为手机&#xff0c;然后由于业务逻辑还需要判断一下手机是Android、iOS还是iPad。一般前端…

Shell 编程之条件语句

Shell 编程之条件语句 一、条件测试操作test命令文件测试整数值比较字符串比较逻辑测试 二、if条件语句单分支 if 语句双分支 if 语句多分支 if 语句 三、case 分支语句case语句的结构case 语句应用示例 四、注意事项 在Shell编程中&#xff0c;条件语句是非常重要的一部分&…

Docker 下载与安装以及配置

安装yum工具 yum install -y yum-ulits配置yum源 阿里云源 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo安装Docker 17.03后为两个版本&#xff1a; 社区版&#xff08;Community Edition&#xff0c;缩写为 CE&#x…

获取时间戳是使用System.currentTimeMillis()还是使用new Date().getTime()(阿里开发规范)?

1.阿里规范 在阿里的Java开发手册中强制要求使用System.currentTimeMillis() 2.为什么(源码详解) new Date().getTime()它实际上也是调用的System.currentTimeMillis()&#xff0c;源码分析。 这个fastTime是它的成员变量&#xff0c;在new Date()的时候就被赋值了。 扩展一…

191.回溯算法:组合总和|||(力扣)

代码解决 class Solution { public:vector<vector<int>> result; // 存储所有符合条件的组合vector<int> res; // 当前组合// 回溯函数void backtracing(int k, int n, int index, int sum) {// 如果当前组合的长度等于k&#xff0c;且总和等于nif (res.si…

Django 模版变量

1&#xff0c;模版变量作用 模板变量使用“{{ 变量名 }}” 来表示模板变量前后可以有空格&#xff0c;模板变量名称&#xff0c;可以由数字&#xff0c;字母&#xff0c;下划线组成&#xff0c;不能包含空格模板变量还支持列表&#xff0c;字典&#xff0c;对象 2&#xff0c;…

odoo17 小变更4

odoo17 小变更4 1、代码中去除了访问私人地址权限,但翻译中均还有,怪不 model:res.groups,name:base.group_private_addresses msgid "Access to Private Addresses" msgstr "" 代码也查看了,的确没有了此权限组 --><record model="res.g…

mysql分析常用锁、动态监控、及优化思考

这里写自定义目录标题 1.未提交事物&#xff0c;阻塞DDL&#xff0c;继而阻塞所有同表的后续操作,查看未提交事务的进程2.存着正在进行的线程数据。3.根据processlist表中的id杀掉未释放的线程4.查看正在使用的表5.mysql为什么state会有waiting for handler commit6.什么情况导…

图扑助力铝型材挤压:数字孪生引领智慧管理

通过图扑数字孪生技术&#xff0c;为铝型材挤压车间提供实时监控和优化管理方案。高精度三维建模和数据可视化提升了生产效率和管理透明度&#xff0c;推动智能制造和资源优化配置。

HackTheBox-Linux基础

Linux 结构 历史 许多事件导致了第一个 Linux 内核的创建&#xff0c;并最终创建了 Linux 操作系统 &#xff08;OS&#xff09;&#xff0c;从 1970 年 Ken Thompson 和 Dennis Ritchie&#xff08;当时都在 AT&T 工作&#xff09;发布 Unix 操作系统开始。伯克利软件发行…

[SAP ABAP] 运算符与操作符

1.算数运算符 算术运算符描述加法-减法*乘法/除法MOD取余 示例1 输出结果: 输出结果: 2.比较运算符 比较运算符描述示例 等于 A B A EQ B <> 不等于 A <> B A NE B >大于 A > B A GT B <小于 A < B A LT B >大于或等于 A > B A GE B <小…

SCI一区TOP|双曲正弦余弦优化算法(SCHO)原理及实现【免费获取Matlab代码】

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献5.代码获取 1.背景 2023年&#xff0c;J Bai受到双曲正弦余弦函数启发&#xff0c;提出了双曲正弦余弦优化算法&#xff08;Sinh Cosh optimizer, SCHO&#xff09;。 2.算法原理 2.1算法思想 SCHO灵感来源…

springAI(一)

目录 一、spring AI 目的 二、spring AI 来源 三、sprig AI 是什么&#xff1f; 四、spring AI中的 概念 4.1、模型&#xff08;Models&#xff09; 4.2、提示&#xff08;Prompts&#xff09; 4.3、提示模板&#xff08;Prompt Templates&#xff09; 4.4、令 牌&#…