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之列表内容显示
一:刚开始布局设计:在layout的activity_main中添加listView,效果图如下: 二:在Main_Activity中代码如下: package net.jiaxiang.arrada ...
- CentOS 7 用户账户配置
说明: 1.这篇博文记录的是CentOS 7 用户账户的配置,包括添加用户.添加用户组.删除用户.删除用户组等.其中包括分析用户的配置文件.目录以及对安全的思考. 2.用户配置方面CentOS 7与以 ...
- 【转】理解JavaScript之闭包
闭包(closure)是掌握Javascript从人门到深入一个非常重要的门槛,它是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现.下面写下我的学习笔记~ 闭包-无处不 ...
- WebApp遇到的一些坑
一.关于js 1. 引用zepto.js时,借用插件swipe时,写的滑动加载,在ios上可以实行滑动加载数据,但是在安卓上,就是不能滑动: 注: 在使用插件的时候,要先注意其兼容性问题. 2. 用j ...
- MAC上 nodejs express 安装
最近在MAC上搭建 nodejs环境以及安装 express 框架,遇到了一些问题,不过最后总算还是安装成功了,下面是操作步骤 1.node js 安装 访问nodejs官网进入下载mac上的安装包 ...
- 让ImageView可以使用gif的方法
在自己的包中添加MyGifView.java(直接复制,粘贴),读取gif资源在MyGifView中第20行读取: MyGifView.java: package com.zzw.testgifuse ...
- Sublime Text 前端开发常用扩展插件推荐
Sublime Text 前端开发常用扩展插件推荐 Sublime Text Sublime Text 是程序员们公认的编码神奇,拥有漂亮的用户界面和强大的功能 更重要的是,Sublime Text ...
- AJAX请求和跨域请求详解(原生JS、Jquery)
一.概述 AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术. AJAX = 异步 JavaScript 和 XML,是一种用于创建快速动态网页的技术.通过在后台与服务器进行少量数 ...
- uWSGI uwsgi_response_write_body_do(): Connection reset by peer 报错的解决方法
服务器架构是:Nginx+uWSGI+Django 某一天,发现服务器返回的response不完整,例如文档大小是200K的,但是只返回了100K给浏览器. 查了一下uWSGI的日志,发现以下错误: ...
- js中ajax异步导致的一些问题
问题1:ajax默认是异步,所以在ajax中对外面定义的变量赋值,不能正确赋值 $("form").submit( var flag; $.ajax({ type: 'GET', ...