1. 程式人生 > >用ffmpeg實現錄音

用ffmpeg實現錄音

1、概述

2、程式碼

/*
*最簡單的錄音程式
*繆國凱 MK
*[email protected]
*本程式實現採集麥克風音訊資料,壓制為aac
*2015-6-19
*/


#include "stdafx.h"
#include <windows.h>
#include <DShow.h>
#include <comutil.h>
#pragma comment(lib,"Strmiids")
#pragma comment(lib,"comsuppw.lib")
#include <conio.h>
#pragma comment(lib,"winmm")
#define	SAFE_RELEASE(x)	{if(x != NULL) x->Release();x=NULL;}

#ifdef __cplusplus
extern "C"
{
#endif
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavdevice/avdevice.h"
#include "libavutil/audio_fifo.h"

#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "avdevice.lib")
#pragma comment(lib, "avfilter.lib")
//#pragma comment(lib, "postproc.lib")
//#pragma comment(lib, "swresample.lib")
//#pragma comment(lib, "swscale.lib")
#ifdef __cplusplus
};
#endif

_bstr_t	strDeviceName;

static char *dup_wchar_to_utf8(wchar_t *w);

int _tmain(int argc, _TCHAR* argv[])
{
	AVFormatContext		*	pFmtCtx = NULL, *ofmt_ctx_a = NULL;
	AVInputFormat		*	pAudioInputFmt = NULL;
	AVOutputFormat		*	pAudioOutputFmt = NULL;
	AVStream			*	pAudioStream = NULL;
	AVCodecContext		*	pOutputCodecCtx = NULL;
	AVCodecContext		*	pInputCodecCtx = NULL;
	AVCodec				*	pCodec = NULL;
	AVFrame				*	pAudioFrame = NULL;
	uint8_t				*	pFrameBuffer = NULL;
	int						iAudioIndex = -1;
	//註冊FFMPEG庫
	av_register_all();
	avdevice_register_all();
	
	//查詢輸入方式
	pAudioInputFmt =av_find_input_format("dshow");
	assert(pAudioInputFmt != NULL);
	//以Direct Show的方式開啟裝置,並將 輸入方式 關聯到格式上下文
	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(pFmtCtx,NULL);

	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;
			AVCodec *tmpCodec = avcodec_find_decoder(pFmtCtx->streams[i]->codec->codec_id);
			if(0 > avcodec_open2(pFmtCtx->streams[i]->codec, tmpCodec, NULL))
			{
				printf("can not find or open decoder!\n");
			}

			break;
		}
	}

	av_dump_format(pFmtCtx, 0, NULL, 0);



	avformat_alloc_output_context2(&ofmt_ctx_a, NULL, NULL, "abc.aac");
	
	pAudioStream = avformat_new_stream(ofmt_ctx_a, NULL);
	pAudioStream->codec->codec = avcodec_find_encoder(ofmt_ctx_a->oformat->audio_codec);

	pOutputCodecCtx = pAudioStream->codec;

	pOutputCodecCtx->sample_rate = pFmtCtx->streams[0]->codec->sample_rate;
	pOutputCodecCtx->channel_layout = ofmt_ctx_a->streams[0]->codec->channel_layout;
	pOutputCodecCtx->channels = av_get_channel_layout_nb_channels(pAudioStream->codec->channel_layout);
	if(pOutputCodecCtx->channel_layout == 0)
	{
		pOutputCodecCtx->channel_layout = AV_CH_LAYOUT_STEREO;
		pOutputCodecCtx->channels = av_get_channel_layout_nb_channels(pOutputCodecCtx->channel_layout);

	}
	pOutputCodecCtx->sample_fmt = pAudioStream->codec->codec->sample_fmts[0];
	AVRational time_base={1, pAudioStream->codec->sample_rate};
	ofmt_ctx_a->streams[0]->time_base = time_base;
	//audioCodecCtx->time_base = time_base;

	pOutputCodecCtx->codec_tag = 0;  
	if (ofmt_ctx_a->oformat->flags & AVFMT_GLOBALHEADER)  
		pOutputCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;

	if (avcodec_open2(pOutputCodecCtx, pOutputCodecCtx->codec, 0) < 0)
	{
		//編碼器開啟失敗,退出程式
		exit(0);
	}

	if (!(ofmt_ctx_a->oformat->flags & AVFMT_NOFILE))
	{  
		if (avio_open(&ofmt_ctx_a->pb, "abc.aac", AVIO_FLAG_WRITE) < 0) 
		{  
			printf( "Could not open output file abc.aac"); 
		}  
	}

	if (avformat_write_header(ofmt_ctx_a, NULL) < 0)
	{  
		printf( "Error occurred when opening audio output file\n");   
	}


	AVPacket pkt, pkt_out;

// 	FILE * fp = fopen("C:\\Users\\jk\\Desktop\\abc","wb+");
// 	assert(fp != NULL);
	AVFrame *frame;
	AVAudioFifo *fifo = NULL;
	fifo = av_audio_fifo_alloc(pOutputCodecCtx->sample_fmt,pOutputCodecCtx->channels,1);
	int frameIndex = 0;
	
	while (av_read_frame(pFmtCtx,&pkt) == 0 && _kbhit()==0)
	{
		int gotframe = -1;

		frame = av_frame_alloc();
		if (avcodec_decode_audio4(pFmtCtx->streams[iAudioIndex]->codec, frame, &gotframe, &pkt) < 0)
		{
			av_frame_free(&frame);
			printf("can not decoder a frame");
			break;
		}
		av_free_packet(&pkt);

		if (!gotframe)
		{
			continue;//沒有獲取到資料,繼續下一次
		}

		//test write pcm
		if(0)
		{
			FILE *p = NULL;
			p = fopen("test.pcm", "a+b");
			int tempLenght = 2 * frame->nb_samples;//由於實驗中知道這是16位深,所以才這麼寫
			uint8_t *tmpPtr = frame->data[0];
			if (NULL != p)
			{
				while(tempLenght > 0)
				{
					size_t temp = fwrite(tmpPtr, 1, tempLenght, p);
					tmpPtr+= temp;
					tempLenght = tempLenght - temp;
				}				
				fclose(p);
			}			
		}

		if (pFmtCtx->streams[iAudioIndex]->codec->sample_fmt != pOutputCodecCtx->sample_fmt 
			|| pFmtCtx->streams[iAudioIndex]->codec->channels != pOutputCodecCtx->channels 
			|| pFmtCtx->streams[iAudioIndex]->codec->sample_rate != pOutputCodecCtx->sample_rate)
		{
			//如果輸入和輸出的音訊格式不一樣 需要重取樣,這裡是一樣的就沒做
		}

		av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + frame->nb_samples);

		av_audio_fifo_write(fifo, (void **)frame->data, frame->nb_samples);

		//迴圈讀取資料,直到buf裡資料取樣數不夠
		while(av_audio_fifo_size(fifo) >= (pOutputCodecCtx->frame_size > 0 ? pOutputCodecCtx->frame_size : 1024))
		{
			av_frame_free(&frame);
			frame = av_frame_alloc();
			frame->nb_samples = pOutputCodecCtx->frame_size>0 ? pOutputCodecCtx->frame_size: 1024;
			frame->channel_layout = pOutputCodecCtx->channel_layout;
			frame->format = pOutputCodecCtx->sample_fmt;
			frame->sample_rate = pOutputCodecCtx->sample_rate;
			av_frame_get_buffer(frame, 0);

			av_audio_fifo_read(fifo, (void **)frame->data, (pOutputCodecCtx->frame_size > 0 ? pOutputCodecCtx->frame_size : 1024));
			av_init_packet(&pkt_out);
			//frame->pts = pFrame->pts;
			int got_picture = -1;
			pkt_out.data = NULL;
			pkt_out.size = 0;			
			if (avcodec_encode_audio2(pOutputCodecCtx, &pkt_out, frame, &got_picture) < 0)
			{
				printf("can not decoder a frame");			
			}
			av_frame_free(&frame);
			if (got_picture) 
			{
				pkt_out.pts = frameIndex * pOutputCodecCtx->frame_size;
				pkt_out.dts = frameIndex * pOutputCodecCtx->frame_size;
				pkt_out.duration = pOutputCodecCtx->frame_size;
				av_write_frame(ofmt_ctx_a, &pkt_out);
				frameIndex++;
			}
		}
	}


	av_write_trailer(ofmt_ctx_a);

	avio_close(ofmt_ctx_a->pb);
	avformat_free_context(ofmt_ctx_a);
	

	//解初始化
	if (pFmtCtx != NULL)
	{
		avformat_close_input(&pFmtCtx);
		pFmtCtx = NULL;
	}
	return 0;
}

static char *dup_wchar_to_utf8(wchar_t *w)
{
	char *s = NULL;
	int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
	s = (char *) av_malloc(l);
	if (s)
		WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
	return s;
}

3、工程下載地址

http://download.csdn.net/detail/dancing_night/8822669

相關推薦

ffmpeg實現錄音

1、概述 2、程式碼 /* *最簡單的錄音程式 *繆國凱 MK *[email protected] *本程式實現採集麥克風音訊資料,壓制為aac *2015-6-19 */ #include "stdafx.h" #include <windows.

ffmpeg 實現批量剪下視訊

一直對編輯視訊很有興趣,上大學的時候學了一些視訊剪輯的軟體,已經好久沒用了,現在也都忘的差不多了。前段時間弄了個頭條號,想發一些視訊,就又想做視訊這回事了,要不還真快忘記自己曾經做過一些小視訊了(捂臉)。其實現在想要做的視訊,不需要做很多特效,也不需要做配字幕等這些內容,所以不是很難,但

FFmpeg總結(十二)ffmpeg與nginx實現直播多路流並發播放

xxx 開源 conf ref itl rect arc med rtm 圖:撒哈拉沙漠 下載 nginx 和 nginx-rtmp源碼: http://nginx.org/download/nginx-1.5.10.tar.gz https://github.com/a

ffmpeg和SDL2實現linux player

rec null sizeof open type error yuv text idt 一、version 1#include <stdio.h> #include <libavcodec/avcodec.h> #include <lib

speech_recognition實現錄音ffmpeg實現音訊檔案轉換,並用百度語音的sdk實現語音識別

專案說明: 在windows平臺下,使用speech_recognition記錄音訊,並轉換為16k的wav, 之後利用ffmpeg將wav轉化為pcm檔案,上傳到百度語音端,返回語音資訊,並利用pyttsx3添加了簡單的互動功能。 需求模組: speech_recognit

ffmpeg+nginx+海康威視網路攝像頭rtsp在手機端和電腦端實現直播

原料:海康威視攝像頭,nginx伺服器,ffmpeg。首先海康威視攝像頭,它的rtsp資料流的地址為:rtsp://[username]:[password]@[ip]:[port]/[codec]/[channel]/[subtype]/av_stream說明:userna

FFmpeg總結(十三)ffmpeg基於nginx實現直播功能,不用第三方SDK,自研推流拉流

直播app實現流程 1.採集 2.濾鏡處理 3.編碼 4.推流 5.CDN分發 6.拉流 7.解碼 8.播放 9.聊天互動 影象格式: public static final int DEPTH16 = 11444022

ffmpeg程式碼實現自己的muxer

1、概述 本程式碼實現了一個muxer並加入到ffmpeg的AVOutputFormat 連結串列中去,使程式碼能直接呼叫。實現的意義一是瞭解ffmpeg程式碼結構,二是可以自己整自己的視訊格式,讓別人播放不了。 2、程式碼 簡單看下程式碼: /* *本程式主要實現一個自

FFmpeg實現錄屏+錄音

1、概述最簡單的基於FFmpeg的AVDevice例子(螢幕錄製+聲音採集),視訊採用mpeg4編碼,音訊採用aac編碼,並生成mp4檔案,其中fifo是此程式的關鍵,此程式只是一個demo很多優化都沒做,僅供參考。2、程式碼<pre name="code"class=

FFmpeg總結(十二)ffmpeg與nginx實現直播多路流併發播放

編譯安裝: cd nginx-1.5.10 ./configure –with-http_ssl_module –add-module=../nginx-rtmp-module-master make make install 瀏覽器輸入loc

Drawable 實現Android UI 元素間距效果

purple 固定 展示 .com otto 技巧 log contain dev 源文地址: 巧用Drawable 實現Android UI 元素間距效果 在大部分的移動UI或者Web UI都是基於網格概念而設計的。這種網格一般都是有一些對其的方塊組成,然後

JS調命令實現F11全屏

return ima logs key f11全屏 嘗試 ges div 500px <body onload =‘autoSetFull()‘> <button id=‘btn‘>全屏按鈕</button> <div

C++實現約瑟夫環的問題

content 人在 -h tel padding next family bsp sun 約瑟夫問題是個有名的問題:N個人圍成一圈。從第一個開始報數,第M個將被殺掉,最後剩下一個,其余人都將被殺掉。比如N=6,M=5。被殺掉的人的序號為5,4,6。2。3。最後剩下1

Android調相機實現拍照並裁剪圖片,調手機中的相冊圖片並裁剪圖片

!= findview create 圖片剪裁 顯示 parent 學會 true mfile 在 Android應用中,非常多時候我們須要實現上傳圖片,或者直接調用手機上的拍照功能拍照處理然後直接顯示並上傳功能,以下將講述調用相機拍照處理圖片然後顯示和調用手機相冊中的

init.rc文件中面啟動c++程序,通過jni調java實現

mini val sni ril urn runtime sport mco env </pre><p>註:假設是自己的myself.jar包,還要修改例如以下:</p><p>target/product/core_bas

C# tabcontrol實現窗體類似網頁排版的顯示

code star tar 做的 ide 切換 drop rri all 這裏做的比較簡陋,可以美化下 吧form設置位非頂級控件,直接放在tabcontro裏邊,然後實現tabcontrol的拖拽移除tabpage顯示form以及添加tabpage mousemove的觸

NIO實現http協議

his 開發 非阻塞 etl 必須 操作 nts blocking this 先來看一下本篇博文的目錄: 一:簡介Nio 二:Nio的好處 三:關於http協議 四:代碼實現 五:總結 一:簡介Nio 我們都知道io流,那麽NIO是什麽呢?本篇博文將會帶你一探NIO,NIO

再談java實現Smtp發送郵件之Socket編程

~~ 成功 剛才 還要 登陸 computer and ont sys 很多其它內容歡迎訪問個人站點 http://icodeyou.com 前幾天利用Socket實現了用java語言搭建webserver,全程下來應該會對Socket這

多級聯動系列——ajax調XML實現三級聯動

title div sdn 選擇器 class var () doc img ajax 使用起來特別的方便,再也不操心瀏覽器兼容問題了。用ajax調用XML頁面中的內容,來生成三級聯動,OK廢話不多說,跟著我一步步寫吧。 首先寫一個XML文件。data.xml <

shell實現打印600-700 之間的偶數

shell#!/bin/bash for i in {600..700} do count=`expr $i % 2` if [ $count -eq 0 ] then out="$out $i" fi done echo $out本文出自 “luosea” 博客,請務必保留此出處http://luosea