音频处理中,有时不同的编解码器支持的音频格式不一样,原始采样的音频数据可能没法直接直接为编解码器支持,如FFMPEG编码MP3格式的音频,就要求样本采用AV_SAMPLE_FMT_S16P格式保存。
这就需要对不同的音频格式转换,需要重采样。
1、如果PCM文件采用交叉存储方式,视频帧的概念可能没什么影响,因为数据都是LRLRLR...LR方式;
2、如果采用平行存储方式,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:1269122125@qq.com
Description: 代码实现音频重采样 把交叉存储的双声道立体声转换成平行存储的双声道
立体声
--------------------------------------------------------------------------------
Modification History
DATE AUTHOR DESCRIPTION
--------------------------------------------------------------------------------
********************************************************************************/
#include <stdio.h>
#define __STDC_CONSTANT_MACROS
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"
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结构体中
avcodec_fill_audio_frame(pRawframe, iInputChans, eInputSampleFormat, (const uint8_t*)pRawBuff, iRawBuffSize, 0);
// 计算并申请一段buf用于存放数据
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;
avcodec_fill_audio_frame(pConvertframe, iOutputChans, eOutputSampleFormat, (const uint8_t*)pConvertBuff, iConvertBuffSize, 0);
//将数据buf给avframe的date* 如果需要平面音频,则分配AVFrame extended_data通道指针。
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;
}
来源:CSDN
作者:SXM19940913sxm
链接:https://blog.csdn.net/qq_42024067/article/details/104582326