ffmpeg简单分析系列----音频(audio)

ffmpeg简单分析系列----音频(audio)

  • 音频有几个重要的参数:采样率(sample_rate,单位是Hz),通道数(channels),采样格式(sample_fmt,见AVSampleFormat,其实就是采样的精度,位数越多表示越精细,当然占用的空间也会比较大)
  • 在ffmpeg中,音频数据的存储格式也有planar和packed之分,planar表示每个通道数据单独存储,packed表示通道数据交叉存储,在AVSampleFormat的类型末尾带P的就表示是planar格式的
  • 比如双声道,用L表示左声道,R表示右声道,那么packed的存储为:LRLRLRLRLRLRLRLR;而planar的存储为LLLLRRRRLLLLRRRR

采样格式

enum AVSampleFormat {
 AV_SAMPLE_FMT_NONE = -1,
 AV_SAMPLE_FMT_U8,          ///< unsigned 8 bits
 AV_SAMPLE_FMT_S16,         ///< signed 16 bits
 AV_SAMPLE_FMT_S32,         ///< signed 32 bits
 AV_SAMPLE_FMT_FLT,         ///< float
 AV_SAMPLE_FMT_DBL,         ///< double
 
  AV_SAMPLE_FMT_U8P,         ///< unsigned 8 bits, planar
  AV_SAMPLE_FMT_S16P,        ///< signed 16 bits, planar
  AV_SAMPLE_FMT_S32P,        ///< signed 32 bits, planar
  AV_SAMPLE_FMT_FLTP,        ///< float, planar
  AV_SAMPLE_FMT_DBLP,        ///< double, planar
  AV_SAMPLE_FMT_S64,         ///< signed 64 bits
  AV_SAMPLE_FMT_S64P,        ///< signed 64 bits, planar
    
  AV_SAMPLE_FMT_NB           ///< Number of sample formats. DO NOT USE if linking dynamically
    };

通道布局(channel layout)

  • 在AVCodecContext的结构体中有channel_layout和request_channel_layout这两个参数,它们的类型是uint64_t,表示无符号64位整型
  • 很多人对这个参数无从下手,因为不知道它表示什么,该怎么使用它
  • request_channel_layout表示你期待的通道布局,而channel_layout表示实际的通道布局,channel_layout是由解码器设置的
  • channel_layout的值转换成二进制后,有多少个1就表示多少个通道
  • channel_layout.h头文件中定义了有关它的一些掩码,通过这些掩码的组合就能凑成多种通道布局,例如AV_CH_LAYOUT_STEREO是立体声(2通道),其通道的存放顺序为LEFT | RIGHT;AV_CH_LAYOUT_4POINT0是4通道,其通道的存放顺序为
    LEFT | RIGHT | FRONT-CENTER | BACK-CENTER
  • 有了channel_layout,我们就知道了通道的顺序,这样我们就可以随意取得我们指定的通道的数据
  • 这里注意一点的是,sdl不支持音频平面格式(planar),因此如果用sdl播放音频必须先得转成packed格式
  • 以下是channel_layout.h的部分摘抄:
   37 /**
   38  * @defgroup channel_masks Audio channel masks
   39  *
   40  * A channel layout is a 64-bits integer with a bit set for every channel.
   41  * The number of bits set must be equal to the number of channels.
   42  * The value 0 means that the channel layout is not known.
   43  * @note this data structure is not powerful enough to handle channels
   44  * combinations that have the same channel multiple times, such as
   45  * dual-mono.
   46  *
   47  * @{
   48  */
   49 #define AV_CH_FRONT_LEFT             0x00000001
   50 #define AV_CH_FRONT_RIGHT            0x00000002
   51 #define AV_CH_FRONT_CENTER           0x00000004
   52 #define AV_CH_LOW_FREQUENCY          0x00000008
   53 #define AV_CH_BACK_LEFT              0x00000010
   54 #define AV_CH_BACK_RIGHT             0x00000020
   55 #define AV_CH_FRONT_LEFT_OF_CENTER   0x00000040
   56 #define AV_CH_FRONT_RIGHT_OF_CENTER  0x00000080
   57 #define AV_CH_BACK_CENTER            0x00000100
   58 #define AV_CH_SIDE_LEFT              0x00000200
   59 #define AV_CH_SIDE_RIGHT             0x00000400
   60 #define AV_CH_TOP_CENTER             0x00000800
   61 #define AV_CH_TOP_FRONT_LEFT         0x00001000
   62 #define AV_CH_TOP_FRONT_CENTER       0x00002000
   63 #define AV_CH_TOP_FRONT_RIGHT        0x00004000
   64 #define AV_CH_TOP_BACK_LEFT          0x00008000
   65 #define AV_CH_TOP_BACK_CENTER        0x00010000
   66 #define AV_CH_TOP_BACK_RIGHT         0x00020000
   67 #define AV_CH_STEREO_LEFT            0x20000000  ///< Stereo downmix.
   68 #define AV_CH_STEREO_RIGHT           0x40000000  ///< See AV_CH_STEREO_LEFT.
   69 #define AV_CH_WIDE_LEFT              0x0000000080000000ULL
   70 #define AV_CH_WIDE_RIGHT             0x0000000100000000ULL
   71 #define AV_CH_SURROUND_DIRECT_LEFT   0x0000000200000000ULL
   72 #define AV_CH_SURROUND_DIRECT_RIGHT  0x0000000400000000ULL
   73 #define AV_CH_LOW_FREQUENCY_2        0x0000000800000000ULL
   74 
   75 /** Channel mask value used for AVCodecContext.request_channel_layout
   76     to indicate that the user requests the channel order of the decoder output
   77     to be the native codec channel order. */
   78 #define AV_CH_LAYOUT_NATIVE          0x8000000000000000ULL
   79 
   80 /**
   81  * @}
   82  * @defgroup channel_mask_c Audio channel layouts
   83  * @{
   84  * */
   85 #define AV_CH_LAYOUT_MONO              (AV_CH_FRONT_CENTER)
   86 #define AV_CH_LAYOUT_STEREO            (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT)
   87 #define AV_CH_LAYOUT_2POINT1           (AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY)
   88 #define AV_CH_LAYOUT_2_1               (AV_CH_LAYOUT_STEREO|AV_CH_BACK_CENTER)
   89 #define AV_CH_LAYOUT_SURROUND          (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER)
   90 #define AV_CH_LAYOUT_3POINT1           (AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY)
   91 #define AV_CH_LAYOUT_4POINT0           (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_CENTER)
   92 #define AV_CH_LAYOUT_4POINT1           (AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY)
   93 #define AV_CH_LAYOUT_2_2               (AV_CH_LAYOUT_STEREO|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT)
   94 #define AV_CH_LAYOUT_QUAD              (AV_CH_LAYOUT_STEREO|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT)
   95 #define AV_CH_LAYOUT_5POINT0           (AV_CH_LAYOUT_SURROUND|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT)
   96 #define AV_CH_LAYOUT_5POINT1           (AV_CH_LAYOUT_5POINT0|AV_CH_LOW_FREQUENCY)
   97 #define AV_CH_LAYOUT_5POINT0_BACK      (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT)
   98 #define AV_CH_LAYOUT_5POINT1_BACK      (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_LOW_FREQUENCY)
   99 #define AV_CH_LAYOUT_6POINT0           (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_CENTER)
  100 #define AV_CH_LAYOUT_6POINT0_FRONT     (AV_CH_LAYOUT_2_2|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER)
  101 #define AV_CH_LAYOUT_HEXAGONAL         (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_BACK_CENTER)
  102 #define AV_CH_LAYOUT_6POINT1           (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_CENTER)
  103 #define AV_CH_LAYOUT_6POINT1_BACK      (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_BACK_CENTER)
  104 #define AV_CH_LAYOUT_6POINT1_FRONT     (AV_CH_LAYOUT_6POINT0_FRONT|AV_CH_LOW_FREQUENCY)
  105 #define AV_CH_LAYOUT_7POINT0           (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT)
  106 #define AV_CH_LAYOUT_7POINT0_FRONT     (AV_CH_LAYOUT_5POINT0|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER)
  107 #define AV_CH_LAYOUT_7POINT1           (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT)
  108 #define AV_CH_LAYOUT_7POINT1_WIDE      (AV_CH_LAYOUT_5POINT1|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER)
  109 #define AV_CH_LAYOUT_7POINT1_WIDE_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER)
  110 #define AV_CH_LAYOUT_OCTAGONAL         (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_CENTER|AV_CH_BACK_RIGHT)
  111 #define AV_CH_LAYOUT_HEXADECAGONAL     (AV_CH_LAYOUT_OCTAGONAL|AV_CH_WIDE_LEFT|AV_CH_WIDE_RIGHT|AV_CH_TOP_BACK_LEFT|AV_CH_TOP_BACK_RIGHT|AV_CH_TOP_BACK_CENTER|AV_CH_TOP_FRONT_CENTER|AV_CH_TOP_FRONT_LEFT|AV_CH_TOP_FRONT_RIGHT)
  112 #define AV_CH_LAYOUT_STEREO_DOWNMIX    (AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT)

常用api

int64_t av_get_default_channel_layout(int nb_channels)
  • 这个函数可以根据通道的个数获得默认的channel_layout
int av_get_channel_layout_nb_channels(uint64_t channel_layout)
  • 根据通道布局获得对应的通道数
int av_get_channel_layout_channel_index(uint64_t channel_layout,uint64_t channel);
  • 获得单通道在通道布局中的下标,注意channel必须是单通道的,比如获得AV_CH_BACK_CENTER在AV_CH_LAYOUT_4POINT0中的下标,可以得到结果为3;
  • 根据这个下标就可以取到对应通道的数据了

音频解码

typedef struct AVCodecContext {

/* audio only */
int sample_rate; ///< samples per second
int channels;    ///< number of audio channels

/**
* audio sample format
* - encoding: Set by user.
* - decoding: Set by libavcodec.
*/
 enum AVSampleFormat sample_fmt;  ///< sample format

 /* The following data should not be initialized. */
 /**
 * Number of samples per channel in an audio frame.
 *
 * - encoding: set by libavcodec in avcodec_open2(). Each submitted frame
 *   except the last must contain exactly frame_size samples per channel.
 *   May be 0 when the codec has AV_CODEC_CAP_VARIABLE_FRAME_SIZE set, then the
 *   frame size is not restricted.
 * - decoding: may be set by some decoders to indicate constant frame size
 */
int frame_size;

/**
  * Audio cutoff bandwidth (0 means "automatic")
  * - encoding: Set by user.
  * - decoding: unused
   */
   int cutoff;
  
   /**
 * Audio channel layout.
 * - encoding: set by user.
 * - decoding: set by user, may be overwritten by libavcodec.
  */
       uint64_t channel_layout;
 /**
   * Request decoder to use this channel layout if it can (0 for default)
    * - encoding: unused
    * - decoding: Set by user.
    */
   uint64_t request_channel_layout;
    /**
    * Type of service that the audio stream conveys.
     * - encoding: Set by user.
     * - decoding: Set by libavcodec.
     */
    enum AVAudioServiceType audio_service_type;
   
   /**
    * desired sample format
   * - encoding: Not used.
   * - decoding: Set by user.
   * Decoder will decode to this format if it can.
   */
  enum AVSampleFormat request_sample_fmt;
}
  • 其中frame_size的意思就是一个packet中的采样数,比如采样率是48000,frame_size=1152,则表示每秒有48000次采样,而每个packet有1152次采样,因此一个packet的时间是1152/48000 * 1000 = 24毫秒
  • channel_layout是声道布局,表示多声道的个数和顺序,有了这个顺序才能顺利取到需要的数据

libswresample

  • libswresample主要是用于音频的重采样和格式转换的,包含如下功能:

    • 采样频率转换:对音频的采样频率进行转换的处理,例如把音频从一个高的44100Hz的采样频率转换到8000Hz;从高采样频率到低采样频率的音频转换是一个有损的过程
    • 声道格式转换:对音频的声道格式进行转换的处理,例如立体声转换为单声道;当输入通道不能映射到输出流时,这个过程是有损的,因为它涉及不同的增益因素和混合。
    • 采样格式转换:对音频的样本格式进行转换的处理,例如把s16(AV_SAMPLE_FMT_S16)的PCM数据转换为s8格式或者f32的PCM数据;此外提供了Packed和Planar包装格式之间相互转换的功能
  • 当音频的采样率与播放器的采样率不一致时,那么想在播放器正常播放,就需要对音频进行重采样,否则可能会出现音频变速的问题

音频转换

  • 音频转换一般就是指planar和packed的互转,或者声道之间的转换
  • 当我们解码后的音频数据是planar的,而我们的播放器却只支持packed的,那么我们就需要将planar转为packed,例如是双声道的话就是要将原本为LLLLRRRR的数据变为LRLRLRLR,知道这个原理后,其实两个for循环就能搞定这次转换,如下
 data_size = av_get_bytes_per_sample(dec_ctx->sample_fmt);
 for (i = 0; i < frame->nb_samples; i++)
     for (ch = 0; ch < dec_ctx->channels; ch++)
         fwrite(frame->data[ch] + data_size*i, 1, data_size, outfile);
  • 以上只是为了更好的理解转换过程,实际上ffmpeg已经提供了相关的接口来帮助我们转换,如非特别需求,建议还是使用ffmpeg提供的转换接口
  • 在ffmpeg中,转换主要包含3个步骤:
  • 1 实例化SwrContext
  • 2 计算转换后的sample个数
  • 3 调用 swr_convert进行转换

uint8_t **input;
int in_samples;

//第一种方式创建SwrContext
//SwrContext *swr = swr_alloc();
// av_opt_set_channel_layout(swr, "in_channel_layout",  AV_CH_LAYOUT_5POINT1, 0);
// av_opt_set_channel_layout(swr, "out_channel_layout", AV_CH_LAYOUT_STEREO,  0);
// av_opt_set_int(swr, "in_sample_rate",     48000,                0);
// av_opt_set_int(swr, "out_sample_rate",    44100,                0);
// av_opt_set_sample_fmt(swr, "in_sample_fmt",  AV_SAMPLE_FMT_FLTP, 0);
// av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S32,  0);

//第二种方式创建SwrContext,以下代码作用等同于上面的
SwrContext *swr = swr_alloc_set_opts(NULL,  // we're allocating a new context
                         AV_CH_LAYOUT_STEREO,  // out_ch_layout
                         AV_SAMPLE_FMT_S32,    // out_sample_fmt
                         44100,                // out_sample_rate
                         AV_CH_LAYOUT_5POINT1, // in_ch_layout
                         AV_SAMPLE_FMT_FLTP,   // in_sample_fmt
                         48000,                // in_sample_rate
                         0,                    // log_offset
                         NULL);                // log_ctx


//在得到SwrContext后就要进行初始化 ,如果SwrContext的参数有任何变化,则必须再次调用以下初始化函数
swr_init(swr)//这里演示修改了第三个参数为AV_SAMPLE_FMT_S16,则需要再次调用swr_init
swr = swr_alloc_set_opts(swr,  
                         AV_CH_LAYOUT_STEREO,  // out_ch_layout
                         AV_SAMPLE_FMT_S16,    // out_sample_fmt
                         44100,                // out_sample_rate
                         AV_CH_LAYOUT_5POINT1, // in_ch_layout
                         AV_SAMPLE_FMT_FLTP,   // in_sample_fmt
                         48000,                // in_sample_rate
                         0,                    // log_offset
                         NULL);                // log_ctx
                         
swr_init(swr)//再次调用

//计算转换后的采样数samples,计算公式为 in_samples*out_sample_rate=out_samples*in_sample_rate
//该运算在数学上等价于a * b / c,最后一个参数可以支持多种取舍
int out_samples = av_rescale_rnd(swr_get_delay(swr, //获取下一个输入样本相对于下一个输出样本将经历的延迟
												48000)//输入采样率 
									+in_samples, 
                                     44100, //输出采样率
                                     48000, //输入采样率
                                     AV_ROUND_UP);//表示向上取整,如3/2=2

//根据转换后的音频参数分配一块缓冲来存储数据
uint8_t *  output[8];//用于存储转换后的数据
//分配一个样本缓冲区,并相应地填充数据指针和行大小
//可以使用av_freep(&output [0])释放分配的样本缓冲区
  av_samples_alloc(&output,//[out]
    				 NULL, //[out]
    				 2, //通道数
    				 out_samples,//采样数
                     AV_SAMPLE_FMT_S16, //采样格式
                     0);//对齐,0--默认,1--不对齐

 out_samples = swr_convert(swr, 
   						      &output, //转换后的数据
   						      out_samples,
                              input, //要转换的数据
                              in_samples);

if(swr_get_out_samples(swr,0)>0){//表示有缓冲数据
//通过设置in和in_count为0将缓存中的全部处理完毕,这通常是最后一步,如果没有这步,则可能最后的音频数据会存在缓冲中没有全部转换出来
  out_samples = swr_convert(swr, 
   						      &output, 
   						      out_samples,
                              NULL, 
                              0);
}
                             
swr_free(&swr)//最后释放

  • swr_convert()在转换过程中如果输入采样数大于输出采样数,那么超出的部分会被Swresample缓存起来,因此输出采样数这个参数要根据输入采样数和已经存在的缓存进行计算,否则可能会导致缓存的采样数越来越多,内存一直在上涨;当in和in_count都为0时,就表示要把缓存中数据都输出出来了
  • swr_get_out_samples()函数的意思是获得下一个输出样本缓冲的数量,相同的输入返回值并不是一样的,这取决于内部的缓存采样数的多少;我们知道,swr_convert在调用后,如果输入的采样数比输出的采样数大,那么Swresample便会对超出的那部分进行缓存,如果输入一直比输出大,那么内存就会一直上涨,为此,我们需要swr_get_out_samples这个函数让我们得知输出应该为多大才能把缓冲里的数据也带走,比如Swresample里已经有10个采样数的缓存了,此时输入如果为100个采样数,那么我们希望输出为110(这是在不改变采样率的情况下),这样就能把所有数据都输出,缓存也清空了,就不会引起内存上涨,那么怎么得到这个110呢,通过swr_get_out_samples(swr,100)=110;如果swr_get_out_samples(swr,0)就表示获得Swresample已经缓存的采样数;最后总结一下,swr_get_out_samples就是根据你的输入采样数,得到应该取走的输出采样数,如果输入采样数为0,那么就能得到已经缓存的采样数,得到这个输出采样数后,我们才知道应该通过av_samples_alloc为输出样本分配多大的缓存空间
  • swr_get_delay()这个暂时也没搞懂

音频重采样

  • https://blog.csdn.net/eydwyz/article/details/78748312 ffmpeg解码音频数据时,进行重采样(即改变文件原有的采样率)_Python_eydwyz的专栏-CSDN博客

相关计算

  • AVFrame.nb_samples(AVFrame.nb_samples和AVCodecContext.frame_size实际上是同一个东西,他们相等)表示的是每帧每个通道的采样数,aac一般是1024(LC)或2048(HE),mp3一般是1152

A HE-AAC v1 or v2 audio frame contains 2048 PCM samples per channel
(there is also one mode with 1920 samples per channel but this is
only for special purposes such as DAB+ digital radio). These
bits/frame figures are average figures where each AAC frame generally
has a different size in bytes. To calculate the same for AAC-LC just
use 1024 instead of 2048 PCM samples per frame and channel. For
AAC-LD/ELD it is either 480 or 512 PCM samples per frame and channel.

  • 我们知道从解码器解码出一帧,如果是视频的话,那这一帧通常就是一个画面的数据,而对于音频来说,这一帧大概只包含几十毫秒长的音频数据,那么怎么知道这一帧究竟是表示多长的音频呢
  • 首先我们要清楚AVFrame.nb_samples等于AVCodecContext.farme_size,它表示的意思就是每帧每个通道的采样数,有了它,我们就可以计算出一帧包含的音频时长,因为音频都有一个采样率,它表示一秒采样多少次,现在我们知道了采样数,那么一除就可以知道时长了,如下
  • 一帧时长(ms)=一帧采样数/采样率*1000
  • 在ffmpeg中一帧采样数就是AVFrame.nb_samples或者AVCodecContext.farme_size,而采样率就是AVCodecContext.sample_rate
  • 比如采样率是48000,而frame_size=1152,那么就可以得出这一帧的音频时长为1152/48000*1000 = 24毫秒
  • 此时你已经知道了一帧的音频时长,假如你还想知道这一帧的数据大小那该怎么计算呢
  • 我们知道,每次采样后都需要保存这个采样的数据,那么用多大来保存它呢,这就看AVSampleFormat了,比如AV_SAMPLE_FMT_S16就表示用16位即2个字节来保存一个采样数据,当然位数越多,能保存的数据就会更多,音质肯定就会越好
  • 我们知道AV_SAMPLE_FMT_S16是占2个字节,AV_SAMPLE_FMT_S32是占4个字节,在ffmpeg中提供了一个函数av_get_bytes_per_sample(),它可以帮我们计算出AVSampleFormat究竟是几个字节,比如av_get_bytes_per_sample(AV_SAMPLE_FMT_S16)=2,av_get_bytes_per_sample(AV_SAMPLEAV_SAMPLE_FMT_S32)=4
  • 有了上面的分析,我们就可以得出一帧的数据大小=采样数*存储采样的位数*声道数
  • 这一帧的数据都保存在AVFrame.data里,假如是双声道,planar格式,那么我们想取出左声道的数据的话,那得先知道左声道的数据放在AVFrame.data这个数组的哪个下标,在ffmpeg中**av_get_channel_layout_channel_index()**这个函数就能帮助我们得到下标,然后我们就可以愉快取出数据了
  • 根据上面的分析,我们还可以轻松计算出1秒能包含多少帧音频,假如我们知道了采样率,采样格式,一帧的采样数,那么我们就可以计算出1秒包含的音频帧数,比如采样率是88200,采样格式是AV_SAMPLE_FMT_S16(这么写太长了,这里用s16代替下),一帧的采样数是1024,那么一帧数据量:1024*2*av_get_bytes_per_sample(s16) = 4096个字节,一秒可以编码的帧数:88200/(1024*2*av_get_bytes_per_sample(s16)) = 21.5帧数据

参考

  • https://blog.csdn.net/qq_18998145/article/details/97394595 ffmpeg音频存储格式packed和planar_LIEY-CSDN博客
  • https://www.cnblogs.com/wangguchangqing/p/5851490.html FFmpeg学习4:音频格式转换 - Brook_icv - 博客园
  • https://blog.csdn.net/eydwyz/article/details/78748241 (25条消息)FFmpeg关于nb_smples,frame_size以及profile的解释_eydwyz的专栏-CSDN博客
  • https://blog.csdn.net/eydwyz/article/details/78748312 ffmpeg解码音频数据时,进行重采样(即改变文件原有的采样率)_Python_eydwyz的专栏-CSDN博客
  • https://www.jianshu.com/p/bf5e54f553a4 FFmpeg音频重采样API(libswresample) - 简书
  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
fluent-ffmpeg 是一个在 Node.js 中处理和转码音视频文件的流行库。以下是 fluent-ffmpeg 的一些常见用法示例: 1. 转码视频文件: ```javascript import ffmpeg from 'fluent-ffmpeg'; const inputFilePath = 'path/to/your/input/video'; // 输入视频文件路径 const outputFilePath = 'path/to/your/output/video'; // 输出转码后的视频文件路径 ffmpeg(inputFilePath) .output(outputFilePath) .run(); ``` 2. 添加水印到视频文件: ```javascript import ffmpeg from 'fluent-ffmpeg'; const inputFilePath = 'path/to/your/input/video'; // 输入视频文件路径 const outputFilePath = 'path/to/your/output/video'; // 输出带水印的视频文件路径 const watermarkFilePath = 'path/to/your/watermark/image'; // 水印图片文件路径 ffmpeg(inputFilePath) .input(watermarkFilePath) .complexFilter([ '[0:v][1:v]overlay=W-w-10:H-h-10', // 在视频右下角添加水印 ]) .output(outputFilePath) .run(); ``` 3. 提取音频文件: ```javascript import ffmpeg from 'fluent-ffmpeg'; const inputFilePath = 'path/to/your/input/video'; // 输入视频文件路径 const outputFilePath = 'path/to/your/output/audio'; // 输出音频文件路径 ffmpeg(inputFilePath) .output(outputFilePath) .noVideo() .run(); ``` 4. 提取视频文件的音频流并进行转码: ```javascript import ffmpeg from 'fluent-ffmpeg'; const inputFilePath = 'path/to/your/input/video'; // 输入视频文件路径 const outputFilePath = 'path/to/your/output/audio'; // 输出音频文件路径 ffmpeg(inputFilePath) .output(outputFilePath) .audioCodec('aac') .run(); ``` 这些只是 fluent-ffmpeg 的一些基本用法示例,它还提供了许多其他功能和选项,如剪切、合并、调整音频/视频参数等。你可以参考 fluent-ffmpeg 的文档以获取更多详细信息和示例:https://github.com/fluent-ffmpeg/node-fluent-ffmpeg

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值