概述
1、最近一网友找到我,说我博客上的录音程序用不起了,研究一番发现是他用我代码然后链接ffmpeg库。发现版本改动还挺大,故此从新上传一份依赖最新版本的ffmpeg的录音程序,以便大家参考。
2、直接上代码:
/*
*最简单的录音
*缪国凯 Mickel
*821486004@qq.com
*本程序用目前最新ffmpeg录音
*2018-11-19
*/
#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"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.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
typedef struct FilteringContext
{
AVFilterContext *buffersink_ctx;
AVFilterContext *buffersrc_ctx;
AVFilterGraph *filter_graph;
} FilteringContext;
_bstr_t strDeviceName;
FilteringContext *filter_ctx = NULL;
static char *dup_wchar_to_utf8(wchar_t *w);
static int init_filter(FilteringContext* fctx, AVCodecContext *dec_ctx,
AVCodecContext *enc_ctx, const char *filter_spec)
{
char args[512];
int ret = 0;
const AVFilter *buffersrc = NULL;
const AVFilter *buffersink = NULL;
AVFilterContext *buffersrc_ctx = NULL;
AVFilterContext *buffersink_ctx = NULL;
AVFilterInOut *outputs = avfilter_inout_alloc();
AVFilterInOut *inputs = avfilter_inout_alloc();
AVFilterGraph *filter_graph = avfilter_graph_alloc();
if (!outputs || !inputs || !filter_graph)
{
ret = AVERROR(ENOMEM);
goto end;
}
if (dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO)
{
buffersrc = avfilter_get_by_name("abuffer");
buffersink = avfilter_get_by_name("abuffersink");
if (!buffersrc || !buffersink)
{
av_log(NULL, AV_LOG_ERROR, "filtering source or sink element not foundn");
ret = AVERROR_UNKNOWN;
goto end;
}
if (!dec_ctx->channel_layout)
dec_ctx->channel_layout = av_get_default_channel_layout(dec_ctx->channels);
//format args
_snprintf(args, sizeof(args),
"time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x",
dec_ctx->time_base.num, dec_ctx->time_base.den, dec_ctx->sample_rate,
av_get_sample_fmt_name(dec_ctx->sample_fmt),
dec_ctx->channel_layout);
ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", args, NULL, filter_graph);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sourcen");
goto end;
}
// char args1[512];
// _snprintf(args1, sizeof(args1),
// "sample_rates=%d:sample_fmts=%s:channel_layouts=0x%I64x",
// (uint8_t)enc_ctx->sample_rate, (uint8_t)enc_ctx->sample_fmt,
// (uint8_t)enc_ctx->channel_layout);
ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", NULL, NULL, filter_graph);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sinkn");
goto end;
}
ret = av_opt_set_bin(buffersink_ctx, "sample_fmts", (uint8_t*)&enc_ctx->sample_fmt,
sizeof(enc_ctx->sample_fmt), AV_OPT_SEARCH_CHILDREN);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "Cannot set output sample formatn");
goto end;
}
ret = av_opt_set_bin(buffersink_ctx, "channel_layouts", (uint8_t*)&enc_ctx->channel_layout,
sizeof(enc_ctx->channel_layout), AV_OPT_SEARCH_CHILDREN);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layoutn");
goto end;
}
ret = av_opt_set_bin(buffersink_ctx, "sample_rates", (uint8_t*)&enc_ctx->sample_rate,
sizeof(enc_ctx->sample_rate), AV_OPT_SEARCH_CHILDREN);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "Cannot set output sample raten");
goto end;
}
}
else
{
ret = AVERROR_UNKNOWN;
goto end;
}
/* Endpoints for the filter graph. */
outputs->name = av_strdup("in");
outputs->filter_ctx = buffersrc_ctx;
outputs->pad_idx = 0;
outputs->next = NULL;
inputs->name = av_strdup("out");
inputs->filter_ctx = buffersink_ctx;
inputs->pad_idx = 0;
inputs->next = NULL;
if (!outputs->name || !inputs->name)
{
ret = AVERROR(ENOMEM);
goto end;
}
if ((ret = avfilter_graph_parse_ptr(filter_graph, filter_spec, &inputs, &outputs, NULL)) < 0)
goto end;
if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
goto end;
/* Fill FilteringContext */
fctx->buffersrc_ctx = buffersrc_ctx;
fctx->buffersink_ctx = buffersink_ctx;
fctx->filter_graph = filter_graph;
end:
avfilter_inout_free(&inputs);
avfilter_inout_free(&outputs);
return ret;
}
int init_filters(AVCodecContext *inCodecContext, AVCodecContext *outCodecContext)
{
const char *filter_spec = "anull";
unsigned int i;
int ret;
filter_ctx = (FilteringContext *)av_malloc_array(1, sizeof(*filter_ctx));
if (!filter_ctx)
return AVERROR(ENOMEM);
ret = init_filter(&filter_ctx[0], inCodecContext, outCodecContext, filter_spec);
return ret;
}
int main()
{
AVFormatContext * pFmtInputCtx = NULL, *ofmt_ctx_a = NULL;
AVInputFormat * pAudioInputFmt = NULL;
AVOutputFormat * pAudioOutputFmt = NULL;
AVStream * pOutAudioStream = 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(&pFmtInputCtx, psDevName, pAudioInputFmt, NULL) == 0);
// avformat_find_stream_info(pFmtCtx,NULL);
if (avformat_find_stream_info(pFmtInputCtx, NULL) < 0)
return -1;
for (int i = 0; i < pFmtInputCtx->nb_streams; i++)
{
if (pFmtInputCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
{
pInputCodecCtx = avcodec_alloc_context3(NULL);
if (avcodec_parameters_to_context(pInputCodecCtx, pFmtInputCtx->streams[i]->codecpar) < 0)
{
printf("Copy stream failed!n");
return -1;
}
iAudioIndex = i;
AVCodec *tmpCodec = avcodec_find_decoder(pInputCodecCtx->codec_id);
if (0 > avcodec_open2(pInputCodecCtx, tmpCodec, NULL))
{
printf("can not find or open decoder!n");
}
break;
}
}
av_dump_format(pFmtInputCtx, 0, NULL, 0);
// pAudioOutputFmt = av_find_output_format("dshow");
// assert(pAudioOutputFmt != NULL);
// av_register_output_format(pAudioOutputFmt);
avformat_alloc_output_context2(&ofmt_ctx_a, NULL, NULL, "abc.aac");
pOutAudioStream = avformat_new_stream(ofmt_ctx_a, NULL);
AVCodec *audioEnCoder = avcodec_find_encoder(ofmt_ctx_a->oformat->audio_codec);
pOutputCodecCtx = avcodec_alloc_context3(audioEnCoder);
pOutputCodecCtx->sample_rate = pInputCodecCtx->sample_rate;
pOutputCodecCtx->channel_layout = pOutputCodecCtx->channel_layout;
pOutputCodecCtx->channels = av_get_channel_layout_nb_channels(pOutputCodecCtx->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 = pOutputCodecCtx->codec->sample_fmts[0];
AVRational time_base = { 1, pOutputCodecCtx->sample_rate };
pOutputCodecCtx->time_base = time_base;
//audioCodecCtx->time_base = time_base;
pOutputCodecCtx->codec_tag = 0;
if (ofmt_ctx_a->oformat->flags & AVFMT_GLOBALHEADER)
pOutputCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
if (avcodec_open2(pOutputCodecCtx, pOutputCodecCtx->codec, 0) < 0)
{
//编码器打开失败,退出程序
return -1;
}
int ret = avcodec_parameters_from_context(pOutAudioStream->codecpar, pOutputCodecCtx);
if (ret < 0)
{
printf("Failed to copy encoder parameters to output stream #%un");
return ret;
}
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");
return -1;
}
}
if (avformat_write_header(ofmt_ctx_a, NULL) < 0)
{
printf("Error occurred when opening audio output filen");
return -1;
}
if ((ret = init_filters(pInputCodecCtx, pOutputCodecCtx)) < 0)
{
printf("init_filters failedn");
return -1;
}
AVPacket pkt, pkt_out;
// FILE * fp = fopen("C:\Users\jk\Desktop\abc","wb+");
// assert(fp != NULL);
AVFrame *frame = av_frame_alloc();
AVAudioFifo *fifo = NULL;
fifo = av_audio_fifo_alloc(pOutputCodecCtx->sample_fmt, pOutputCodecCtx->channels, 1);
int frameIndex = 0;
char errbuf[256] = { 0 };
while (av_read_frame(pFmtInputCtx, &pkt) == 0 && _kbhit() == 0)
{
pkt_out.data = NULL;
pkt_out.size = 0;
pkt_out.stream_index = pkt.stream_index;
int iRes;
if ((iRes = avcodec_send_packet(pInputCodecCtx, &pkt)) != 0)
{
printf("Send video stream packet failed!n");
av_strerror(iRes, errbuf, 256);
continue;
}
if ((iRes = avcodec_receive_frame(pInputCodecCtx, frame)) != 0)
{
printf("Receive video frame failed!n");
av_strerror(iRes, errbuf, 256);
continue;
}
av_packet_unref(&pkt);
//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);
}
continue;
}
AVFrame *filter_frame;
if (pInputCodecCtx->sample_fmt != pOutputCodecCtx->sample_fmt
|| pInputCodecCtx->channels != pOutputCodecCtx->channels
|| pInputCodecCtx->sample_rate != pOutputCodecCtx->sample_rate)
{
filter_frame = av_frame_alloc();
ret = av_buffersrc_add_frame_flags(filter_ctx[0].buffersrc_ctx, frame, 0);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "Error while feeding the filtergraphn");
continue;
}
ret = av_buffersink_get_frame(filter_ctx[0].buffersink_ctx, filter_frame);
if (ret < 0)
{
/* if no more frames for output - returns AVERROR(EAGAIN)
* if flushed and no more frames for output - returns AVERROR_EOF
* rewrite retcode to 0 to show it as normal procedure completion
*/
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
ret = 0;
av_frame_free(&filter_frame);
continue;
}
}
else
{
filter_frame = frame;
}
int tmpSize = av_audio_fifo_size(fifo);
int tmpSpace = av_audio_fifo_space(fifo);
//av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + filter_frame->nb_samples);
av_audio_fifo_write(fifo, (void **)filter_frame->data, filter_frame->nb_samples);
if (filter_frame != frame)
{
av_frame_free(&filter_frame);
}
tmpSize = av_audio_fifo_size(fifo);
tmpSpace = av_audio_fifo_space(fifo);
//循环读取数据,直到buf里数据采样数不够
while (av_audio_fifo_size(fifo) >= (pOutputCodecCtx->frame_size > 0 ? pOutputCodecCtx->frame_size : 1024))
{
AVFrame *frameInput = av_frame_alloc();
frameInput->nb_samples = pOutputCodecCtx->frame_size > 0 ? pOutputCodecCtx->frame_size : 1024;
frameInput->channel_layout = pOutputCodecCtx->channel_layout;
frameInput->format = pOutputCodecCtx->sample_fmt;
frameInput->sample_rate = pOutputCodecCtx->sample_rate;
av_frame_get_buffer(frameInput, 0);
av_audio_fifo_read(fifo, (void **)frameInput->data, (pOutputCodecCtx->frame_size > 0 ? pOutputCodecCtx->frame_size : 1024));
ret = avcodec_send_frame(pOutputCodecCtx, frameInput);
if (ret < 0)
{
fprintf(stderr, "Error sending a frame for encodingn");
continue;
}
av_frame_free(&frameInput);
while (ret >= 0)
{
av_init_packet(&pkt_out);
ret = avcodec_receive_packet(pOutputCodecCtx, &pkt_out);
if (ret != 0)
{
continue;
}
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);
av_packet_unref(&pkt_out);
frameIndex++;
}
}
}
av_frame_free(&frame);
av_write_trailer(ofmt_ctx_a);
avio_close(ofmt_ctx_a->pb);
avformat_free_context(ofmt_ctx_a);
//解初始化
if (pFmtInputCtx != NULL)
{
avformat_close_input(&pFmtInputCtx);
pFmtInputCtx = 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、工程地址:
https://download.csdn.net/download/dancing_night/10793816
4、老版本录音程序链接:
https://blog.csdn.net/dancing_night/article/details/46561909
最后
以上就是简单蜡烛为你收集整理的ffmpeg4.x版本录音的全部内容,希望文章能够帮你解决ffmpeg4.x版本录音所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复