使用ffmpeg轉碼pcm至aac格式
阿新 • • 發佈:2019-02-16
準備工作
去官網下載原始碼自己編譯所需要的庫,或者直接從官網下載已經編寫好的庫,由於本例是Window平臺下的開發,而官網已經有了編譯好的庫,所以直接下載編譯所需要的庫檔案即可。下載地址:需要下載兩個壓縮包,Dev版本和Shared版本,其中Dev版本是標頭檔案和lib庫檔案,Shared是包含執行所需要的dll檔案。
下載完成後,需要把這些標頭檔案、靜態庫、動態連結庫引入到我們的工程裡面,不過在Windows下面,標頭檔案除了要用到FFMPEG提供的,還要使用另外三個檔案:inttypes.h,stdint.h,_mingw.h,這三個檔案放到FFMPEG標頭檔案的根目錄下即可。
專案工程
程式碼示例
// C++程式碼需要加這個!!否則找不到函式的 extern "C" { #include "libavcodec\avcodec.h" #include "libavformat\avformat.h" #include "libswscale\swscale.h" // 連結的ffmpeg庫,我把所有可能需要用到的都寫這裡了 #pragma comment (lib, "Ws2_32.lib") #pragma comment (lib, "avcodec.lib") #pragma comment (lib, "avdevice.lib") #pragma comment (lib, "avfilter.lib") #pragma comment (lib, "avformat.lib") #pragma comment (lib, "avutil.lib") #pragma comment (lib, "swresample.lib") #pragma comment (lib, "swscale.lib") }; int main(int argc, char* argv[]) { AVFormatContext* pFormatCtx; AVOutputFormat* fmt; AVStream* audio_st; AVCodecContext* pCodecCtx; AVCodec* pCodec; uint8_t* frame_buf; AVFrame* frame; int size; FILE *fileIn = fopen("Beyond.pcm", "rb"); char* fileOut = "Beyond.aac"; // 初始化註冊FFMPEG以供使用 av_register_all(); // 解碼檔案格式 avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, fileOut); fmt = pFormatCtx->oformat; //注意輸出路徑 if (avio_open(&pFormatCtx->pb, fileOut, AVIO_FLAG_READ_WRITE) < 0) { printf("輸出檔案開啟失敗!\n"); return -1; } audio_st = avformat_new_stream(pFormatCtx, 0); if (audio_st == NULL) { printf("新建流失敗!!!\n"); return -1; } // 設定轉碼資訊 pCodecCtx = audio_st->codec; pCodecCtx->codec_id = fmt->audio_codec; pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO; pCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16; pCodecCtx->sample_rate= 44100; // 音訊的取樣率 pCodecCtx->channel_layout=AV_CH_LAYOUT_STEREO; pCodecCtx->channels = av_get_channel_layout_nb_channels(pCodecCtx->channel_layout); pCodecCtx->bit_rate = 64000; // 音訊的位元率 //除錯輸出格式資訊 av_dump_format(pFormatCtx, 0, fileOut, 1); pCodec = avcodec_find_encoder(pCodecCtx->codec_id); if (!pCodec) { printf("找不到輸入檔案所需的編碼器!\n"); return -1; } if (avcodec_open2(pCodecCtx, pCodec,NULL) < 0) { printf("開啟編碼器失敗!\n"); return -1; } frame = avcodec_alloc_frame(); frame->nb_samples= pCodecCtx->frame_size; frame->format= pCodecCtx->sample_fmt; size = av_samples_get_buffer_size(NULL, pCodecCtx->channels,pCodecCtx->frame_size,pCodecCtx->sample_fmt, 1); frame_buf = (uint8_t *)av_malloc(size); avcodec_fill_audio_frame(frame, pCodecCtx->channels, pCodecCtx->sample_fmt,(const uint8_t*)frame_buf, size, 1); // 填充輸出的標頭檔案資訊 avformat_write_header(pFormatCtx,NULL); AVPacket pkt; av_new_packet(&pkt,size); for (int i=0; ; i++) { //讀入PCM if (fread(frame_buf, 1, size, fileIn) < 0) { printf("檔案讀取錯誤!\n"); return -1; } else if(feof(fileIn)) { break; } frame->data[0] = frame_buf; //取樣訊號 frame->pts=i*100; int got_frame=0; //編碼 int ret = avcodec_encode_audio2(pCodecCtx, &pkt,frame, &got_frame); if(ret < 0) { printf("編碼錯誤!\n"); return -1; } if (got_frame==1) { pkt.stream_index = audio_st->index; ret = av_write_frame(pFormatCtx, &pkt); av_free_packet(&pkt); } } //寫檔案尾 av_write_trailer(pFormatCtx); //清理 if (audio_st) { avcodec_close(audio_st->codec); av_free(frame); av_free(frame_buf); } avio_close(pFormatCtx->pb); avformat_free_context(pFormatCtx); fclose(fileIn); printf("轉碼完畢!!!\n"); return 0; }
注
由於FFMPEG會沒事就修改介面,所以不同版本的FFMPEG可能會編譯不過,反正2015年1月23日17:29:31是可以編譯通過的。