MediaExtractor+MediaMuxer分离/合成一个新的Mp4

一、概述

  案例:使用MediaExtractor和MediaMuxer生成一个新的无声的视频

二、代码示例

/**
 * 将Mp4文件中的视频单独提取出来,并重新生成一个无声的Mp4文件
 * ps:经过测试,是可以分离出无声的视频的,分离成功会弹出Toast
 */
class ExtractorMp4ToNoAudioActivity : BaseActivity() {
    override fun videoPathCallback(vidoPath: String?) {

    }

    private val VIDEO_SOURCE = "input.mp4"
    private val OUTPUT_VIDEO = "output.mp4"
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_extractor_mp4_to_no_audio)
        copyFileToSdcard()
        btnExtractorNoAudioVideo.setOnClickListener {
            extractorNoAudioVideo()
        }

    }

    /**
     * 分离出没有音频的视频
     */
    @SuppressLint("WrongConstant")
    private fun extractorNoAudioVideo() {
        //创建媒体文件分离器
        var mediaExtractor = MediaExtractor()
        var mediaMuxer: MediaMuxer? = null
        try {
            //设置视频源
            val inputFile =
                File(Environment.getExternalStorageDirectory(), VIDEO_SOURCE)
            mediaExtractor.setDataSource(inputFile.absolutePath)
            //找到视频轨道索引
            var videoIndex = -1
            //视频轨道格式信息
            var videoFormat: MediaFormat? = null
            //找出视频轨道格式
            var trackCount = mediaExtractor.trackCount
            for (index in 0 until trackCount) {
                var mediaFormat = mediaExtractor.getTrackFormat(index)
                var mime = mediaFormat.getString(MediaFormat.KEY_MIME)
                if (mime.startsWith("video/")) {
                    videoIndex = index
                    videoFormat = mediaFormat
                    break;
                }
            }

            //切换想要的轨道
            mediaExtractor.selectTrack(videoIndex)

            //输入路径
            val outFile =
                File(Environment.getExternalStorageDirectory(), OUTPUT_VIDEO)
            if (outFile.exists()) {
                outFile.delete()
            }
            //实例化封装器,并置顶输出的媒体格式为mp4
            mediaMuxer =
                MediaMuxer(outFile.absolutePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
            //将视频轨添加到MediaMuxer,并返回新的轨
            var newTrackIndex = mediaMuxer.addTrack(videoFormat)
            var maxInputSize = videoFormat?.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE)
            var byteBuffer = ByteBuffer.allocateDirect(maxInputSize!!)

            var bufferInfo = MediaCodec.BufferInfo()
            mediaMuxer.start()
            while (true) {
                //将样本数据存储到字节缓冲区
                var readSampleSize = mediaExtractor.readSampleData(byteBuffer, 0)
                //如果没有可获取的样本,退出循环
                if (readSampleSize < 0) {
                    mediaExtractor.unselectTrack(videoIndex)
                    break;
                }
                bufferInfo.size = readSampleSize
                bufferInfo.flags = mediaExtractor.sampleFlags
                bufferInfo.offset = 0
                bufferInfo.presentationTimeUs = mediaExtractor.sampleTime
                mediaMuxer.writeSampleData(newTrackIndex, byteBuffer, bufferInfo)
                //读取下一帧
                mediaExtractor.advance()
            }
            Toast.makeText(this, "分离视频完成", Toast.LENGTH_SHORT).show();

        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            //释放封装器和解封装器
            if (mediaMuxer != null) {
                mediaMuxer.stop()
                mediaMuxer.release()
            }
            mediaExtractor.release()

        }


    }

    /**
     * copy文件到sdcard
     */
    private fun copyFileToSdcard() {
        FileUtils.copyAssetsFileToSdcard(
            this@ExtractorMp4ToNoAudioActivity,
            VIDEO_SOURCE,
            object : FileUtils.OnCopySuccessListener {
                override fun onSuccess(inputPath: String?, outputPath: String?) {

                }

                override fun onError(msg: String?) {

                }

            })
    }
}

 

posted on 2023-01-12 11:21  飘杨......  阅读(208)  评论(0)    收藏  举报