EasyPlayer实现Android MediaMuxer录像MP4(支持G711/AAC/G726音频)
本文转自EasyDarwin开源团队John的博客:http://blog.csdn.net/jyt0551/article/details/72787095
Android平台的MediaMuxer是个非常好的录像库,它能将H.264视频+AAC音频存储成.mp4格式的文件,而且稳定性、同步效果都非常好。
MediaMuxer在安卓版的EasyPlayer和EasyPusher都用到了该方法来进行本地录像。作者也写过两篇针对性的博客来做介绍,参考:
http://blog.csdn.net/jyt0551/article/details/60152344
http://blog.csdn.net/jyt0551/article/details/58714595
MediaMuxer的接口定义相对而言比较简单,调用过程如下图所示。
简单来说,就是创建对象、添加音视频轨道、开始、持续写入音视频数据、关闭这样一个过程。
遗憾的是,MediaMuxer并不支持对除AAC以外的音频编码格式的封装,然而在安防行业里G711音频格式的数据是大多数设备的默认编码格式。
如何支持G711格式的数据呢?其实换种思路就会豁然开朗,我们可以先把G711数据解码成PCM,再用MediaCodec编码成AAC,这样曲线存储^_^。不光是G711,所有的音频编码格式都可以这样做哈哈。。
所以前面的流程图里,writeAudioSample的部分就变成这样了:
下面是将解码后的PCM数据塞入Muxer的代码片段。
package org.easydarwin.audio;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.util.Log;
import org.easydarwin.video.EasyMuxer;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* 对EasyMuxer的扩展。支持对PCM格式的音频打包。
*/
public class EasyAACMuxer extends EasyMuxer {
MediaCodec mMediaCodec;
String TAG = "EasyAACMuxer";
protected MediaCodec.BufferInfo mBufferInfo = new MediaCodec.BufferInfo();
protected ByteBuffer[] mBuffers = null;
private MediaFormat mAudioFormat;
public EasyAACMuxer(String path, long durationMillis) {
super(path, durationMillis);
}
@Override
public synchronized void addTrack(MediaFormat format, boolean isVideo) {
super.addTrack(format, isVideo);
if (!isVideo){
mAudioFormat = format;
}
}
public synchronized void pumpPCMStream(byte []pcm, int length, long timeUs) throws IOException {
if (mMediaCodec == null) {// 启动AAC编码器。这里用MediaCodec来编码
if (mAudioFormat == null) return;
mMediaCodec = MediaCodec.createEncoderByType("audio/mp4a-latm");
Log.i(TAG, String.valueOf(mAudioFormat));
mAudioFormat.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
mAudioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE,MediaCodecInfo.CodecProfileLevel.AACObjectLC);
mAudioFormat.setInteger(MediaFormat.KEY_BIT_RATE, 16000);
// mAudioFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 320);
mMediaCodec.configure(mAudioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mMediaCodec.start();
mBuffers = mMediaCodec.getOutputBuffers();
}
int index = 0;
// 将pcm编码成AAC
do {
index = mMediaCodec.dequeueOutputBuffer(mBufferInfo, 1000);
if (index >= 0) {
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
continue;
}
if (mBufferInfo.presentationTimeUs == 0){
continue;
}
if (VERBOSE) Log.d(TAG,String.format("dequeueOutputBuffer data length:%d,tmUS:%d", mBufferInfo.size, mBufferInfo.presentationTimeUs));
ByteBuffer outputBuffer = mBuffers[index];
// ok,编码成功了。将AAC数据写入muxer.
pumpStream(outputBuffer, mBufferInfo, false);
mMediaCodec.releaseOutputBuffer(index, false);
} else if (index == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
mBuffers = mMediaCodec.getOutputBuffers();
} else if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
Log.v(TAG, "output format changed...");
MediaFormat newFormat = mMediaCodec.getOutputFormat();
Log.v(TAG, "output format changed..." + newFormat);
} else if (index == MediaCodec.INFO_TRY_AGAIN_LATER) {
Log.v(TAG, "No buffer available...");
} else {
Log.e(TAG, "Message: " + index);
}
} while (index >= 0 && !Thread.currentThread().isInterrupted());
final ByteBuffer[] inputBuffers = mMediaCodec.getInputBuffers();
do {
index = mMediaCodec.dequeueInputBuffer(1000);
if (index >= 0) {
inputBuffers[index].clear();
inputBuffers[index].put(pcm, 0, length);
if (VERBOSE) Log.d(TAG,String.format("queueInputBuffer pcm data length:%d,tmUS:%d", length, timeUs));
mMediaCodec.queueInputBuffer(index, 0, length, timeUs, 0);
}
}
while (!Thread.currentThread().isInterrupted() && index < 0);
}
@Override
public synchronized void release() {
if (mMediaCodec != null) mMediaCodec.release();
mMediaCodec = null;
super.release();
}
}
一切都在代码中,不再过多解释,至此结束。
更多代码请查看EasyPlayer Github:https://github.com/EasyDarwin/EasyPlayer
获取更多信息
Copyright © EasyDarwin.org 2012-2017

EasyPlayer实现Android MediaMuxer录像MP4(支持G711/AAC/G726音频)的更多相关文章
- java攻城狮之路(Android篇)--MP3 MP4、拍照、国际化、样式主题、图片移动和缩放
一.MP3播放器 查看Android API文档可以看到MediaPlayer状态转换图: 练习: package com.shellway.mp3player; import java.io.Fil ...
- Android:让WebView支持<input type=”file”…>元素
最近在做一个活动页面:用户上传一张图片进行缩放.旋转后点击下一步填写内容后生成图片! 做好后经过各种测试是没有问题的,基本没有什么明显BUG,流程都能走通,但是嵌入到APP后,问题就来了! 在IOS上 ...
- Android 2.3 不支持印度文
Android 2.3 不支持印度文(hindi),即使你指定了相关的字符串也不行,它们一律显示为方格. 实际上,你在系统的语言设置界面也可以看到,印度文一行也是被显示为方格(既然是方格,如何知道它是 ...
- 为Cocos2d-x的Android平台加入Protobuffer支持
为Cocos2d-x的Android平台加入Protobuffer支持 分类: 工作2013-11-27 18:00 386人阅读 评论(1) 收藏 举报 cocos2d-xandroid平台交叉编译 ...
- 图解IntelliJ IDEA 13版本对Android SQLite数据库的支持
IntelliJ IDEA 13版本的重要构建之一是支持Android程序开发.当然对Android SQLite数据库的支持也就成为了Android开发者对IntelliJ IDEA 13版本的绝对 ...
- CEF3编译添加mp4支持(对应CefSharp63.0.3),chromium63(3239),附release下载
编译环境需求(3239版本) win7或更高,64位 vs2017 15.3.2+ 默认位置安装 不需要安装附带的win10sdk,sdk单独装 Windows 10.0.15063.468 SDK ...
- 【树莓派】【转】树莓派3装Android 6.0,支持Wi-Fi和蓝牙
树莓派3装Android 6.0,支持Wi-Fi和蓝牙 相信对于许多树莓派初学者(包括我)来说,Android系统的确是一个不错的选择.但国内这方面资源稀缺,经本人FQ苦寻,找到了老外的树莓派Andr ...
- EasyPlayer RTSP Android安卓播放器修复播放画面卡在第一帧bug
本文转自EasyDarwin团队成员John的博客:http://blog.csdn.net/jyt0551/article/details/75717097 最近发现某些手机在运行EasyPlaye ...
- EasyPlayer RTSP Android安卓播放器实现视频源快速切换
EasyPlayer现在支持多视频源快速切换了,我们介绍一下是如何实现的. 这个需求通常应用在一个客户端需要查看多个视频源的情况,比如多个监控场景轮播. 由于EasyPlayer的播放端已经放在Fra ...
随机推荐
- 第二课 GCC入门之静态库以及共享库
序言: 前面一课讲了gcc的简单入门,包括gcc编译步骤:预处理:编译:汇编:链接.今天这节课就来讲下linux的库也欢迎大家吐糟共同学习. 原理: linux系统中分为2种库:静态库和共享库.静态库 ...
- LeetCode:逆波兰表达式求值【150】
LeetCode:逆波兰表达式求值[150] 题目描述 根据逆波兰表示法,求表达式的值. 有效的运算符包括 +, -, *, / .每个运算对象可以是整数,也可以是另一个逆波兰表达式. 说明: 整数除 ...
- 错误:为 Web 项目“XXX”配置的 URL“http://localhost/”的网站同时存在于本地 IIS Web 服务器和 IIS Express Web 服务器上。您需要使用 IIS 管理器在 IIS 中更改此网站的绑定。
解决方法: 用记事本打开MVC网站的项目文件(*.csproj),滚动条拉到最下,找到这两个节点: <UseIIS>True</UseIIS> <AutoAssignPo ...
- poj2996
/*排序函数要写对,优先级:K,Q,R,B,N,P 白色的:如果优先级一样,那么按照行数大的优先,如果行数一样,那么列数小的优先 黑色的:如果优先级一样,那么按照行数小的优先,如果行数一样,那么列数小 ...
- Sybase:循环调用存储过程
Sybase:循环调用存储过程 一.日期循环 declare @c_count int declare @rq int --获取两个日期之间的天数 ,getdate()) begin ,),),),) ...
- 用户iis可以用外网ip访问,用内网访问报错404
如下,没有添加内网ip绑定
- Codeforces Round #448 (Div. 2) B
题目描述有点小坑,ij其实是没有先后的 并且y并不一定存在于a中 判断y的个数和所给数组无关 对于2 - 7来说 中间满足%2==0的y一共有3个 2 4 6 这样 可以看出对于每个数字a 都能够二分 ...
- crm开发(基于ssh)(1)
搭建crm练习ssh环境 第一步 导入jar包 第二步 搭建struts2环境 (1)创建action,创建struts.xml配置文件,配置action (2)配置struts2的过滤器 第三步 搭 ...
- mysql建立索引
mysql的几种索引http://jingyan.baidu.com/article/da1091fbd166ff027849d687.html
- 智课雅思词汇---二十四、形容词后缀-al-ial-ar-ary-ic-id-ish-ile-ine-oid-ory
智课雅思词汇---二十四.形容词后缀-al-ial-ar-ary-ic-id-ish-ile-ine-oid-ory 一.总结 一句话总结: 1.形容词后缀-al? autumnal 英 [ɔː'tʌ ...