音频重采样和音量调整ffmpeg滤镜(二十一)

前言

ffmpeg内置了很多滤镜库,都封装在AVFilter模块中,通过这个滤镜模块可以用来更加方便的处理音视频。比如视频分辨率压缩滤镜scale(用来对视频的分辨率进行缩放),视频翻转滤镜transpose(对视频进行上下左右的翻转);音频格式转换滤镜aformat(它实际上最终是调用avresample滤镜实现的),volume(用来调整音量大小)等等。

  • 关于ffmpeg的滤镜AVFilter源码及编译
    1、默认情况下libavfilter模块会编译如下文件:
    OBJS = allfilters.o
    audio.o
    avfilter.o
    avfiltergraph.o
    buffersink.o
    buffersrc.o
    drawutils.o
    fifo.o
    formats.o
    framepool.o
    framequeue.o
    graphdump.o
    graphparser.o
    transform.o
    video.o
    以上来自libavfilter/Makefile,所以就算编译ffmpeg时加入--disable-filters 也会将这些文件编译进去生成libavfilter库;
    如果要将整个libavfilter模块禁用掉,在根目录Makefile将如下语句注释掉即可:
    FFLIBS-$(CONFIG_AVFILTER) += avfilter

    2、如果要使用音频格式转换滤镜时需要添加如下选项:
    aformat滤镜用于音频格式(如采样率,采样格式,声道类型)的转换(相当于实现了SwrContext的功能),它内部最终调用的aresample滤镜,而aresample滤镜内部又是用libswresample模块
    的SwrContext实现的
    --enable-filter=aformat;--enable-filter=aresample
    3、如果要使用音频声音变化滤镜时需要添加如下选项:
    --enable-filter=volume
    4、分别对应的滤镜名称为
    ff_af_aformat;ff_af_aresample;ff_af_volume
    5、ffmpeg所有的滤镜在libavfilter/filter_list.c文件下

本文目的

通过aformat滤镜和volume滤镜实现音频格式转换,音量调整功能来学习滤镜的使用流程,其实不管是音频还是视频滤镜使用流程都是一样的。

ffmpeg的音频滤镜是通过滤镜管道来进行管理的,滤镜管道可以将各个滤镜连接到一起,形成一个处理流水线,流程如下:
srcfilter-->volumefilter->aformat....->otherfilter->sinkfilter

  • 1、一个音频滤镜管道必须要有一个输入滤镜(abuffer,用于接收要处理的数据),一个输出滤镜(abuffersink,用于提供处理好的数据)
  • 2、每一个滤镜(AVFilter)都有一个滤镜上下文AVFilterContext(也称为滤镜实例)与之对应,滤镜的参数通过这个上下文来设置
  • 3、输入滤镜的输出端口连接着volume滤镜的输入端口,volume滤镜的输出端口连接着aformat的输入端口,aformat的输出端口连接着输出滤镜的输入端口,
    这样就形成了一个滤镜处理链

音频滤镜使用流程

音频滤镜的使用流程有两种方式,这里分别进行说明。
方式一:

 

image.png

  • 总结:滤镜初始化流程为
    1、创建滤镜管道
    2、创建各个滤镜(其中输入滤镜,输出滤镜是必须的滤镜),每个滤镜的创建为固定的流程(创建滤镜,创建滤镜上下文,设置滤镜参数并初始化上下文)
    3、连接各个滤镜(其中输入滤镜一定要放在第一个,输出滤镜一定要放到最后一个)
    4、初始化滤镜管道
    5、av_buffersrc_add_frame()函数添加要进行滤镜处理的数据
    6、av_buffersink_get_frame()函数获取处理好了的音频数据

方式二:

 

image.png

  • 总结起来使用步骤为:
    1、创建滤镜管道
    2、创建各个滤镜(其中输入滤镜,输出滤镜是必须的滤镜),每个滤镜的创建为固定的流程(创建滤镜,创建滤镜上下文,设置滤镜参数并初始化上下文)
    3、连接各个滤镜(其中输入滤镜一定要放在第一个,输出滤镜一定要放到最后一个)
    4、初始化滤镜管道
    5、av_buffersrc_add_frame()函数添加要进行滤镜处理的数据
    6、av_buffersink_get_frame()函数获取处理好了的音频数据
    其中2、3步骤每一个滤镜的处理步骤都一样,只是参数不同而已。ffmpeg针对性的提出了另外一种初始化每个滤镜的简化的处理方式。它通过给定格式的滤镜字符串来解析出
    并初始化每个滤镜,同时自动添加到滤镜管道中。滤镜字符串的格式如下:
    filter_name1=par_name1=par_val1,filter_name2=par_name1=par_val1
    如果滤镜只需要一个参数,可以简化为filter_name=par_val;如果滤镜有多个参数,则多个参数用":"分隔filter_name=par_name1=par_val1:par_name2=par_val2:
    多个滤镜之间则用","分隔
    如:
    aresample=44100,aformat=sample_fmts=s32:channel_layouts=mono

实现代码

公共代码文件

 

#ifndef AudioVolume_hpp
#define AudioVolume_hpp

#include <stdio.h>
#include <inttypes.h>
#include <string>

using namespace std;
extern "C" {
#include "Common.h"
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavcodec/avcodec.h>
#include <libavfilter/avfilter.h>
#include <libavfilter/buffersrc.h>
#include <libavfilter/buffersink.h>
#include <libavutil/opt.h>
#include <libavutil/macros.h>
#include <libavutil/timestamp.h>
}

class AudioVolume
{
public:
    AudioVolume();
    ~AudioVolume();
    /** 方式一:实现调整声音的大小以及改变音频数据的格式功能
     *  1、可以调整声音的大小
     *  2、可以改变音频的采样率,采样格式,声道类型等等格式
     *  使用音频滤镜实现,改变后达到想要的效果
     *  备注:以MP3音频为例;
     */
    void doChangeAudioVolume();
    
    /** 方式二:实现调整声音的大小以及改变音频数据的格式功能
     *  1、可以调整声音的大小
     *  2、可以改变音频的采样率,采样格式,声道类型等等格式
     *  使用音频滤镜实现,改变后达到想要的效果
     *  备注:以MP3音频为例;与方式一不同的地方在于滤镜管道的初始化方式更加简单
     */
    void doChangeAudioVolume2();
    
private:
    // 用于解析本地音频源文件
    AVFormatContext *in_fmt;
    // 用于写入改变后的音频数据到目标文件
    AVFormatContext *ou_fmt;
    // 用于解码的
    AVCodecContext  *de_ctx;
    // 用于编码的
    AVCodecContext  *en_ctx;
    AVFrame         *de_frame;
    AVFrame         *en_frame;
    // 处理音频转换的滤镜管道
    AVFilterGraph *graph;
    // 输入滤镜上下文(滤镜实例)
    AVFilterContext *src_flt_ctx;
    // 输出滤镜上下文(滤镜实例)
    AVFilterContext *sink_flt_ctx;
    // 输入滤镜
    AVFilter        *src_flt;
    // 输出滤镜
    AVFilter        *sink_flt;
    int             next_audio_pts;
    
    void doDecode(AVPacket *packt);
    void doEncode(AVFrame *frame);
    void releasesources();
};
#endif /* AudioVolume_hpp */

方式一实现代码:

 

void AudioVolume::doChangeAudioVolume()
{
    string curFile(__FILE__);
    unsigned long pos = curFile.find("2-video_audio_advanced");
    if (pos == string::npos) {
        LOGD("not find file");
        return;
    }
    string srcDic = curFile.substr(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值