时机不对解决方案建议时机:dequeueOutputBuffer返回MediaCodec.INFO_OUTPUT_FORMAT_CHANGED更新MediaMuxer.addTrack, 所有的track 音频:dequeueOutputBuffer返回MediaCodec.INFO_OUTPUT_FORMAT_CHANGED触发新MediaMuxer.addTrack视频:dequeueOutputBuffer 返回MediaCodec.INFO_OUTPUT_FORMAT_CHANGED触发新MediaMuxer.addTrackMediaMuxer:所有track add完成之后触发start问题示例如果提前 会爆addTrack ERROR如果提前addTrack && start,录制视频会卡顿兼容性问题导致数据被丢弃问题现象有些机型,音频 or 视频初始化很慢,时间错开,导致另一个通道数据到达之后,因为MediaMuxer 解决方案添加队列保存提前到来的数据,当MediaMuxer.Start之后统一写进去写入缓存时候需要加锁,防止新的数据进来导致时序不对,就会出现上面MediaMuxer.writeSampleData
工具准备: 视频的分离合成我主要用到了MediaExtractor和MediaMuxer两个类: MediaExtractor是用于提取多路的、通常编码的视频资源的,通过它我们可以选择音频或者视频轨, 然后分别对它们进行操作等; MediaMuxer是用于复用基本流的,用它可以将音频和视频合成,目前支持输出MP4,Webm和3GP格式的视频,在Android7.0以后支持多路复用帧的MP4。 类是用来合成的吧,那么我们将找到的音频轨通过addTrack方法设置给MediaMuxer对象,这里有个小细节需要注意,我们需要记录两个音频轨,一个是原视频的(旧轨道),一个是将来合成的视频的(新轨道) OK,视频一的音频已经提取出来啦,那么我们用相似的方法将视频二的视频图像提取出来,也通过addTrack方法设置给同一个MediaMuxer对象,不同的是我们要获取到视频的帧率,并且在之后合成的时候需要处理一下 2.合成: 那么到这里,视频一的音频和视频二的视频图像都已经设置给MediaMuxer对象了,我们就可以合成啦,还记得我们在找音频和视频的时候记录下的新旧轨道吧,现在通过MediaExtractor对象的
音视频合成采用MediaMuxer合成。 ? 官方示例: //MediaMuxer facilitates muxing elementary streams. //MediaMuxer muxer = new MediaMuxer("temp.mp4", OutputFormat.MUXER_OUTPUT_MPEG_4); // More often (audioEncodec.getOutputFormat()); } 开始合成 mediaMuxer.start(); //写入视频数据 mediaMuxer.writeSampleData(videoTrackIndex , audioBufferinfo); 合成结束,写入头信息 mediaMuxer.stop(); mediaMuxer.release(); mediaMuxer = null; 具体查看demo:
MediaMuxer的使用比较简单,方法很少,就那么几个。 但是需要注意的是我们添加音视频轨的时候,MediaMuxer.addTrack(MediaFormat)需要一个MediaFormat参数,而这个参数不是我们打开MediaCodec的时候简单构造的那个 我们先看一下MediaMuxer的主要方法: /** * 我们都知道,一个视频文件是包含一个或多个音视频轨道的, * 而这个方法就是用于添加一个视频或视频轨道,并返回对应的ID。 (path, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4) } 因为我们需要在添加音频和视频轨道之后才能开启Muxer,所以分别用两个bool来标记对应的轨道已经添加 release() } 本章知识点: 使用MediaMuxer对音视频进行混合封装。 本章相关源码·HardwareVideoCodec项目: MuxerImpl
MediaCodec录制主要代码 private MediaMuxer mMediaMuxer; private MediaCodec.BufferInfo mBuffInfo; private String savePath, String mineType, int width, int height) { try { mMediaMuxer = new MediaMuxer (savePath,MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); initVideoEncoder(mineType,width,height (videoEncodec.getOutputFormat()); mediaMuxer.start(); }else { while (outputBufferIndex (); mediaMuxer.release(); mediaMuxer = null; } 具体示例请看: https://github.com/ChinaZeng/SurfaceRecodeDemo
MediaCodec+MediaMuxer: MediaCodec 与 MediaMuxer结合使用同样能够实现短视频源码开发录制的功能。 MediaCodec是Android提供的编解码类,MediaMuxer则是复用类(生成视频文件)。 五、MediaCodec+MediaMuxer的使用 MediaMuxer和MediaCodec这两个类,它们的参考文http://developer.android.com/reference/android 把audio和video的MediaCodec,MediaCodec用的Surface及MediaMuxer对象释放。 MediaMuxer的使用要按照Constructor -> addTrack -> start -> writeSampleData -> stop 的顺序。
MediaCodec+MediaMuxer: MediaCodec 与 MediaMuxer结合使用同样能够实现录制的功能。 MediaCodec是Android提供的编解码类,MediaMuxer则是复用类(生成视频文件)。 五、MediaCodec+MediaMuxer的使用 MediaMuxer和MediaCodec这两个类,它们的参考文http://developer.android.com/reference/android 把audio和video的MediaCodec,MediaCodec用的Surface及MediaMuxer对象释放。 最后几点注意: 1. MediaMuxer的使用要按照Constructor -> addTrack -> start -> writeSampleData -> stop 的顺序。
MediaCodec+MediaMuxer: MediaCodec 与 MediaMuxer结合使用同样能够实现录制的功能。 MediaCodec是Android提供的编解码类,MediaMuxer则是复用类(生成视频文件)。 五、MediaCodec+MediaMuxer的使用 MediaMuxer和MediaCodec这两个类,它们的参考文http://developer.android.com/reference/android 把audio和video的MediaCodec,MediaCodec用的Surface及MediaMuxer对象释放。 MediaMuxer的使用要按照Constructor -> addTrack -> start -> writeSampleData -> stop 的顺序。
lastAudioTimeStamp; Timer::Ptr _timer; MuteAudioMaker::Ptr _audioMaker; MultiMediaSourceMuxer::Ptr _mediaMuxer == NULL) { //使用rtmp://127.0.0.1/live/chn_00 点播就可以了 inputInfo->_mediaMuxer.reset(new ->addTrack(inputInfo->_videoTrack); //视频数据写入_mediaMuxer inputInfo->_videoTrack->addDelegate(inputInfo ->_mediaMuxer); //用来合并rtp包 inputInfo->_merger = std::make_shared<FrameMerger>(); ->addTrack(inputInfo->_audioTrack); inputInfo->_audioTrack->addDelegate(inputInfo->_mediaMuxer);
保存为mp4格式的视频 视频处理需要用到MediaMuxer: mediaMuxer = new MediaMuxer(out.getAbsolutePath(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG = new MediaMuxer(out.getAbsolutePath(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); } catch (IOException = null) { mediaCodec.stop(); mediaCodec.release(); } if (mediaMuxer = null) { try { if (mMuxerStarted) { mediaMuxer.stop( (mediaFormat); mediaMuxer.start(); mMuxerStarted = true;
MediaCodec工作原理 image.png MediaCodec类Android提供的用于访问低层多媒体编/解码器接口,它是Android低层多媒体架构的一部分,通常与MediaExtractor、MediaMuxer TIMEOUT_USEC); mMediaCodec.releaseOutputBuffer(outputBufferIndex, false); 音视频数据混合 创建混合器实例 MediaMuxer mediaMuxer = new MediaMuxer(filePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); 在混合之前需要通过编码器获取一个音轨视频轨的索引 以音频为例: mediaMuxerRunnable.addTrackIndex(MediaMuxerThread.TRACK_AUDIO, format); 以视频为例: mediaMuxer.addTrackIndex Log.e(TAG, "写入混合数据 " + data.bufferInfo.size); try { mediaMuxer.writeSampleData
随着Android 4.4及以上版本的逐渐普及,Android 4.1引入的MediaExtractor类,以及Android 4.3引入的MediaMuxer类,终于可以开始正式地“发光发热”了。 MediaMuxer类主要用于将音频和视频数据进行混合生成多媒体文件(如:mp4文件),而MediaExtractor则刚好相反,主要用于多媒体文件的音视频数据的分离。 本文将介绍如何利用Android SDK提供的MediaExtractor和MediaMuxer类来完成mp4文件的提取和生成,指出开发过程中会遇到的坑,并给出简单的Demo示例代码。 MediaMuxer 该类主要用于将音频和视频进行混合生成多媒体文件,创建该类对象,需要传入输出的文件位置以及格式,构造函数如下: public MediaMuxer(String path, int 通过 addTrack() 添加了数据通道之后,记录下函数返回的 trackIndex,然后就可以调用 MediaMuxer.writeSampleData() 愉快地向mp4文件中写入数据了。
知识点 在代码中,MediaCodeC只负责数据的传输,而生成MP4文件主要靠的类是MediaMuxer。 在传入数据后使用drainCoder函数,从MediaCodeC读取输出数据,使用MediaMuxer编码为Mp4视频文件。 也就是在这里的代码中,当输出数据格式改变时,为MediaMuxer加上视频轨,并启动。 trackIndex = mediaMuxer!!. addTrack(codec.outputFormat) mediaMuxer!!. start() 整体上的工作流程就是以上这些代码了,传入一帧数据到Surface-->MediaCodeC循环拿输出数据--> MediaMuxer写入Mp4视频文件。
回想之前我们使用MediaCodec进行硬编的时候,可以使用MediaMuxer进行文件封装,那么这里我们能不能也使用这个对x264编码后的数据进行封装呢,答案是可以的! 第六章讲MediaMuxer用法的时候我们说到,要使用MediaMuxer就必须先addTrack(MediaFormat)来添加音视频轨道,而这个方法需要一个特殊的MediaFormat,这个参数特殊在哪呢 查看官方文档可以发现,MediaMuxer对h264进行封装的时候需要sps和pps,这两块数据分别对应MediaMuxer中的csd-1和csd-2,这些数据可以通过MediaFormat.setByteBuffer 所需要的特殊MediaFormat了,之后参考第六章正常使用MediaMuxer即可。 MediaMuxer的另类用法。
selectTrack(mAudioTrack) } } 二、音视频封装 Android原生提供了一个封装器MediaMuxer,用于将已经编码好的音视频流数据封装到指定格式的文件中,MediaMuxer MMuxer { private val TAG = "MMuxer" private var mPath: String private var mMediaMuxer: MediaMuxer Environment.getExternalStorageDirectory().absolutePath.toString() + "/" mPath = filePath + fileName mMediaMuxer = MediaMuxer (mPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4) } //...... } 这里指定了视频并保存路径和保存的格式。
实现效果 代码实现 微卡智享 采用的组件 MediaProjectionManager MediaProjection MediaCodec MediaMuxer Android 5.0后Google 终于开放了屏幕采集的接口,也就是 MediaProjection 和 MediaProjectionManager,然后再用MediaCodec输出AAC、MediaMuxer合成音频视频并输出mp4, android.media.MediaCodec import android.media.MediaCodecInfo import android.media.MediaFormat import android.media.MediaMuxer = null private var mMuxer: MediaMuxer? (filename, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4) } else {
下面是媒体转换器MediaMuxer的主要方法说明: 构造函数 : 根据文件路径与文件格式构造一个媒体转换器。 文件格式通常取值MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4。 addTrack : 把指定格式添加到转换轨道上。返回轨道的索引位置。 private int mScreenWidth, mScreenHeight, mScreenDensity; private MediaCodec mMediaCodec; private MediaMuxer (mVideoPath); mVideoName = Utils.getNowDateTime() + ".mp4"; //文件格式为MPEG-4 mMediaMuxer = new MediaMuxer (mVideoPath+mVideoName, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); while (isRecording) {
SurfaceTexture(集成了EGL环境的Surface,可以很方便的与OpenGL联动,也是TextureView提供的渲染接口) MediaCodec(硬编解决方案) X264(软编解决方案) MediaMuxer 这里我可以很负责任的告诉你,直接使用x264,再配合MediaMuxer使用会简单很多,也是因为硬编同样会用到MediaMuxer。
2.1.3 MediaMuxer MediaMuxer是Android平台的音视频合成工具,上面我们介绍了MediaCodec可以编码数据,EGL环境可以让OpenGL程序将绘制的内容渲染到MediaCodec 中,MediaCodec将这些数据编码,最后这些编码后的数据需要使用MediaMuxer写入到指定的文件中。 MediaMuxer基本使用: //创建一个MediaMuxer,需要指定输出保存的路径,和输出保存的格式。 val mediaMuxer = MediaMuxer(path, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4) //根据MediaFormat添加媒体轨道 mediaMuxer.addTrack(MediaFormat(...))
SurfaceTexture(集成了EGL环境的Surface,可以很方便的与OpenGL联动,也是TextureView提供的渲染接口) MediaCodec(硬编解决方案) X264(软编解决方案) MediaMuxer 这里我可以很负责任的告诉你,直接使用x264,再配合MediaMuxer使用会简单很多,也是因为硬编同样会用到MediaMuxer。