EasyPlayer实现Android MediaMuxer录像MP4(支持G711/AAC/G726音频)
来源:互联网 发布:mac itunes 设置铃声 编辑:程序博客网 时间:2024/06/05 04:46
本文转自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
获取更多信息
邮件:support@easydarwin.org
WEB:www.EasyDarwin.org
Copyright © EasyDarwin.org 2012-2017
- EasyPlayer实现Android MediaMuxer录像MP4(支持G711/AAC/G726音频)
- Android MediaMuxer录像(支持G711音频)
- Android G711(PCMA/PCMU)、G726、PCM音频转码到AAC
- 开源G711(PCMA、PCMU)/G726转AAC项目EasyAACEncoder
- EasyDarwin开源音频解码项目EasyAudioDecoder:基于ffmpeg的安卓音频(AAC、G726)解码库(第一部分,ffmpeg-android的编译)
- EasyPlayer Android基于ffmpeg实现播放(RTSP/RTMP/HTTP/HLS)同步录像功能
- Android音视频处理之MediaMuxer(MP4)
- Android中如何提取和生成mp4文件(MediaMUxer)
- EasyAACEncoder 海思等ARM平台 优化G711、G726转AAC的CPU占用等问题
- EasyAACEncoder海思/ARM平台优化G711、G726转AAC的CPU占用高问题
- EasyPlayer源码解析系列之录像写MP4
- Android Multimedia实战(四)MediaProjection实现截图,与MediaMuxer实现录屏为MP4,Gif格式
- EasyPlayer Android安卓流媒体播放器实现播放同步录像功能实现(附源码)
- Android-->MediaMuxer,MediaCodec,AudioRecord及Camera实现音频视频混合MP4文件
- 【转载】Android-->MediaMuxer,MediaCodec,AudioRecord及Camera实现音频视频混合MP4文件
- Android-->MediaMuxer,MediaCodec,AudioRecord及Camera实现音频视频混合MP4文件
- 音频:G711
- ffmpeg开发之旅(3):AAC编码格式分析与MP4文件封装(MediaCodec+MediaMuxer)
- Oracle12C--游标(三十五)
- Oracle12C--显式游标(三十六)
- jzoj P1522 无线网络
- Linux 快捷键
- 5、聚类之层次聚类、基于划分的聚类(k-means)、基于密度的聚类、基于模型的聚类
- EasyPlayer实现Android MediaMuxer录像MP4(支持G711/AAC/G726音频)
- lua switch
- realloc函数和calloc函数
- Kotlin 定义List 和 Map 等约定写法
- vi/vim 编辑器详解
- json小通讯接口
- 提高编程能力经验
- awk工具详解
- python+selenium+phantomjs 模拟淘宝登陆