基本方法就是在原有的推流代碼基礎上(比如rtmp推流的代碼),修改打開輸入設備的代碼改爲如下類似的代碼,調整一下源文件的變量等設置,就可以實現了:
//輸入(Input)
// if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
// printf( "Could not open input file.");
// goto end;
// }
// if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
// printf( "Failed to retrieve input stream information");
// goto end;
// }
//
// int videoindex=-1;
// for(i=0; i<ifmt_ctx->nb_streams; i++)
// if(ifmt_ctx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO){
// videoindex=i;
// break;
// }
//
// av_dump_format(ifmt_ctx, 0, in_filename, 0);
//查找輸入方式
pAudioInputFmt =av_find_input_format("dshow");
//以Direct Show<pAudioInputFmt>的方式打開設備psDevName,並將 輸入方式 關聯到格式上下文pFmtCtx
// 函數的各個參數:
// 1、AVFormatContext **ps:指向用戶提供的結構體,一般可以將這個參數定義指向空然後傳遞到函數中,這樣avformat_open_input函數將會分配這個結構體的內存空間並初始化。
// 2、const char *filename:打開視頻文件的文件名。
// 3、AVInputFormat *fmt:如果這個參數不爲空,則指定固定的輸入格式,否則自動檢測輸入格式;一般設爲空即可。
// 4、AVDictionary **options:由AVFormatContext和demuxer-private options組成的字典結構,可設爲空。
char * psDevName = dup_wchar_to_utf8(L"audio=麥克風 (Realtek High Definition Au");
assert(avformat_open_input(&pFmtCtx,psDevName,pAudioInputFmt,NULL) == 0);
//該函數可以讀取一部分視音頻數據並且獲得一些相關的信息
// avformat_find_stream_info()代碼比較長,難以全部分析,在這裏只能簡單記錄一下它的要點。
// 該函數主要用於給每個媒體流(音頻/視頻)的AVStream結構體賦值。
// 我們大致瀏覽一下這個函數的代碼,會發現它其實已經實現瞭解碼器的查找,解碼器的打開,
// 視音頻幀的讀取,視音頻幀的解碼等工作。換句話說,該函數實際上已經“走通”的解碼的整個流程。
// 下面看一下除了成員變量賦值之外,該函數的幾個關鍵流程。
// 1.查找解碼器:find_decoder()
// 2.打開解碼器:avcodec_open2()
// 3.讀取完整的一幀壓縮編碼的數據:read_frame_internal()
// 注:av_read_frame()內部實際上就是調用的read_frame_internal()。
// 4.解碼一些壓縮編碼數據:try_decode_frame()
AVDictionary* pOptions = NULL;
pFmtCtx->probesize = 1 *1024;
pFmtCtx->max_analyze_duration = 1 * AV_TIME_BASE;
// Retrieve stream information
if(avformat_find_stream_info(pFmtCtx,&pOptions)<0)
{
printf("Couldn't find stream information.\n");
return -1;
}
// if(avformat_find_stream_info(pFmtCtx,NULL)<0)
// return -1;
for(int i=0; i<pFmtCtx->nb_streams; i++)
{
if(pFmtCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO)
{
iAudioIndex=i;
//用於查找FFmpeg的解碼器<音頻>。
AVCodec *tmpCodec = avcodec_find_decoder(pFmtCtx->streams[i]->codec->codec_id);
// 我們可以簡單梳理一下avcodec_open2()所做的工作,如下所列:
// (1)爲各種結構體分配內存(通過各種av_malloc()實現)。
// (2)將輸入的AVDictionary形式的選項設置到AVCodecContext。
// (3)其他一些零零碎碎的檢查,比如說檢查編解碼器是否處於“實驗”階段。
// (4)如果是編碼器,檢查輸入參數是否符合編碼器的要求
// (5)調用AVCodec的init()初始化具體的解碼器。
if(0 > avcodec_open2(pFmtCtx->streams[i]->codec, tmpCodec, NULL))//打開解碼器<音頻>//打開麥克風錄音
{
printf("can not find or open decoder!\n");
}
break;
}
}
// * Print detailed information about the input or output format, such as
// * duration, bitrate, streams, container, programs, metadata, side data,
// * codec and time base.
// * @param ic the context to analyze
// * @param index index of the stream to dump information about
// * @param url the URL to print, such as source or destination file
// * @param is_output Select whether the specified context is an input(0) or output(1)
av_dump_format(pFmtCtx, 0, NULL, 0);