FFmpeg代码实现抽取音频、视频数据

这篇具有很好参考价值的文章主要介绍了FFmpeg代码实现抽取音频、视频数据。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

今天开始撸代码,首先使用FFmpeg的API抽取一个MP4文件的音频数据。

IDE

应该是第一次在Mac上做C/C++开发,纠结过后选择使用CLion 开发。CLion是 JetBrains下专门用来开发C/C++的IDE,已经用习惯了Android studio和IntelliJ IDEA ,所以CLion用起来还是很顺手的。

在新建一个C项目后,需要把FFmpeg的库导入才能正常运行。我们修改项目的CMakeLists.txt文件。

ffmpeg读取mp4文件,ffmpeg

抽取音频AAC数据

其实我们要做的主要就是一个文件的操作,把一个文件打开,从里面拿出它的一部分数据,再把这部分数据放到另一个文件中保存。

定义参数

#include <stdio.h>
#include <libavutil/log.h>
#include <libavformat/avformat.h>

//上下文
AVFormatContext *fmt_ctx = NULL;
AVFormatContext *ofmt_ctx = NULL;

//支持各种各样的输出文件格式,MP4,FLV,3GP等等
AVOutputFormat *output_fmt = NULL;

//输入流
AVStream *in_stream = NULL;

//输出流
AVStream *out_stream = NULL;

//存储压缩数据
AVPacket packet;

//要拷贝的流
int audio_stream_index = -1;

1.打开输入文件,提取参数

//打开输入文件,关于输入文件的所有就保存到fmt_ctx中了
err_code = avformat_open_input(&fmt_ctx, src_fileName, NULL, NULL);

if (err_code < 0) {
    av_log(NULL, AV_LOG_ERROR, "cant open file:%s\n", av_err2str(err_code));
    return -1;
}

if(fmt_ctx->nb_streams<2){
      //流数小于2,说明这个文件音频、视频流这两条都不能保证,输入文件有错误 
      av_log(NULL, AV_LOG_ERROR, "输入文件错误,流不足2条\n");
      exit(1);
 }

 //拿到文件中音频流
 in_stream = fmt_ctx->streams[1];
 //参数信息
 AVCodecParameters *in_codecpar = in_stream->codecpar;

//找到最好的音频流
audio_stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
    if(audio_stream_index < 0){
        av_log(NULL, AV_LOG_DEBUG, "寻找最好音频流失败,请检查输入文件!\n");
        return AVERROR(EINVAL);
}

2.准备输出文件,输出流

// 输出上下文
ofmt_ctx = avformat_alloc_context();

//根据目标文件名生成最适合的输出容器
output_fmt = av_guess_format(NULL,dst_fileName,NULL);
if(!output_fmt){
    av_log(NULL, AV_LOG_DEBUG, "根据目标生成输出容器失败!\n");
    exit(1);
}

ofmt_ctx->oformat = output_fmt;

//新建输出流
 out_stream = avformat_new_stream(ofmt_ctx, NULL);
 if(!out_stream){
      av_log(NULL, AV_LOG_DEBUG, "创建输出流失败!\n");
      exit(1);
 }

3. 数据拷贝

3.1 参数信息

// 将参数信息拷贝到输出流中,我们只是抽取音频流,并不做音频处理,所以这里只是Copy
if((err_code = avcodec_parameters_copy(out_stream->codecpar, in_codecpar)) < 0 ){
    av_strerror(err_code, errors, ERROR_STR_SIZE);
    av_log(NULL, AV_LOG_ERROR,"拷贝编码参数失败!, %d(%s)\n",
           err_code, errors);
}

3.2 初始化AVIOContext

//初始化AVIOContext,文件操作由它完成
if((err_code = avio_open(&ofmt_ctx->pb, dst_fileName, AVIO_FLAG_WRITE)) < 0) {
    av_strerror(err_code, errors, 1024);
    av_log(NULL, AV_LOG_DEBUG, "Could not open file %s, %d(%s)\n",
           dst_fileName,
           err_code,
           errors);
    exit(1);
}

3.3 开始拷贝

//初始化 AVPacket, 我们从文件中读出的数据会暂存在其中
av_init_packet(&packet);
packet.data = NULL;
packet.size = 0;

// 写头部信息
if (avformat_write_header(ofmt_ctx, NULL) < 0) {
    av_log(NULL, AV_LOG_DEBUG, "Error occurred when opening output file");
    exit(1);
}


//每读出一帧数据
while(av_read_frame(fmt_ctx, &packet) >=0 ){
    if(packet.stream_index == audio_stream_index){
        //时间基计算,音频pts和dts一致
        packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, (AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
        packet.dts = packet.pts;
        packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base);
        packet.pos = -1;
        packet.stream_index = 0;
        //将包写到输出媒体文件
        av_interleaved_write_frame(ofmt_ctx, &packet);
        //减少引用计数,避免内存泄漏
        av_packet_unref(&packet);
    }
}

//写尾部信息
av_write_trailer(ofmt_ctx);

//最后别忘了释放内存
avformat_close_input(&fmt_ctx);
avio_close(ofmt_ctx->pb);

执行

./MyC /Users/david/Desktop/1080p.mov /Users/david/Desktop/test.aac

抽取视频数据

抽取视频信息并保存在文件中的流程甚至代码和上面抽取音频基本一致。

//拿到文件中音频流 或者 视频流,所有流都在streams数组中
 in_stream = fmt_ctx->streams[1];

//找到最好的视频流
video_stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);

packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base, (AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));

基本上就是一些参数的改变,所有流程和代码保持不变,就可以把一个音视频文件中的视频数据抽取出来了,mp4、mov等格式随便,就是这么简单。。。

更新

====== 贴出完整代码,并对代码中的一些细节做出优化========

#include <stdio.h>
#include <libavutil/log.h>
#include <libavformat/avio.h>
#include <libavformat/avformat.h>

#define ERROR_STR_SIZE 1024

int main(int argc, char *argv[]) {
    int err_code;
    char errors[1024];

    char *src_filename = NULL;
    char *dst_filename = NULL;

    int audio_stream_index;

    //上下文
    AVFormatContext *fmt_ctx = NULL;
    AVFormatContext *ofmt_ctx = NULL;

    //支持各种各样的输出文件格式,MP4,FLV,3GP等等
    AVOutputFormat *output_fmt = NULL;

    AVStream *in_stream = NULL;
    AVStream *out_stream = NULL;

    AVPacket pkt;

    av_log_set_level(AV_LOG_DEBUG);

    if (argc < 3) {
        av_log(NULL, AV_LOG_DEBUG, "argc < 3!\n");
        return -1;
    }

    src_filename = argv[1];
    dst_filename = argv[2];

    if (src_filename == NULL || dst_filename == NULL) {
        av_log(NULL, AV_LOG_DEBUG, "src or dts file is null!\n");
        return -1;
    }


    if ((err_code = avformat_open_input(&fmt_ctx, src_filename, NULL, NULL)) < 0) {
        av_strerror(err_code, errors, 1024);
        av_log(NULL, AV_LOG_DEBUG, "打开输入文件失败: %s, %d(%s)\n",
               src_filename,
               err_code,
               errors);
        return -1;
    }

    if ((err_code = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
        av_strerror(err_code, errors, 1024);
        av_log(NULL, AV_LOG_DEBUG, "failed to find stream info: %s, %d(%s)\n",
               src_filename,
               err_code,
               errors);
        return -1;
    }

    av_dump_format(fmt_ctx, 0, src_filename, 0);

    if (fmt_ctx->nb_streams < 2) {
        //流数小于2,说明这个文件音频、视频流这两条都不能保证,输入文件有错误
        av_log(NULL, AV_LOG_ERROR, "输入文件错误,流不足2条\n");
        exit(1);
    }

    //拿到文件中音频流
    /**只需要修改这里AVMEDIA_TYPE_VIDEO参数**/
    audio_stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO /*AVMEDIA_TYPE_VIDEO*/, -1, -1, NULL, 0);
    if (audio_stream_index < 0) {
        av_log(NULL, AV_LOG_DEBUG, " 获取音频流失败%s,%s\n",
               av_get_media_type_string(AVMEDIA_TYPE_AUDIO),
               src_filename);
        return AVERROR(EINVAL);
    }

    in_stream = fmt_ctx->streams[audio_stream_index];
    //参数信息
    AVCodecParameters *in_codecpar = in_stream->codecpar;


    // 输出上下文
    ofmt_ctx = avformat_alloc_context();

    //根据目标文件名生成最适合的输出容器
    output_fmt = av_guess_format(NULL, dst_filename, NULL);
    if (!output_fmt) {
        av_log(NULL, AV_LOG_DEBUG, "根据目标生成输出容器失败!\n");
        exit(1);
    }

    ofmt_ctx->oformat = output_fmt;

    //新建输出流
    out_stream = avformat_new_stream(ofmt_ctx, NULL);
    if (!out_stream) {
        av_log(NULL, AV_LOG_DEBUG, "创建输出流失败!\n");
        exit(1);
    }

    // 将参数信息拷贝到输出流中,我们只是抽取音频流,并不做音频处理,所以这里只是Copy
    if ((err_code = avcodec_parameters_copy(out_stream->codecpar, in_codecpar)) < 0) {
        av_strerror(err_code, errors, ERROR_STR_SIZE);
        av_log(NULL, AV_LOG_ERROR,
               "拷贝编码参数失败!, %d(%s)\n",
               err_code, errors);
    }

    out_stream->codecpar->codec_tag = 0;

    //初始化AVIOContext,文件操作由它完成
    if ((err_code = avio_open(&ofmt_ctx->pb, dst_filename, AVIO_FLAG_WRITE)) < 0) {
        av_strerror(err_code, errors, 1024);
        av_log(NULL, AV_LOG_DEBUG, "文件打开失败 %s, %d(%s)\n",
               dst_filename,
               err_code,
               errors);
        exit(1);
    }



    av_dump_format(ofmt_ctx, 0, dst_filename, 1);


    //初始化 AVPacket, 我们从文件中读出的数据会暂存在其中
    av_init_packet(&pkt);
    pkt.data = NULL;
    pkt.size = 0;


    // 写头部信息
    if (avformat_write_header(ofmt_ctx, NULL) < 0) {
        av_log(NULL, AV_LOG_DEBUG, "写入头部信息失败!");
        exit(1);
    }

    //每读出一帧数据
    while (av_read_frame(fmt_ctx, &pkt) >= 0) {
        if (pkt.stream_index == audio_stream_index) {
            pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base,
                                       (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
            pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base,
                                       (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;
            pkt.stream_index = 0;
            //将包写到输出媒体文件
            av_interleaved_write_frame(ofmt_ctx, &pkt);
            //减少引用计数,避免内存泄漏
            av_packet_unref(&pkt);
        }
    }

    //写尾部信息
    av_write_trailer(ofmt_ctx);

    //最后别忘了释放内存
    avformat_close_input(&fmt_ctx);
    avio_close(ofmt_ctx->pb);

    return 0;
}

./MyC /Users/david/Desktop/1080p.mov /Users/david/Desktop/test.aac

只需要修改av_find_best_stream中的参数,执行以下命令就可以将视频流提取,成为单独的视频文件

./MyC /Users/david/Desktop/1080p.mov /Users/david/Desktop/test1.mp4

./MyC /Users/david/Desktop/1080p.mov /Users/david/Desktop/test2.mov

原文 FFmpeg代码实现抽取音频、视频数据 - 掘金 文章来源地址https://www.toymoban.com/news/detail-721824.html

到了这里,关于FFmpeg代码实现抽取音频、视频数据的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • qt+ffmpeg 实现音视频播放(二)之音频播放

    通过  avformat_open_input () 打开媒体文件并分配和初始化  AVFormatContext   结构体。 函数原型如下: int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options); 参数说明: - `ps`:指向 `AVFormatContext` 结构体指针的指针,用于存储打开的媒体文件的信息。

    2024年04月22日
    浏览(34)
  • OpenAI Whisper + FFmpeg + TTS:动态实现跨语言视频音频翻译

    本文作者系360奇舞团前端开发工程师 本文介绍了如何结合 OpenAI Whisper、FFmpeg 和 TTS(Text-to-Speech)技术,以实现将视频翻译为其他语言并更换声音的过程。我们将探讨如何使用 OpenAI Whisper 进行语音识别和翻译,然后使用 FFmpeg 提取视频音轨和处理视频,最后使用 TTS 技术生成新

    2024年02月09日
    浏览(37)
  • 利用FFmpeg实现录屏、直播推流、音频视频格式转换、剪裁等功能

    一、FFmpeg简介。 二、FFmpeg常用参数及命令。 三、FFmpeg在Unity 3D中的使用。 1、FFmpeg 录屏。 2、FFmpeg 推流。 3、FFmpeg 其他功能简述。 对于FFmpeg,其官网上是这样介绍的: FFmpeg is the leading multimedia framework, able to decode, encode, transcode, mux, demux, stream, filter and play pretty much anything th

    2024年02月09日
    浏览(41)
  • 使用FFMPEG库封装264视频和acc音频数据到MP4文件中

    ffmepeg 4.4 一段H264的视频文件 一段acc格式的音频文件 1.使用avformat_open_input分别打开视频和音频文件,初始化其AVFormatContext,使用avformat_find_stream_info获取编码器基本信息 2.使用avformat_alloc_output_context2初始化输出的AVFormatContext结构 3.使用函数avformat_new_stream给输出的AVFormatContext结

    2024年02月11日
    浏览(32)
  • ffmpeg视频音频命令

    视频音频合并,以视频时间为主,音频短了循环 方法1:混音,视频权重0,volume调节音量,aloop无限循环,duration:first为第一个素材的长度 ffmpeg -i video.mp4 -i audio.mp3 -filter_complex \\\"[1:a]volume=0.5[a1];[a1]aloop=loop=-1:size=2e+09[a2];[0:a][a2]amix=inputs=2:duration=first:weights=\\\'0 1\\\'[a]\\\" -map 0:v -map \\\"[a]\\\"

    2024年02月13日
    浏览(23)
  • FFmpeg从视频中提取音频

    参考博客 ffmpeg Documentation FFmpeg最全教程 FFmpeg 提取视频的音频 FFMPEG 提取音频 ffmpeg 给音频添加封面,ffmpeg对音视频metadata相关操作 查看 使用 FFprobe ffprobe 是一个多媒体流分析工具。它从多媒体流中收集信息,并且以人类和机器可读的形式打印出来。它可以用来检测多媒体流的

    2023年04月08日
    浏览(38)
  • 利用FFmpeg合并音频和视频

    一、FFmpeg 多个音频合并的2种方法 多个mp3文件合并成一个mp3文件 一种方法是连接到一起 ffmpeg64.exe -i \\\"concat:123.mp3|124.mp3\\\" -acodec copy output.mp3 解释:-i代表输入参数     contact:123.mp3|124.mp3代表着需要连接到一起的音频文件                  -acodec copy  output.mp3 重新编码并复制到

    2024年04月10日
    浏览(32)
  • Vue 3 + ffmpeg + wasm 实现前端视频剪辑、音频剪辑、音波展示、视频抽帧、gif抽帧、帧播放器、字幕、贴图、时间轴、素材轨道

    预览 www.bilibili.com/video/BV1YT411Y7YJ 技术栈: 💪 Vue 3、Vue-Router 4、Vite、pnpm、esbuild、TypeScript ☀️ Pinia 状态管理 🌪 Tailwind 原子css集成 💥 ffmpeg、wasm 底层音视频处理集成 功能 多轨道时间轴,支持帧缩放,时间缩放 支持多种类型轨道的添加删除 多功能轨道调节,支持音视频轨

    2024年02月11日
    浏览(33)
  • 【FFmpeg】ffmpeg 命令行参数 ⑧ ( 使用 ffmpeg 转换封装格式 | 音视频编解码器参数设置 | 视频 帧率 / 码率 / 分辨率 设置 | 音频 码率 / 采样率 设置 )

    音视频 文件 从 采样 - 处理 - 得到原始数据帧队列 - 音视频编码 - 音视频包队列 - 格式封装 的过程如下 : 封装格式 参考 【音视频原理】音视频 “ 采样 - 编码 - 封装 过程 “ 和 “ 解封装 - 解码 - 播放 过程 “ 分析 ( 视频采集处理流程 | 音频采集处理流程 | 音视频文件解封装

    2024年04月17日
    浏览(61)
  • 使用ffmpeg调整视频中音频采样率及声道

    通过ffmpeg -i命令查看视频基本信息 -r fps每秒传输帧数,默认为25 -s 分辨率 -ar 设定采样率 -ac 设定声音的Channel数 -acodec 设定声音编解码器,未设定时则使用与输入流相同的编解码器 FFmpeg项目由 Fabrice Bellard在2000年创立。到目前为止,FFmpeg项目的开发者仍然与VLC、MPV、dav1d、x

    2024年01月23日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包