/*
*最简单的录音程序
*缪国凯 MK
*[email protected]
*本程序实现采集麦克风音频数据,压制为aac
*2015-6-19
*/
#include "stdafx.h"
#include
#include
#include
#pragma comment(lib,"Strmiids")
#pragma comment(lib,"comsuppw.lib")
#include
#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; inb_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;
}
http://download.csdn.net/detail/dancing_night/8822669
注:4.xffmpeg版本的录音程序请移步至 https://blog.csdn.net/dancing_night/article/details/84253764