技术在于交流、沟通,转载请注明出处并保持作品的完整性。

原文:https://blog.csdn.net/hiwubihe/article/details/81259134
<https://blog.csdn.net/hiwubihe/article/details/81259134>

[音频编解码系列文章]

* 音频编解码基础 <https://blog.csdn.net/hiwubihe/article/details/81258879>
* FFMPEG实现音频重采样 <https://blog.csdn.net/hiwubihe/article/details/81259134>
* FFMPEG实现PCM编码(采用封装格式实现)
<https://blog.csdn.net/hiwubihe/article/details/81260882>
* FFMPEG实现PCM编码(不采用封装格式实现)
<https://blog.csdn.net/hiwubihe/article/details/81260923>
* FAAC库实现PCM编码 <https://blog.csdn.net/hiwubihe/article/details/81260931>
* FAAD库实现RAW格式AAC解码 <https://blog.csdn.net/hiwubihe/article/details/81260961>
* FAAD库实现RAW格式AAC封装成ADTS格式
<https://blog.csdn.net/hiwubihe/article/details/81260980>
* FAAD库实现ADTS格式解码 <https://blog.csdn.net/hiwubihe/article/details/81261006>
* FFMPEG实现对AAC解码(采用封装格式实现)
<https://blog.csdn.net/hiwubihe/article/details/81261022>
* FFMPEG实现对AAC解码(不采用封装格式实现)
<https://blog.csdn.net/hiwubihe/article/details/81267872>

音频处理中,有时不同的编解码器支持的音频格式不一样,原始采样的音频数据可能没法直接直接为编解码器支持,如FFMPEG编码MP3格式的音频,就要求样本采用AV_SAMPLE_FMT_S16P格式保存。这就需要对不同的音频格式转换,需要重采样。这里需要注意一点,如果PCM文件采用交叉存储方式,视频帧的概念可能没什么影响,因为数据都是LRLRLR...LR方式;但是如果采用平行存储方式,L...LR...RL...LR...R,一帧必须按照指定的数据读取了,如MP3读取一帧需要读取1152*2(通道数)个样本,然后前1152为左声道,后1152为右声道。

音频重采样式例代码

/*******************************************************************************
Copyright (c) wubihe Tech. Co., Ltd. All rights reserved.
--------------------------------------------------------------------------------
Date Created: 2014-10-25 Author: wubihe QQ:1269122125 Email:[email protected]
Description: 代码实现音频重采样 把交叉存储的双声道立体声转换成平行存储的双声道 立体声
--------------------------------------------------------------------------------
Modification History DATE AUTHOR DESCRIPTION
--------------------------------------------------------------------------------
********************************************************************************/
#include <stdio.h> #define __STDC_CONSTANT_MACROS #ifdef _WIN32 //Windows
extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h"
#include "libswresample/swresample.h" }; #else //Linux... #ifdef __cplusplus
extern "C" { #endif #include <libavcodec/avcodec.h> #include
<libavformat/avformat.h> #ifdef __cplusplus }; #endif #endif int main() {
static char*pFormatName[]= { "FMT_U8","FMT_S16","FMT_S32","FMT_FLT","FMT_DBL",
"FMT_U8P","FMT_S16P","FMT_S32P","FMT_FLTP","FMT_DBLP" }; //原始PCM文件 FILE
*pInputFile = fopen("huangdun_r48000_FMT_S16_c2.pcm", "rb"); uint64_t
iInputLayout = AV_CH_LAYOUT_STEREO; int iInputChans =
av_get_channel_layout_nb_channels(iInputLayout); AVSampleFormat
eInputSampleFormat = AV_SAMPLE_FMT_S16; int iInputSampleRate = 48000;
//转换后PCM文件 uint64_t iOutputLayout = AV_CH_LAYOUT_STEREO; int iOutputChans =
av_get_channel_layout_nb_channels(iOutputLayout); AVSampleFormat
eOutputSampleFormat = AV_SAMPLE_FMT_S16P; int iOutputSampleRate = 48000; bool
bOutPutPlaner=true; char szOutFileName[256]={0};
sprintf(szOutFileName,"huangdun_r%d_%s_c%d.pcm",iOutputSampleRate,pFormatName[eOutputSampleFormat],iOutputChans);
FILE *pOutputFile = fopen(szOutFileName, "wb"); //初始化转换上下文 SwrContext *pSwrCtx
= swr_alloc_set_opts(NULL,iOutputLayout, eOutputSampleFormat,
iOutputSampleRate, iInputLayout,eInputSampleFormat , iInputSampleRate,0, NULL);
swr_init(pSwrCtx); //1帧数据样本数 int iFrameSamples = 1024; //保存转换后的数据 /*uint8_t
**ppConvertData = (uint8_t**)calloc(iOutputChans,sizeof(*ppConvertData)); int
iConvertLineSize = 0; int iConvertDataSize = av_samples_alloc(ppConvertData,
&iConvertLineSize,iOutputChans, iFrameSamples,eOutputSampleFormat, 0);*/
//音频处理是以帧为单位处理的 //分配存储原始数据内存空间 int iRawLineSize = 0; int iRawBuffSize =
av_samples_get_buffer_size(&iRawLineSize, iInputChans, iFrameSamples,
eInputSampleFormat, 0); uint8_t *pRawBuff = (uint8_t *)av_malloc(iRawBuffSize);
//原始数据保存在AVFrame结构体中 AVFrame* pRawframe = av_frame_alloc();
pRawframe->nb_samples = iFrameSamples; pRawframe->format = eInputSampleFormat;
pRawframe->channels = iInputChans; //把分配内存挂到AVFrame结构体中 int iReturn =
avcodec_fill_audio_frame(pRawframe, iInputChans, eInputSampleFormat, (const
uint8_t*)pRawBuff, iRawBuffSize, 0); if(iReturn<0) { return -1; } // 存储转换后数据
int iConvertLineSize = 0; int iConvertBuffSize =
av_samples_get_buffer_size(&iConvertLineSize, iOutputChans, iFrameSamples,
eOutputSampleFormat, 0); uint8_t *pConvertBuff = (uint8_t
*)av_malloc(iConvertBuffSize); //转换后数据保存在AVFrame结构体中 AVFrame* pConvertframe =
av_frame_alloc(); pConvertframe->nb_samples = iFrameSamples;
pConvertframe->format = eOutputSampleFormat; pConvertframe->channels =
iOutputChans; iReturn = avcodec_fill_audio_frame(pConvertframe, iOutputChans,
eOutputSampleFormat, (const uint8_t*)pConvertBuff, iConvertBuffSize, 0);
if(iReturn<0) { return -1; } int iFrameNum =0; //读取一帧音频数据 int iRealRead =
fread(pRawBuff, 1, iRawBuffSize, pInputFile); while(iRealRead>0) { //完成音频帧转换
swr_convert(pSwrCtx, (uint8_t**)pConvertframe->data, iFrameSamples ,(const
uint8_t**)pRawframe->data, iFrameSamples ); if(bOutPutPlaner) { //只保存一个通道数据
便于分析 因为PCM工具不支持这种平行存储方式数据查看
//一般情况平行存储方式pConvertframe->data[i]为i声道数据pConvertframe->linesize[i]
//为i声道长度,但是音频各个声道的数据长度是相同的,所以只有pConvertframe->linesize[0]表示长度,
//其他pConvertframe->linesize[1]==0
fwrite(pConvertframe->data[0],pConvertframe->linesize[0],1,pOutputFile); }
printf("Convert Frame :%d\n",++iFrameNum); iRealRead = fread(pRawBuff, 1,
iRawBuffSize, pInputFile); } fclose(pInputFile); fclose(pOutputFile);
av_free(pRawBuff); av_free(pConvertBuff); swr_free(&pSwrCtx); printf("Convert
Success!!\n"); getchar(); return 0; }
原始文件双通道交叉存储方式huangdun_r48000_FMT_S16_c2.pcm。



转换后文件采用平行存储方式huangdun_r48000_FMT_S16P_c2.pcm,这里只保存一个通道的数据,另一个通道是一样的。



编译环境:   Win7_64bit+VS2008

DEMO下载地址:https://download.csdn.net/download/hiwubihe/10569433
<https://download.csdn.net/download/hiwubihe/10569433>

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信