基于ffmpeg的音频转码

Posted 楠倏之语

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于ffmpeg的音频转码相关的知识,希望对你有一定的参考价值。

首先引入音频帧的概念:

正常人听觉的频率范围大约在20Hz~20kHz之间。
采样频率是指将模拟声音波形进行数字化时,每秒钟抽取声波幅度样本的次数。 根据奈奎斯特采样理论,为了保证声音不失真,采样频率应该在40kHz左右。 常用的音频采样频率有8kHz、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz等, 如果采用更高的采样频率,还可以达到DVD的音质。
对采样率为44.1kHz的AAC音频进行解码时,一帧的解码时间须控制在23.22毫秒内。 通常是按1024个采样点一帧
分析: 1. AAC 一个AAC原始帧包含某段时间内1024个采样点相关数据。 用1024主要是因为AAC是用的1024点的mdct。
音频帧的播放时间 = 一个AAC帧对应的采样样本的个数 / 采样频率(单位为s)。
采样率(samplerate)为 44100Hz,表示每秒 44100个采样点,  所以,根据公式,    音频帧的播放时长 = 一个AAC帧对应的采样点个数 / 采样频率 则,当前一帧的播放时间 = 1024 * 1000000/44100= 23.22ms(单位为ms)
48kHz采样率, 则,当前一帧的播放时间 = 1024 * 1000000/48000= 21.32ms(单位为ms)
22.05kHz采样率, 则,当前一帧的播放时间 = 1024 * 1000000/22050= 46.44ms(单位为ms)
2.MP3  mp3 每帧均为1152个字节,  则: 每帧播放时长 = 1152 * 1000000 / sample_rate 例如:sample_rate = 44100HZ时,  计算出的时长为26.122ms, 这就是经常听到的mp3每帧播放时间固定为26ms的由来。

ffmpeg音频转码:

由于不同格式音频帧数的不同,在使用ffmpeg作音频转码时需要作音频fifo来缓存解码数据,依据编码音频帧需要给对应的大小。

音频fifo可使用ffmpeg中已写好的fifo,定义在libavutil/audio_fifo.h下。


AVAudioFifo,SwrContext定义及初始化:

    AVAudioFifo *af = NULL;
    SwrContext *resample_context = NULL;
    long long pts = 0;
    for(int i=0; i<1; i++)
        printf(" samplerate input = %d , samplerate output = %d\\n",pAudioCodecCtx[i]->sample_rate, AudioEncodeCtx[i]->sample_rate);
        resample_context = swr_alloc_set_opts(NULL, av_get_default_channel_layout(AudioEncodeCtx[i]->channels),
                                                          AudioEncodeCtx[i]->sample_fmt,
                                                          AudioEncodeCtx[i]->sample_rate,
                                                          av_get_default_channel_layout(pAudioCodecCtx[i]->channels),
                                                          pAudioCodecCtx[i]->sample_fmt,
                                                          pAudioCodecCtx[i]->sample_rate,
                                                          0, NULL);
        swr_init(resample_context);
    
    af = av_audio_fifo_alloc(AudioEncodeCtx[0]->sample_fmt, AudioEncodeCtx[0]->channels, 1);
    if(af == NULL)
    
        printf("error af \\n");
        return -1;
    

转码过程:

if (avcodec_decode_audio4(pAudioCodecCtx[i], pAudioframe[i], &frame_size, &pkt) >= 0) 
                        if (i == 0)
                            uint8_t *converted_input_samples = NULL;
                            converted_input_samples = (uint8_t *)calloc(AudioEncodeCtx[i]->channels, sizeof(*converted_input_samples));
                            av_samples_alloc(&converted_input_samples, NULL, AudioEncodeCtx[i]->channels, pAudioframe[i]->nb_samples, AudioEncodeCtx[i]->sample_fmt, 0);
                            int error = 0;
                            if((error = swr_convert(resample_context, &converted_input_samples, pAudioframe[i]->nb_samples,
                                                   (const uint8_t**)pAudioframe[i]->extended_data, pAudioframe[i]->nb_samples))<0)
                                printf("error  : %d\\n",error);
                            
                            av_audio_fifo_write(af, (void **)&converted_input_samples, pAudioframe[i]->nb_samples);

                            int got_frame=0;
                            //Encode
                            while(av_audio_fifo_size(af) >= AudioEncodeCtx[i]->frame_size)
                                int frame_size = FFMIN(av_audio_fifo_size(af),AudioEncodeCtx[i]->frame_size);
                                pOutAudioframe[i]->nb_samples =  frame_size;
                                pOutAudioframe[i]->channel_layout = AudioEncodeCtx[i]->channel_layout;
                                pOutAudioframe[i]->sample_rate = AudioEncodeCtx[i]->sample_rate;
                                pOutAudioframe[i]->format = AudioEncodeCtx[i]->sample_fmt;

                                av_frame_get_buffer(pOutAudioframe[i], 0);
                                av_audio_fifo_read(af, (void **)&pOutAudioframe[i]->data, frame_size);

                                pOutAudioframe[i]->pts=pts;
                                pts += pOutAudioframe[i]->nb_samples;

                                audio_pkt.data = NULL;
                                audio_pkt.size = 0;
                                av_init_packet(&audio_pkt);
                                avcodec_encode_audio2(AudioEncodeCtx[i], &audio_pkt, pOutAudioframe[i], &got_frame);
                            
                        
                        break;
                    


以上是关于基于ffmpeg的音频转码的主要内容,如果未能解决你的问题,请参考以下文章

FFMPEG 音频解码和绘制波形

FFmpeg:流式音频播放列表,标准化响度并生成频谱图和波形

Lambda 上的 FFmpeg 转码导致无法使用(静态)音频

FFMPEG:设置音频波形颜色的不透明度

ffmpeg 波形音频和 avi 视频格式合并

ffmpeg 音频转码