ffmpeg 音频转码
大多数厂家摄像机输出的音频流格式都是PCM,有一些场合(比如讲音视频流保存成Ts流)需要将PCM格式转成AAC格式。基本的思路是先解码得到音频帧,再将音频帧编码成AAC格式。编码和解码之间需要添加一个filter。filter起到适配的作用。
首先解码:
AVFrame * decode(AVPacket* sample)
{
int gotframe = ;
AVFrame* frame = av_frame_alloc();
AVFrame *filt_frame = nullptr;
auto length = avcodec_decode_audio4(decoderContext, frame, &gotframe, sample);
frame->pts = frame->pkt_pts;
if(length >= && gotframe != )
{
if (av_buffersrc_add_frame_flags(buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_PUSH) < ) {
av_log(NULL, AV_LOG_ERROR, "Error while feeding the audio filtergraph\n");
av_frame_free(&frame);
return nullptr;
}
frame->pts = AV_NOPTS_VALUE; /* pull filtered audio from the filtergraph */
filt_frame = av_frame_alloc();
while () {
int ret = av_buffersink_get_frame_flags(buffersink_ctx, filt_frame, AV_BUFFERSINK_FLAG_NO_REQUEST);
if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
break;
if(ret < )
{
av_frame_free(&frame);
av_frame_free(&filt_frame);
return nullptr;
} int64_t frame_pts = AV_NOPTS_VALUE;
if (filt_frame->pts != AV_NOPTS_VALUE) {
startTime = (startTime == AV_NOPTS_VALUE) ? : startTime;
AVRational av_time_base_q;
av_time_base_q.num = ;
av_time_base_q.den = AV_TIME_BASE;
filt_frame->pts = frame_pts =
av_rescale_q(filt_frame->pts, buffersink_ctx->inputs[]->time_base, encoderContext->time_base)
- av_rescale_q(startTime, av_time_base_q, encoderContext->time_base);
}
av_frame_free(&frame);
return filt_frame;
}
}
av_frame_free(&filt_frame);
av_frame_free(&frame);
return nullptr;
}
decode 得到AVFrame 也即音频帧,这个frame是不能做为编码的源要经过filter,原因之一是有些摄像机输出的音频包每个packet是320个字节,AAC每个Packet是1024个字节。
初始化Filter:
int initFilters()
{
char args[];
int ret;
AVFilter *abuffersrc = avfilter_get_by_name("abuffer");
AVFilter *abuffersink = avfilter_get_by_name("abuffersink");
AVFilterInOut *outputs = avfilter_inout_alloc();
AVFilterInOut *inputs = avfilter_inout_alloc();
static const enum AVSampleFormat out_sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE };
static const int64_t out_channel_layouts[] = { AV_CH_LAYOUT_MONO, - };
static const int out_sample_rates[] = {decoderContext->sample_rate , - };
AVRational time_base = input->time_base;
filter_graph = avfilter_graph_alloc(); /* buffer audio source: the decoded frames from the decoder will be inserted here. */ if (!decoderContext->channel_layout)
decoderContext->channel_layout = av_get_default_channel_layout(decoderContext->channels);
sprintf_s(args, sizeof(args),
"time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x",
time_base.num, time_base.den, decoderContext->sample_rate,
av_get_sample_fmt_name(decoderContext->sample_fmt), decoderContext->channel_layout);
ret = avfilter_graph_create_filter(&buffersrc_ctx, abuffersrc, "in",
args, NULL, filter_graph);
if (ret < ) {
av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer source\n");
return ret;
} /* buffer audio sink: to terminate the filter chain. */
ret = avfilter_graph_create_filter(&buffersink_ctx, abuffersink, "out",
NULL, NULL, filter_graph);
if (ret < ) {
av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sink\n");
return ret;
} ret = av_opt_set_int_list(buffersink_ctx, "sample_fmts", out_sample_fmts, -,
AV_OPT_SEARCH_CHILDREN);
if (ret < ) {
av_log(NULL, AV_LOG_ERROR, "Cannot set output sample format\n");
return ret;
} ret = av_opt_set_int_list(buffersink_ctx, "channel_layouts", out_channel_layouts, -,
AV_OPT_SEARCH_CHILDREN);
if (ret < ) {
av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layout\n");
return ret;
} ret = av_opt_set_int_list(buffersink_ctx, "sample_rates", out_sample_rates, -,
AV_OPT_SEARCH_CHILDREN);
if (ret < ) {
av_log(NULL, AV_LOG_ERROR, "Cannot set output sample rate\n");
return ret;
} /* Endpoints for the filter graph. */
outputs->name = av_strdup("in");
outputs->filter_ctx = buffersrc_ctx;
outputs->pad_idx = ;
outputs->next = NULL; inputs->name = av_strdup("out");
inputs->filter_ctx = buffersink_ctx;
inputs->pad_idx = ;
inputs->next = NULL; if ((ret = avfilter_graph_parse_ptr(filter_graph, "anull",
&inputs, &outputs, nullptr)) < )
return ret; if ((ret = avfilter_graph_config(filter_graph, NULL)) < )
return ret; av_buffersink_set_frame_size(buffersink_ctx, );
return ;
}
Filter可以简理解为FIFO(当然实际上不是)输入是解码后的AVFrame,输出是编码的源头。AVFrame 经过Filter以后就可以编码了。
shared_ptr<AVPacket> encode(AVFrame * frame)
{
int gotpacket = ;
shared_ptr<AVPacket> packet((AVPacket*)av_malloc(sizeof(AVPacket)), [&](AVPacket *p){av_free_packet(p);av_freep(&p);});
auto pkt = packet.get();
av_init_packet(pkt);
pkt->data = nullptr;
pkt->size = ;
frame->nb_samples = encoderContext->frame_size;
frame->format = encoderContext->sample_fmt;
frame->channel_layout = encoderContext->channel_layout;
int hr = avcodec_encode_audio2(encoderContext.get(), pkt, frame, &gotpacket);
av_frame_free(&frame);
if(gotpacket)
{
if (pkt->pts != AV_NOPTS_VALUE)
pkt->pts = av_rescale_q(pkt->pts, encoderContext->time_base, output->time_base);
if (pkt->dts != AV_NOPTS_VALUE)
pkt->dts = av_rescale_q(pkt->dts, encoderContext->time_base,output->time_base);
if (pkt->duration > )
pkt->duration = int(av_rescale_q(pkt->duration, encoderContext->time_base, output->time_base));
return packet;
}
return nullptr;
}
实际运用中我们用到了智能指针shared_ptr<AVPacket>,也可以不用。但是要注意内存泄露问题。如果程序运行在多核上,建议AVFilterGraph 中thread设置为1.以上代码久经考验。放心使用。如果有什么问题,可以加群 流媒体/Ffmpeg/音视频 127903734进行交流
视频下载地址:http://www.chungen90.com/?news_3/
Demo下载地址: http://www.chungen90.com/?news_2
ffmpeg 音频转码的更多相关文章
- Ffmpeg音频转码 卡顿(MP2转AAC)
最好经手一个小的功能将mp2实时流转成AAC并发布成rtmp音频流,本身不是很难的一个需求, 一个晚上就能将功能开发好.功能开发完毕后,找来一音频文件利用Ffmpeg命令将音视频文件推成 实时udp格 ...
- C# 使用 ffmpeg 进行音频转码
先放一下 ffmpeg 的官方文档以及下载地址: 官方文档:http://ffmpeg.org/ffmpeg.html 下载地址:http://ffmpeg.org/download.html 用 f ...
- ffmpeg使用转码学习
ffmpeg在官网上描述自身:是一个对视频和音频进行记录,转换,流化的完整的跨平台解决方案.事实上,现在有很多工具都是基于ffmpeg来进行视频音频的处理工具的.比如鼎鼎大名的格式工厂,就是使用ffm ...
- 使用ffmpeg实现转码样例(代码实现)
分类: C/C++ 使用ffmpeg实现转码样例(代码实现) 使用ffmpeg转码主要工作如下: Demux -> Decoding -> Encoding -> Muxing 其中 ...
- 最简单的基于FFMPEG的转码程序
本文介绍一个简单的基于FFmpeg的转码器.它可以将一种视频格式(包括封转格式和编码格式)转换为另一种视频格式.转码器在视音频编解码处理的程序中,属于一个比较复杂的东西.因为它结合了视频的解码和编码. ...
- ffmpeg/ffplay源码剖析笔记<转>
转载:http://www.cnblogs.com/azraelly/ http://www.cnblogs.com/azraelly/archive/2013/01/18/2865858.html ...
- ffmpeg音频编码
在弄音频采集时,需要设置缓存的大小,如果只是简单的采集和直接播放PCM数据,缓存的大小一般不影响播放和保存. 但是,如果需要使用FFMpeg音频编码,这时,音频缓存的大小必须设置av_samples_ ...
- C#实现 ffmpeg视频转码、播放
近来公司项目要求实现全景相机的视频截取,但是截取的视频需求转码上传.经过研究采用ffmpeg转码,奉上一个详细介绍的博文: 最简单的基于FFMPEG的转码程序 主要是转码的操作过程,能够实现了从相机获 ...
- FFmpeg简单转码程序--视频剪辑
学习了雷神的文章,慕斯人分享精神,感其英年而逝,不胜唏嘘.他有分享一个转码程序<最简单的基于FFMPEG的转码程序>其中使用了filter(参考了ffmpeg.c中的流程),他曾说想再编写 ...
随机推荐
- Android之开源项目工具库篇
本文转自:http://www.trinea.cn/android/android-open-source-projects-dev-lib/ 本文中你可以找到那些精美App中各种有特性的View,如 ...
- ueditor 单独图片上传 转载
<body> <script type="text/javascript"> //这个是图片上传的,网上还有附件上传的 (function($) { var ...
- ubuntu tty 永久修改中文环境为英文
以下代码只针对当前用户tty1有效, 对我来说足够了 vim ~/.bashrc 加入如下代码 if [ "$(tty)" = "/dev/tty1" ]; t ...
- linux 在xenserver上安装如何显示图形界面
centos5.8 64-bit和 centos 6.5 64-bit xenserver安装linux的时候默认使用的VHM,选择对应的虚拟机模板安装linux是Linux Text界面. VHM ...
- iOS开发中的那些小技巧
前言:今天在写代码的过程中遇到一个需要修改系统navigationBar的背景色,我起初用的是barTintColor去修改但是防不住系统点击按钮的时候会有一个渲染高亮的效果,调了好久没有达到自己想要 ...
- Mac下github的使用
新建github账户 新建Repository,如下图: 建立连接github的秘钥 打开mac的shell cd ~ mkdir .ssh cd .ssh ssh-keygen -t rsa ...
- linux工程管理工具make入门
一.make工具的功能 1.主要负责一个软件工程中多个源代码的自动编译工作 2.还能进行环境检测.后期处理等工作: 3.make工具可以识别出工程中哪些文件已经被修改,并且在再次编译的时候只编译这些文 ...
- 浅谈JavaScript中的apply,call和bind
apply,call,bine 这三兄弟经常让初学者感到疑惑.前两天准备面试时特地做了个比较,其实理解起来也不会太难. apply MDN上的定义: The apply() method calls ...
- EXT中的iconCls 图标加载
刚刚遇到了个奇怪的问题. 我用 在主页面用TAB autoLoad:{url:link, nocache: true, scripts:true} 加载页面Student.jsp, 郁闷,FF可以正常 ...
- 8套迷人精致的CSS3 3D按钮动画
1.纯CSS3 3D按钮 按钮酷似牛奶般剔透 CSS3按钮一般都可以设计的非常漂亮,利用投影.渐变等CSS3属性特效可以把按钮渲染的十分动感.今天分享的这款CSS3按钮外观非常特别,它看上去酷似晶莹剔 ...