AndroidプラットフォームのMediaExtractorとMediaMuxer学習、分析およびパッケージMP4

免責事項:この記事はブロガーオリジナル記事ですが、許可ブロガーなく再生してはなりません。https://blog.csdn.net/One_Month/article/details/90267556

Kotlinのコードサンプルは、この記事の構文を使用しますが、ない高度な機能

MediaExtractor:分離できるビデオファイル、ビデオとオーディオを抽出
MediaMuxerを、シンセサイザーのオーディオおよびビデオファイルのビデオとオーディオの合成新しいビデオ抽出することができます:
MediaFormatを:抽出取得したメディア・フォーマット・クラス、取得を保存メディア情報(メディアタイプ、
フレームレート、等)

1.設定権限が必要
。それがローカルファイルである場合は、読み取りと書き込みを伴います、あなたがマニフェストを設定する必要があります

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

6.0はここでは省略し、動的なコードのために適用するには

2.ビデオファイルを入手し必要
この論文は、ContentResolverのを介して直接マルチメディアファイルを照会することです

 val cursor = contentResolver.query(
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
                null, null, null, null
        )
查询到的数据存储到了自建的Song类中,存了文件名(name)和路径(path),然后用ListView展示,

次のファイルおよび使用に直接隣接する時間を、保存するには、ビデオとオーディオを抽出するための原料として、ファイルをクリックされ
ますが、ファイルを探すために気にしない場合は動画ファイルも直接のres /生フォルダに入れることができ、生独自に作成
その後、ファイルを取得し、MediaExtractor.setDataSourceは埋めるために多くの方法をサポート

3.抽出オーディオとビデオ

	/**
     * 配置音视频提取器
     * @param position  点击的文件下标
     */
    fun configureVideoAndAudioExtractor(position: Int) {
        try {
            //1.设置要提取视频的文件
//
         


   			/**
             *
             * MediaExtractor反复提示初始化失败
             * 1.检查文件访问权限
             * 2.检查视频文件大小是否大于0!!!!!!!!!!!!!!!
             *3.最好不要用拼接路径,比如
             * mVideoMediaExtractor.setDataSource(context.getFilesDir()+"xxx.mp4")
             * 最好添加路径变量或完整路径地址,比如下面的变量或
             * "mnt/sdcard/.../.../xxx.mp4"这种的
             */

			//初始化解析器和合成器对象,合成输入的格式是mp4,
			//outputVideoPath是合成后输出的路径,自己构建就好
			//我的是fileDir+“video.mp4”
			
            mMediaMuxer = MediaMuxer(outputVideoPath,     
            MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
            
            mVideoMediaExtractor = MediaExtractor()
            mAudioMediaExtractor = MediaExtractor()

			//songList是一个集合,存着Song类,
			//设置要提取出视频的原材料文件
            mVideoMediaExtractor.setDataSource(songList[position].path)
            //设置要提取出音频的文件
            mAudioMediaExtractor.setDataSource(songList[position].path)

            //获取轨道,找到视频轨道
            for (i in 0 until mVideoMediaExtractor.trackCount) {
                val mediaFormat = mVideoMediaExtractor.getTrackFormat(i)
                if (mediaFormat.getString(MediaFormat.KEY_MIME).startsWith("video/")) {
                    //获取到视频轨道
                    mVideoMediaExtractor.selectTrack(i)
                    //获取添加到Muxer后生成的新的视频轨道下标
                    videoMuxerTrackIndex = mMediaMuxer.addTrack(mediaFormat)
                    //获取视频帧最大值,为了后面合成新视频,读取文件时候设定缓冲区大小
                    maxFrameSize = mediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE)
                    //获取视频帧率,为了后面计算获取到的文件处于的播放时间
                    frameRate = mediaFormat.getInteger(MediaFormat.KEY_FRAME_RATE)
                }
            }

			//找到视频文件中的音频轨道,方法和获取视频差不多
            for (j in 0 until mAudioMediaExtractor.trackCount) {
                val mediaFormat = mAudioMediaExtractor.getTrackFormat(j)
                if (mediaFormat.getString(MediaFormat.KEY_MIME).startsWith("audio/")) {
                    //获取音轨
                    mAudioMediaExtractor.selectTrack(j)
                    //添加音轨到Muxer
                    audioMuxerTrackIndex = mMediaMuxer.addTrack(mediaFormat)
                    //获取音频最大输入,为了计算缓冲区大小
                    maxAudioSize = mediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE)
                }
            }

		  //这个方法内执行MediaMuxer的合成操作,下面会贴出来
            compoundVideoAndAudioWithPermissionCheck()
        } catch (e: IOException) {
            Log.i("exception", e.message)

        } finally {
            //释放资源,切记最后要是放资源,重新添加合成文件时候要新建MediaExtractor和MediaMuxer
            if (mMediaMuxer != null) {
                mMediaMuxer.release()
            }
            if (mVideoMediaExtractor != null) {
                mVideoMediaExtractor.release()
            }

            if (mAudioMediaExtractor != null) {
                mAudioMediaExtractor.release()
            }
        }
    }

ステップは、要約することです
MediaExtractorとMediaMuxerは、オブジェクトの作成1.
)2. MediaExtractorオブジェクト(のファイルsetDataSourceの必要性を追加
)(3.forビデオトラックを取得するためのサイクルとオーディオトラックMediaExtractor#selectTrack、とにMediaMuxerに追加
(MediaMuxer#addTrack)
4マージを開始

オーディオとビデオの4合成

/**
     * 合成视频和音频
     */
    fun compoundVideoAndAudio() {
    	//1.开始合成
        mMediaMuxer.start()

        //2.输入提取到的视频,videoMuxerTrackIndex是之前addTrack生成的下标,
        //如果为-1就是添加失败
        if (-1 != videoMuxerTrackIndex) {

            //描述缓冲区数据信息类,最后Muxer合成要求有的东西
            val videoBufferInfo = MediaCodec.BufferInfo()

            //创建缓冲区,最后Muxer合成要求有的东西
            val videoByteBuffer = ByteBuffer.allocate(maxFrameSize)
            while (true) {
                /3./获取样本大小
                val videoSampleSize = mVideoMediaExtractor.readSampleData(videoByteBuffer, 0)
                if (videoSampleSize < 0) {
                    break
                }

                //4.设置样本信息
                videoBufferInfo.offset = 0  //堆buffer缓冲区写入时的字节偏移
                videoBufferInfo.size = videoSampleSize
                videoBufferInfo.flags = mVideoMediaExtractor.sampleFlags
                //读取到的文件的时间戳,单位是微秒
                videoBufferInfo.presentationTimeUs += 1000 * 1000 / frameRate   //每次加每帧的微秒数
				
				//MediaMuxer写入样本数据
				//videoMuxerTrackIndex   之前加入Muxer的视频轨下标
				//videoByteBuffer 上面创建的Buffer对象
				//videoBufferInfo 上面创建的BufferInfo对象
                mMediaMuxer.writeSampleData(videoMuxerTrackIndex, videoByteBuffer, videoBufferInfo)

                //5.推进到下个样本  类似快进
                mVideoMediaExtractor.advance()
            }
        }

        /**
         * 合成音频,和视频类似
         */

        if (-1 != audioMuxerTrackIndex) {
            val audioBufferInfo = MediaCodec.BufferInfo()
            val audioByteBuffer = ByteBuffer.allocate(maxAudioSize)

            while (true) {
                val audioSampleSize = mAudioMediaExtractor.readSampleData(audioByteBuffer, 0)
                if (audioSampleSize < 0) {
                    break
                }

                audioBufferInfo.offset = 0
                audioBufferInfo.size = audioSampleSize
                audioBufferInfo.flags = mAudioMediaExtractor.sampleFlags
                audioBufferInfo.presentationTimeUs += 1000 * 1000 / frameRate

                mMediaMuxer.writeSampleData(audioMuxerTrackIndex, audioByteBuffer, audioBufferInfo)

                mAudioMediaExtractor.advance()
            }
        }
            }
        }
    }

この方法は、従来の方法で呼び出され、そうしてみてください...上記の方法で書かれたキャッチされ、これらのステップは、サブスレッドで行うことができ、最終的には成功した合成かどうかを確認するために、VideoView制御システムを介してビデオoutputVideoPathパスを再生することができます

要約手順
1.バッファオブジェクトを作成し、MediaCodec#BufferInfoオブジェクト
、2サンプルデータを読む検証データサイズ
情報3.完全bufferInfo
バッファの内容がマクサー書き込まれ4.
5.呼び出しMediaExtractor位前進を()、次に進みサンプルデータを、ステップ2-5のループ
6.リリースリソース

重要な考慮事項!
取る1.許可
2.ファイルは、サイズとして、合法的に抽出することを確認しますが、私はMediaExtractor.setDataSourceは()MediaExtractorを初期化することができなかった遭遇、我々は、ビデオのサイズを追加すると、0キロバイトであることが判明し
た合成効果に影響を与えます。3.タイムスタンプは、あなたが注意を払う必要がありますコンピュート

そこの質問やアイデアがあるか、ミスを見つけ、共有してください

おすすめ

転載: blog.csdn.net/One_Month/article/details/90267556