最簡單的基于 FFmpeg 的音頻解碼器
- 最簡單的基于 FFmpeg 的音頻解碼器
- 正文
- 參考
- 工程文件下載
參考雷霄驊博士的文章,鏈接:最簡單的基于FFMPEG+SDL的音頻播放器:拆分-解碼器和播放器
最簡單的基于 FFmpeg 的音頻解碼器
正文
FFmpeg 音頻解碼器實現了音頻數據到 PCM 采樣數據的解碼。
如果你不會 Vusual Studio 下 FFmpeg 的項目配置,可以看我寫的教程:Visual Studio 2015 中 FFmpeg 開發環境的搭建。
源代碼:
// Simplest FFmpeg Audio Decoder.cpp : 定義控制臺應用程序的入口點。/**
* 最簡單的基于 FFmpeg 的音頻解碼器
* Simplest FFmpeg Audio Decoder
*
* 劉文晨 Liu Wenchen
* 812288728@qq.com
* 電子科技大學/電子信息
* University of Electronic Science and Technology of China / Electronic and Information Science
* https://blog.csdn.net/ProgramNovice
*
* 本程序可以將音頻碼流(MP3,AAC等)解碼為 PCM 采樣數據。
*
* This software decode audio streams (MP3, ACC...) to PCM data.
*
*/#include "stdafx.h"#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define __STDC_CONSTANT_MACROS
#ifdef _WIN32
// Windows
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"
};
#else
// Linux
#endif// 1 second of 48kHz 32bit audio,單位是字節
#define MAX_AUDIO_FRAME_SIZE 192000 int main(int argc, char* argv[])
{// 結構體及變量定義AVFormatContext* pFormatCtx;int i, audioStream;AVCodecContext* pCodecCtx;AVCodec* pCodec;AVPacket* packet;uint8_t* out_buffer;AVFrame* pFrame;int ret;uint32_t len = 0;int got_picture;int index = 0;int64_t in_channel_layout;struct SwrContext *au_convert_ctx;// 輸出文件路徑FILE *pFile = fopen("output.pcm", "wb");// 輸入文件路徑char url[] = "skycity.mp3";// 注冊支持的所有的文件格式(容器)及其對應的 CODEC,只需要調用一次av_register_all();// 對網絡庫進行全局初始化(加載 socket 庫以及網絡加密協議相關的庫,為后續使用網絡相關提供支持)// 注意:此函數僅用于解決舊 GnuTLS 或 OpenSSL 庫的線程安全問題。// 如果 libavformat 鏈接到這些庫的較新版本,或者不使用它們,則無需調用此函數。// 否則,需要在使用它們的任何其他線程啟動之前調用此函數。avformat_network_init();// 使用默認參數分配并初始化一個 AVFormatContext 對象pFormatCtx = avformat_alloc_context();// 打開輸入媒體流,分配編解碼器上下文、解復用上下文、I/O 上下文if (avformat_open_input(&pFormatCtx, url, NULL, NULL) != 0){printf("Can't open input stream.\n");return -1;}// 讀取媒體文件的數據包以獲取媒體流信息if (avformat_find_stream_info(pFormatCtx, NULL) < 0){printf("Can't find stream information.\n");return -1;}printf("---------------- File Information ---------------\n");// 將 AVFormatContext 結構體中媒體文件的信息進行格式化輸出av_dump_format(pFormatCtx, 0, url, false);printf("-------------------------------------------------\n");audioStream = -1;for (i = 0; i < pFormatCtx->nb_streams; i++){if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO){audioStream = i;break;}}if (audioStream == -1){printf("Can't find a audio stream.\n");return -1;}// pCodecCtx 是指向音頻流的編解碼器上下文的指針pCodecCtx = pFormatCtx->streams[audioStream]->codec;// 查找 ID 為 pCodecCtx->codec_id 的已注冊的音頻流解碼器pCodec = avcodec_find_decoder(pCodecCtx->codec_id);if (pCodec == NULL){printf("Codec not found.\n");return -1;}// 初始化指定的編解碼器if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0){printf("Can't open codec.\n");return -1;}// 為 packet 分配空間packet = (AVPacket *)av_malloc(sizeof(AVPacket));// 將 packet 中的可選字段初始化為默認值av_init_packet(packet);// 輸出音頻參數// 通道類型:雙聲道uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO;int out_nb_samples = pCodecCtx->frame_size;// 采樣格式:pcm_s16le(整型 16bit)AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;// 采樣率:44100int out_sample_rate = 44100;int out_channels = av_get_channel_layout_nb_channels(out_channel_layout);int out_buffer_size = av_samples_get_buffer_size(NULL, out_channels, out_nb_samples, out_sample_fmt, 1);out_buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE * 2);pFrame = av_frame_alloc();// 根據聲道數目獲取聲道布局in_channel_layout = av_get_default_channel_layout(pCodecCtx->channels);// 創建重采樣結構體 SwrContext 對象au_convert_ctx = swr_alloc();// 設置重采樣的轉換參數au_convert_ctx = swr_alloc_set_opts(au_convert_ctx, out_channel_layout, out_sample_fmt, out_sample_rate,in_channel_layout, pCodecCtx->sample_fmt, pCodecCtx->sample_rate, 0, NULL);// 初始化 SwrContext 對象swr_init(au_convert_ctx);// 讀取碼流中的音頻若干幀或者視頻一幀while (av_read_frame(pFormatCtx, packet) >= 0){if (packet->stream_index == audioStream){// 解碼 packet 中的音頻數據,pFrame 存儲解碼數據ret = avcodec_decode_audio4(pCodecCtx, pFrame, &got_picture, packet);if (ret < 0){printf("Error in decoding audio frame.\n");return -1;}if (got_picture > 0){// 進行格式轉換,返回值為實際轉換的采樣數swr_convert(au_convert_ctx, &out_buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t **)pFrame->data, pFrame->nb_samples);// 打印每一幀的信息printf("index: %5d\t pts: %lld\t packet size: %d\n", index, packet->pts, packet->size);// 向輸出文件中寫入 PCM 數據fwrite(out_buffer, 1, out_buffer_size, pFile);index++;}}// 清空 packet 里面的數據av_free_packet(packet);}// 釋放 SwrContext 對象swr_free(&au_convert_ctx);// 關閉文件指針fclose(pFile);// 釋放內存av_free(out_buffer);// 關閉解碼器avcodec_close(pCodecCtx);// 關閉輸入音頻文件avformat_close_input(&pFormatCtx);return 0;
}
本程序可以直接在 Visual Studio 2015 上運行。
程序運行后,會解碼下面的音頻文件。
解碼后的 PCM 采樣數據被保存成了一個文件,名叫 output.pcm。使用 Adobe Audition 設置采樣率等信息后可以查看 PCM 的內容。
參考
05 FFmpeg4.4源碼分析–解碼
error C4996: ‘fopen’: This function or variable may be unsafe 的解決方法
工程文件下載
GitHub:UestcXiye / Simplest-FFmpeg-Audio-Decoder
CSDN:Simplest FFmpeg Audio Decoder.zip