最簡單的基於FFMPEG+SDL的音訊播放器:拆分-解碼器和播放器
=====================================================
最簡單的基於FFmpeg的音訊播放器系列文章列表:
=====================================================
本文補充記錄《最簡單的基於FFMPEG+SDL的音訊播放器》中的兩個例子:FFmpeg音訊解碼器和SDL音訊取樣資料播放器。這兩個部分是從音訊播放器中拆分出來的兩個例子。FFmpeg音訊解碼器實現了視訊資料到PCM取樣資料的解碼,而SDL音訊取樣資料播放器實現了PCM資料到音訊裝置的播放。簡而言之,原先的FFmpeg+SDL音訊播放器實現了:
音訊資料->PCM->音訊裝置
FFmpeg音訊解碼器實現了:
音訊資料->PCM
SDL音訊取樣資料播放器實現了:
PCM->音訊裝置FFmpeg音訊解碼器
原始碼
/** * 最簡單的基於FFmpeg的音訊解碼器 * Simplest FFmpeg Audio Decoder * * 雷霄驊 Lei Xiaohua * [email protected] * 中國傳媒大學/數字電視技術 * Communication University of China / Digital TV Technology * http://blog.csdn.net/leixiaohua1020 * * 本程式可以將音訊碼流(mp3,AAC等)解碼為PCM取樣資料。 * 是最簡單的FFmpeg音訊解碼方面的教程。 * 通過學習本例子可以瞭解FFmpeg的解碼流程。 * * This software decode audio streams (AAC,MP3 ...) to PCM data. * Suitable for beginner of FFmpeg. * */ #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... #ifdef __cplusplus extern "C" { #endif #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswresample/swresample.h> #ifdef __cplusplus }; #endif #endif #define MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio 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[]="skycity1.mp3"; av_register_all(); avformat_network_init(); pFormatCtx = avformat_alloc_context(); //Open if(avformat_open_input(&pFormatCtx,url,NULL,NULL)!=0){ printf("Couldn't open input stream.\n"); return -1; } // Retrieve stream information if(avformat_find_stream_info(pFormatCtx,NULL)<0){ printf("Couldn't find stream information.\n"); return -1; } // Dump valid information onto standard error av_dump_format(pFormatCtx, 0, url, false); // Find the first audio stream 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("Didn't find a audio stream.\n"); return -1; } // Get a pointer to the codec context for the audio stream pCodecCtx=pFormatCtx->streams[audioStream]->codec; // Find the decoder for the audio stream pCodec=avcodec_find_decoder(pCodecCtx->codec_id); if(pCodec==NULL){ printf("Codec not found.\n"); return -1; } // Open codec if(avcodec_open2(pCodecCtx, pCodec,NULL)<0){ printf("Could not open codec.\n"); return -1; } packet=(AVPacket *)av_malloc(sizeof(AVPacket)); av_init_packet(packet); //Out Audio Param uint64_t out_channel_layout=AV_CH_LAYOUT_STEREO; //nb_samples: AAC-1024 MP3-1152 int out_nb_samples=pCodecCtx->frame_size; AVSampleFormat out_sample_fmt=AV_SAMPLE_FMT_S16; int out_sample_rate=44100; int out_channels=av_get_channel_layout_nb_channels(out_channel_layout); //Out Buffer Size 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(); //FIX:Some Codec's Context Information is missing in_channel_layout=av_get_default_channel_layout(pCodecCtx->channels); //Swr 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); swr_init(au_convert_ctx); while(av_read_frame(pFormatCtx, packet)>=0){ if(packet->stream_index==audioStream){ 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); //Write PCM fwrite(out_buffer, 1, out_buffer_size, pFile); index++; } } av_free_packet(packet); } swr_free(&au_convert_ctx); fclose(pFile); av_free(out_buffer); // Close the codec avcodec_close(pCodecCtx); // Close the video file avformat_close_input(&pFormatCtx); return 0; }
執行結果
程式執行後,會解碼下面的音訊檔案。解碼後的PCM取樣資料被儲存成了一個檔案。使用Adobe Audition設定取樣率等資訊後可以檢視PCM的內容。
SDL音訊取樣資料播放器
原始碼
/** * 最簡單的SDL2播放音訊的例子(SDL2播放PCM) * Simplest Audio Play SDL2 (SDL2 play PCM) * * 雷霄驊 Lei Xiaohua * [email protected] * 中國傳媒大學/數字電視技術 * Communication University of China / Digital TV Technology * http://blog.csdn.net/leixiaohua1020 * * 本程式使用SDL2播放PCM音訊取樣資料。SDL實際上是對底層繪圖 * API(Direct3D,OpenGL)的封裝,使用起來明顯簡單于直接呼叫底層 * API。 * * 函式呼叫步驟如下: * * [初始化] * SDL_Init(): 初始化SDL。 * SDL_OpenAudio(): 根據引數(儲存於SDL_AudioSpec)開啟音訊裝置。 * SDL_PauseAudio(): 播放音訊資料。 * * [迴圈播放資料] * SDL_Delay(): 延時等待播放完成。 * * This software plays PCM raw audio data using SDL2. * SDL is a wrapper of low-level API (DirectSound). * Use SDL is much easier than directly call these low-level API. * * The process is shown as follows: * * [Init] * SDL_Init(): Init SDL. * SDL_OpenAudio(): Opens the audio device with the desired * parameters (In SDL_AudioSpec). * SDL_PauseAudio(): Play Audio. * * [Loop to play data] * SDL_Delay(): Wait for completetion of playback. */ #include <stdio.h> #include <tchar.h> extern "C" { #include "sdl/SDL.h" }; //Buffer: //|-----------|-------------| //chunk-------pos---len-----| static Uint8 *audio_chunk; static Uint32 audio_len; static Uint8 *audio_pos; /* Audio Callback * The audio function callback takes the following parameters: * stream: A pointer to the audio buffer to be filled * len: The length (in bytes) of the audio buffer * */ void fill_audio(void *udata,Uint8 *stream,int len){ //SDL 2.0 SDL_memset(stream, 0, len); if(audio_len==0) /* Only play if we have data left */ return; len=(len>audio_len?audio_len:len); /* Mix as much data as possible */ SDL_MixAudio(stream,audio_pos,len,SDL_MIX_MAXVOLUME); audio_pos += len; audio_len -= len; } int main(int argc, char* argv[]) { //Init if(SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER)) { printf( "Could not initialize SDL - %s\n", SDL_GetError()); return -1; } //SDL_AudioSpec SDL_AudioSpec wanted_spec; wanted_spec.freq = 44100; wanted_spec.format = AUDIO_S16SYS; wanted_spec.channels = 2; wanted_spec.silence = 0; wanted_spec.samples = 1024; wanted_spec.callback = fill_audio; if (SDL_OpenAudio(&wanted_spec, NULL)<0){ printf("can't open audio.\n"); return -1; } FILE *fp=fopen("NocturneNo2inEflat_44.1k_s16le.pcm","rb+"); if(fp==NULL){ printf("cannot open this file\n"); return -1; } int pcm_buffer_size=4096; char *pcm_buffer=(char *)malloc(pcm_buffer_size); int data_count=0; //Play SDL_PauseAudio(0); while(1){ if (fread(pcm_buffer, 1, pcm_buffer_size, fp) != pcm_buffer_size){ // Loop fseek(fp, 0, SEEK_SET); fread(pcm_buffer, 1, pcm_buffer_size, fp); data_count=0; } printf("Now Playing %10d Bytes data.\n",data_count); data_count+=pcm_buffer_size; //Set audio buffer (PCM data) audio_chunk = (Uint8 *) pcm_buffer; //Audio buffer length audio_len =pcm_buffer_size; audio_pos = audio_chunk; while(audio_len>0)//Wait until finish SDL_Delay(1); } free(pcm_buffer); SDL_Quit(); return 0; }
執行結果
程式執行後,會讀取程式資料夾下的一個PCM取樣資料檔案,內容如下所示。接下來會將PCM資料輸出到系統的音訊裝置上(音響、耳機)。
下載
Simplest FFmpeg Audio Player
SourceForge:https://sourceforge.net/projects/simplestffmpegaudioplayer/
本程式實現了音訊的解碼和播放。是最簡單的FFmpeg音訊解碼方面的教程。
通過學習本例子可以瞭解FFmpeg的解碼流程。
專案包含3個工程:
simplest_ffmpeg_audio_player:基於FFmpeg+SDL的音訊解碼器
simplest_ffmpeg_audio_decoder:音訊解碼器。使用了libavcodec和libavformat。
simplest_audio_play_sdl2:使用SDL2播放PCM取樣資料的例子。
相關推薦
最簡單的基於FFMPEG+SDL的音訊播放器:拆分-解碼器和播放器
=====================================================最簡單的基於FFmpeg的音訊播放器系列文章列表:=====================================================本文補充記錄《
最簡單的基於FFMPEG+SDL的視訊播放器:拆分-解碼器和播放器
=====================================================最簡單的基於FFmpeg的視訊播放器系列文章列表:=====================================================本文補充記錄《
最簡單的基於FFMPEG+SDL的音訊播放器 ver2 (採用SDL2 0)
=====================================================最簡單的基於FFmpeg的音訊播放器系列文章列表:=====================================================簡介之前做過一個
100行代碼實現最簡單的基於FFMPEG+SDL的視頻播放器(SDL1.x)【轉】
工程 全屏 升級版 gin avcodec ive 系列文章 相同 hello 轉自:http://blog.csdn.net/leixiaohua1020/article/details/8652605 版權聲明:本文為博主原創文章,未經博主允許不得轉載。
100行程式碼實現最簡單的基於FFMPEG+SDL的視訊播放器(SDL1.x)
=====================================================最簡單的基於FFmpeg的視訊播放器系列文章列表:=====================================================簡介FFMPEG
最簡單的基於FFMPEG+SDL的視訊播放器 ver2 (採用SDL2.0
=====================================================最簡單的基於FFmpeg的視訊播放器系列文章列表:=====================================================簡介之前做過一個
最簡單的基於FFMPEG+SDL的音視訊播放器
一、概述 在《最簡單的基於FFMPEG+SDL的音訊播放器》記錄一中,我們實現了音訊的播放。更早前,我們在《最簡單的基於FFMPEG+SDL的視訊播放器》記錄一和二中,實現了視訊的播放。在實現視訊播放的時候,我們設定了一個延遲40ms,否則視訊就會以解碼的速
XCode版【100行程式碼實現最簡單的基於FFMPEG+SDL的視訊播放器】
【來自】 1.新建XCode工程後,發現即使安裝了SDL和FFMPEG也編譯不成功,需要修改各種環境。經過我的不懈努力加百穀啥的...貼個能編譯通過的過程出來。謹記! 2.首先需要編譯好ffmpeg原始碼,然後還需要安裝SDL(ffmpeg直接編譯,SDL我是通過brew安
最簡單的基於FFMPEG的音訊編碼器(PCM編碼為AAC
本文介紹一個最簡單的基於FFMPEG的音訊編碼器。該編碼器實現了PCM音訊取樣資料編碼為AAC的壓縮編碼資料。編碼器程式碼十分簡單,但是每一行程式碼都很重要。通過看本編碼器的原始碼,可以瞭解FFMPEG音訊編碼的流程。本程式使用最新版的類庫(編譯時間為2014.5.6),開發平
最簡單的基於FFmpeg的封裝格式處理:視音訊分離器簡化版(demuxer-simple)
=====================================================最簡單的基於FFmpeg的封裝格式處理系列文章列表:=====================================================簡介打算記錄
史上最全的基於ffmpeg+sdl網路攝像頭編解碼播放資料(包含交叉編譯過程,附帶完整原始碼)
原創博文,嚴禁私自轉載,轉載請註明出處!!! 近期,由於工作需要,要在開發板上跑一個攝像頭,攝像頭款式比較老,不支援rtsp格式,所以選擇編譯ffmpeg+sdl實現軟解碼播放攝像頭,特此記錄整個編譯過程(非常之艱辛,發文留念) 在ubuntu上交叉編譯環境的搭建:因為開發板上搭建的程式的執
《基於 FFmpeg + SDL 的視訊播放器的製作》課程的視訊
這兩天開始帶廣播電視工程大二的暑假小學期的課程設計了。本次小學期課程內容為《基於 FFmpeg + SDL 的視訊播放器的製作》,其中主要講述了視音訊開發的入門知識。由於感覺本課程的內容不但適合本科生,而且也比較適合無視音訊基礎的開發者入門使用,所以在講課的同時也錄製了一部分
最簡單的基於FFmpeg的移動端例子:Android 視訊轉碼器
=====================================================最簡單的基於FFmpeg的移動端例子系列文章列表:=====================================================本文記錄一個安
最簡單的基於FFmpeg的移動端例子:IOS HelloWorld
=====================================================最簡單的基於FFmpeg的移動端例子系列文章列表:=====================================================本文記錄IOS
基於FFMPEG的音訊編碼器
編碼模組 編碼模組是編碼存放在FIFO中的資料,然後udp輸出,具體的資料流向圖如下: 編碼模組資料流向圖 編碼前,為32位雙聲道48KHz的PCM資料,因為ffmpeg MP2編碼器所支援的PCM資料為16位,所以需要PCM重取樣。
4.基於FFMPEG將音訊解碼為PCM
繼續FFMPEG學習之路,前面瞭解了將PCM編碼為AAC檔案,接下來則需要了解一下解碼方面,將MP3/AAC等音訊格式解碼為PCM資料,記錄一下過程。。。 1)解碼流程 整個解碼流程採用虛擬碼大致如下: 初始化複用器和解複用器—>獲取輸入檔案的一些資訊—->查詢解碼器
最簡單的基於Flash的流媒體示例:RTMP推送和接收(ActionScript)
=====================================================Flash流媒體文章列表:=====================================================本文記錄一些基於Flash的流媒體處理
史上最簡單的SpringCloud教程 | 第二篇: 服務消費者(rest+ribbon)
image tree 開啟 then rom cat learn 替代 官網 最新Finchley版本:https://www.fangzhipeng.com/springcloud/2018/08/30/sc-f2-ribbon/或者http://blog.csdn.n
史上最簡單的 SpringCloud 教程 | 第一篇: 服務的註冊與發現(Eureka)
add 過程 sdn 需要 2.3 boot one ini tail 最新Finchley版本請訪問:https://www.fangzhipeng.com/springcloud/2018/08/30/sc-f1-eureka/或者http://blog.csdn.n
最簡單解決Python安裝拓展包問題:unable to find vcvarsall.bat
一、問題描述 (1)、 電腦配置資訊: win7系統 TMD GCC Python3.5.x (2)使用pip命令安裝mysqlclient時報錯 error:unable to find vcvarsall.bat 我的電腦上安裝了TMD GCC但