FFMPEG實現音訊重取樣
阿新 • • 發佈:2018-11-11
技術在於交流、溝通,轉載請註明出處並保持作品的完整性。
原文:https://blog.csdn.net/hiwubihe/article/details/81259134
[音訊編解碼系列文章]
- 音訊編解碼基礎
- FFMPEG實現音訊重取樣
- FFMPEG實現PCM編碼(採用封裝格式實現)
- FFMPEG實現PCM編碼(不採用封裝格式實現)
- FAAC庫實現PCM編碼
- FAAD庫實現RAW格式AAC解碼
- FAAD庫實現RAW格式AAC封裝成ADTS格式
- FAAD庫實現ADTS格式解碼
- FFMPEG實現對AAC解碼(採用封裝格式實現)
- FFMPEG實現對AAC解碼(不採用封裝格式實現)
音訊處理中,有時不同的編解碼器支援的音訊格式不一樣,原始取樣的音訊資料可能沒法直接直接為編解碼器支援,如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