美文网首页Android技术知识Android开发Android开发经验谈
使用MediaMuxer对音视频进行混合封装「第六章,Andro

使用MediaMuxer对音视频进行混合封装「第六章,Andro

作者: Alimin利民 | 来源:发表于2018-09-09 14:55 被阅读30次

      本章仅对部分代码进行讲解,以帮助读者更好的理解章节内容。
    本系列文章涉及的项目HardwareVideoCodec已经开源到Github,支持软编和硬编。使用它你可以很容易的实现任何分辨率的视频编码,无需关心摄像头预览大小。一切都如此简单。目前已迭代多个稳定版本,欢迎查阅学习和使用,如有BUG或建议,欢迎Issue。


      MediaMuxer的使用比较简单,方法很少,就那么几个。但是需要注意的是我们添加音视频轨的时候,MediaMuxer.addTrack(MediaFormat)需要一个MediaFormat参数,而这个参数不是我们打开MediaCodec的时候简单构造的那个,这个MediaFormat必须是从MediaCodec.getOutputFormat()获取的,他们完全不一样。如果我们直接使用自己简单构造的MediaFormat,是无法写入音视频数据的。
      说必须有点绝对了,这只是官方推荐用法而已。其实如果有必要,我们完全可以自己构造用于添加音视频轨道的MediaFormat,这个我会在第八章教大家怎么做。
      我们先看一下MediaMuxer的主要方法:

    1. int addTrack(@NonNull MediaFormat format)
        我们都知道,一个视频文件是包含一个或多个音视频轨道的,而这个方法就是用于添加一个视频或视频轨道,并返回对应的ID。之后我们可以通过这个ID向相应的轨道写入数据。前面说了,用于新建音视频轨道的MediaFormat是需要从MediaCodec.getOutputFormat()获取的,而不是自己简单构造的MediaFormat。
    2. start()
        当我们添加完所有音视频轨道之后,需要调用这个方法告诉Muxer,我要开始写入数据了。需要注意的是,调用了这个方法之后,我们是无法再次addTrack了的。
    3. void writeSampleData(int trackIndex, @NonNull ByteBuffer byteBuf,
      @NonNull BufferInfo bufferInfo)
        用于向Muxer写入编码后的音视频数据。trackIndex是我们addTrack的时候返回的ID,byteBuf便是要写入的数据,而bufferInfo是跟这一帧byteBuf相关的信息,包括时间戳数据长度和数据在ByteBuffer中的位移
    4. void stop()
        与start()相对应,用于停止写入数据,并生成文件。
    5. void release()
        释放Muxer资源。

      着实有点简单了,整个流程用到的就这个五个方法。我们先来构造一个Muxer,需要两个参数,第一个是音视频文件的保存路径,第二个是音视频封装文件的格式,可以选择mp43gp,我们使用mp4就好。

    private fun start() {
        //用于标记是否已经添加视频轨道
        mVideoTrackReady = false
        //用于标记是否已经添加银频轨道
        mAudioTrackReady = false
        //用于标记是否已经开始
        mStart = false
        //删除已存在的文件
        val file = File(path)
        if (file.exists()) file.delete()
        muxer = MediaMuxer(path, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
    }
    

      因为我们需要在添加音频和视频轨道之后才能开启Muxer,所以分别用两个bool来标记对应的轨道已经添加,并且每次添加轨道时,都使用ready()检查是否可以开启Muxer。

    private fun ready() {
        if (mVideoTrackReady && mAudioTrackReady) {
            muxer?.start()
            mStart = true
            debug_e("Muxer start")
        }
    }
    
    override fun addVideoTrack(format: MediaFormat) {
        try {
            videoTrack = muxer!!.addTrack(format)
        } catch (e: Exception) {
            //Add video track failed
            e.printStackTrace()
            return
        }
        mVideoTrackReady = true
        ready()
    }
    
    override fun addAudioTrack(format: MediaFormat) {
        try {
            audioTrack = muxer!!.addTrack(format)
        } catch (e: Exception) {
            //Add audio track failed
            e.printStackTrace()
            return
        }
        mAudioTrackReady = true
        ready()
    }
    

      添加完轨道之后,我们就可以开始给Muxer写入数据了,这部分也很简单。我们只需要根据addTrack时返回的ID对应的写入数据就好。

    private fun writeSample(track: Int, sample: Sample) {
        try {
            muxer?.writeSampleData(track, sample.sample, sample.bufferInfo)
        } catch (e: Exception) {
            //Write sample failed
            e.printStackTrace()
        }
    }
    

      最后我们写完数据之后,一定要记得调用stop()来生成文件,和release()释放资源。

    private fun stop() {
        if (mStart) {
            mStart = false
            try {
                muxer?.stop()
            } catch (e: IllegalStateException) {
                e.printStackTrace()
            }
        }
        muxer?.release()
    }
    

    本章知识点:

    1. 使用MediaMuxer对音视频进行混合封装。

    本章相关源码·HardwareVideoCodec项目

    相关文章

      网友评论

        本文标题:使用MediaMuxer对音视频进行混合封装「第六章,Andro

        本文链接:https://www.haomeiwen.com/subject/fmyvlftx.html