From 6c36863185d389af59519e50a6fc7d8c0a0acd2c Mon Sep 17 00:00:00 2001 From: Laurent Date: Thu, 10 Sep 2020 14:18:20 +0200 Subject: [PATCH] Remove unused MMediaMuxer --- .../android/util/video/MMediaMuxer.kt | 433 ------------------ 1 file changed, 433 deletions(-) delete mode 100644 app/src/main/java/net/pokeranalytics/android/util/video/MMediaMuxer.kt diff --git a/app/src/main/java/net/pokeranalytics/android/util/video/MMediaMuxer.kt b/app/src/main/java/net/pokeranalytics/android/util/video/MMediaMuxer.kt deleted file mode 100644 index abd13f6e..00000000 --- a/app/src/main/java/net/pokeranalytics/android/util/video/MMediaMuxer.kt +++ /dev/null @@ -1,433 +0,0 @@ -package net.pokeranalytics.android.util.video - -import android.app.Activity -import android.app.ProgressDialog -import android.graphics.Bitmap -import android.graphics.BitmapFactory -import android.media.* -import android.media.MediaCodecInfo.CodecCapabilities -import android.os.Environment -import android.util.Log -import net.pokeranalytics.android.util.extensions.dateTimeFileFormatted -import timber.log.Timber -import java.io.File -import java.io.IOException -import java.util.* - - -class MMediaMuxer { - - private var mediaCodec: MediaCodec? = null - private var mediaMuxer: MediaMuxer? = null - private var mRunning = false - private var generateIndex = 0 - private var mTrackIndex = 0 - private var MAX_FRAME_VIDEO = 0 - private var bitList: MutableList? = null - private var bitFirst: MutableList? = null - private var bitLast: MutableList? = null - private var currentIndexFrame = 0 - private var outputPath: String? = null - private var _activity: Activity? = null - private var pd: ProgressDialog? = null - private var _title: String? = null - private var _mess: String? = null - private var completion: ((String) -> (Unit))? = null - - fun init( - activity: Activity?, - width: Int, - height: Int, - title: String?, - mess: String? - ) { - _title = title - _mess = mess - _activity = activity - _width = width - _height = height - Logd("MMediaMuxer Init") - ShowProgressBar() - } - - fun addFrame(byteFrame: ByteArray) { - checkDataListState() - Thread(Runnable { - Logd("Android get Frame") - val bitmap = BitmapFactory.decodeByteArray(byteFrame, 0, byteFrame.size) - Logd("Android convert Bitmap") - val byteConvertFrame = - getNV21(bitmap.width, bitmap.height, bitmap) - Logd("Android convert getNV21") - bitList!!.add(byteConvertFrame) - }).start() - } - - fun addFrame(byteFrame: ByteArray, count: Int, isLast: Boolean) { - var bf = byteFrame - checkDataListState() - Logd("Android get Frames = $count") - val bitmap = BitmapFactory.decodeByteArray(bf, 0, bf.size) - Logd("Android convert Bitmap") - bf = getNV21(bitmap.width, bitmap.height, bitmap) - Logd("Android convert getNV21") - for (i in 0 until count) { - if (isLast) { - bitLast!!.add(bf) - } else { - bitFirst!!.add(bf) - } - } - } - - fun createVideo(handler: (String) -> (Unit)) { - this.completion = handler - currentIndexFrame = 0 - Logd("Prepare Frames Data") - bitFirst!!.addAll(bitList!!) - bitFirst!!.addAll(bitLast!!) - MAX_FRAME_VIDEO = bitFirst!!.size - Logd("CreateVideo") - mRunning = true - bufferEncoder() - } - - fun GetStateEncoder(): Boolean { - return mRunning - } - - fun GetPath(): String? { - return outputPath - } - - fun onBackPressed() { - mRunning = false - } - - fun ShowProgressBar() { - _activity?.runOnUiThread { - pd = ProgressDialog(_activity) - pd!!.setTitle(_title) - pd!!.setCancelable(false) - pd!!.setMessage(_mess) - pd!!.setCanceledOnTouchOutside(false) - pd!!.show() - } - } - - fun HideProgressBar() { - Thread(Runnable { _activity?.runOnUiThread { pd!!.dismiss() } }).start() - } - - private fun bufferEncoder() { - val runnable = Runnable { - try { - Logd("PrepareEncoder start") - prepareEncoder() - Logd("PrepareEncoder end") - } catch (e: IOException) { - Loge(e.message) - } - try { - while (mRunning) { - encode() - } - } finally { - Logd("release") - Release() - HideProgressBar() - bitFirst = null - bitLast = null - } - } - val thread = Thread(runnable) - thread.start() - } - - fun ClearTask() { - bitList = null - bitFirst = null - bitLast = null - } - - @Throws(IOException::class) - private fun prepareEncoder() { -// val codecInfo = selectCodec(MIME_TYPE) -// if (codecInfo == null) { -// Loge("Unable to find an appropriate codec for $MIME_TYPE") -// } - - val codec = MediaCodec.createEncoderByType(MIME_TYPE) - - val colorFormat: Int - colorFormat = try { - selectColorFormat(codec.codecInfo, MIME_TYPE) - } catch (e: Exception) { - Timber.d(">>> color format exception: $e") - CodecCapabilities.COLOR_FormatYUV420SemiPlanar - } - - Logd("Selected codec: " + codec.name) - Logd("Selected color format: $colorFormat") - -// mediaCodec = MediaCodec.createByCodecName(codecInfo.name) - - mediaCodec = codec - - val mediaFormat = MediaFormat.createVideoFormat(MIME_TYPE, _width, _height) - mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE) - mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE) - mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat) - mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL) - - mediaCodec?.let { - it.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE) - it.start() - Timber.d("format2: ${it.outputFormat}") - } - - try { - val formattedDate = Date().dateTimeFileFormatted - val path = File( - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES), - "video_${formattedDate}.mp4" - ).toString() - outputPath = path - mediaMuxer = MediaMuxer(path, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4) - } catch (ioe: IOException) { - Loge("MediaMuxer creation failed: ${ioe.message}") - } - } - - private fun encode() { - while (true) { - if (!mRunning) { - break - } - Logd("Encode start") - val TIMEOUT_USEC: Long = 5000 - val inputBufIndex = mediaCodec!!.dequeueInputBuffer(TIMEOUT_USEC) - val ptsUsec = - computePresentationTime(generateIndex.toLong(), - FRAME_RATE - ) - if (inputBufIndex >= 0) { - val input = bitFirst!![currentIndexFrame] - val inputBuffer = mediaCodec!!.getInputBuffer(inputBufIndex) - inputBuffer?.clear() - inputBuffer?.put(input) - mediaCodec!!.queueInputBuffer(inputBufIndex, 0, input.size, ptsUsec, 0) - generateIndex++ - } - val mBufferInfo = MediaCodec.BufferInfo() - val encoderStatus = mediaCodec!!.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC) - if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) { // no output available yet - Loge( - "No output from encoder available" - ) - } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { // not expected for an encoder - val newFormat = mediaCodec!!.outputFormat - mTrackIndex = mediaMuxer!!.addTrack(newFormat) - mediaMuxer!!.start() - } else if (encoderStatus < 0) { - Loge( - "unexpected result from encoder.dequeueOutputBuffer: $encoderStatus" - ) - } else if (mBufferInfo.size != 0) { - val encodedData = mediaCodec!!.getOutputBuffer(encoderStatus) - if (encodedData == null) { - Loge( - "encoderOutputBuffer $encoderStatus was null" - ) - } else { - encodedData.position(mBufferInfo.offset) - encodedData.limit(mBufferInfo.offset + mBufferInfo.size) - mediaMuxer!!.writeSampleData(mTrackIndex, encodedData, mBufferInfo) - mediaCodec!!.releaseOutputBuffer(encoderStatus, false) - } - } - currentIndexFrame++ - if (currentIndexFrame > MAX_FRAME_VIDEO - 1) { - Log.d(TAG, "mRunning = false;") - mRunning = false - } - Logd("Encode end") - } - } - - private fun Release() { - if (mediaCodec != null) { - mediaCodec!!.stop() - mediaCodec!!.release() - mediaCodec = null - Logd("RELEASE CODEC") - } - if (mediaMuxer != null) { - mediaMuxer!!.stop() - mediaMuxer!!.release() - mediaMuxer = null - Logd("RELEASE MUXER, path = $outputPath") - } - - this.outputPath?.let { path -> - this.completion?.invoke(path) - } ?: run { - Logd("no path") - } - - } - - private fun getNV21(inputWidth: Int, inputHeight: Int, scaled: Bitmap): ByteArray { - val argb = IntArray(inputWidth * inputHeight) - scaled.getPixels(argb, 0, inputWidth, 0, 0, inputWidth, inputHeight) - val yuv = ByteArray(inputWidth * inputHeight * 3 / 2) - encodeYUV420SP(yuv, argb, inputWidth, inputHeight) - scaled.recycle() - return yuv - } - - private fun encodeYUV420SP(yuv420sp: ByteArray, argb: IntArray, width: Int, height: Int) { - - val frameSize = width * height - var yIndex = 0 - var uvIndex = frameSize - var a: Int - var R: Int - var G: Int - var B: Int - var Y: Int - var U: Int - var V: Int - var index = 0 - for (j in 0 until height) { - for (i in 0 until width) { - - a = argb[index] and -0x1000000 shr 24 // a is not used obviously - R = argb[index] and 0xff0000 shr 16 - G = argb[index] and 0xff00 shr 8 - B = argb[index] and 0xff shr 0 - - Y = (66 * R + 129 * G + 25 * B + 128 shr 8) + 16 - U = (-38 * R - 74 * G + 112 * B + 128 shr 8) + 128 - V = (112 * R - 94 * G - 18 * B + 128 shr 8) + 128 - - yuv420sp[yIndex++] = (if (Y < 0) 0 else if (Y > 255) 255 else Y).toByte() - if (j % 2 == 0 && index % 2 == 0) { - yuv420sp[uvIndex++] = (if (U < 0) 0 else if (U > 255) 255 else U).toByte() - yuv420sp[uvIndex++] = (if (V < 0) 0 else if (V > 255) 255 else V).toByte() - } - - index++ - } - } - } - - private fun checkDataListState() { - if (bitList == null) { - bitList = ArrayList() - } - if (bitFirst == null) { - bitFirst = ArrayList() - } - if (bitLast == null) { - bitLast = ArrayList() - } - } - - private fun computePresentationTime(frameIndex: Long, framerate: Int): Long { - return 132 + frameIndex * 1000000 / framerate - } - - companion object { - private const val MIME_TYPE = MediaFormat.MIMETYPE_VIDEO_AVC // H.264 Advanced Video Coding - private var _width = 512 - private var _height = 512 - private const val BIT_RATE = 2000000 // 800000 - private const val IFRAME_INTERVAL = 1 - private const val FRAME_RATE = 30 // 50 - // private const val DEBUG = false - private const val TAG = "CODEC" - /** - * Returns the first codec capable of encoding the specified MIME type, or - * null if no match was found. - */ - private fun selectCodec(mimeType: String): MediaCodecInfo? { - val numCodecs = MediaCodecList.getCodecCount() - - val validCodecs = mutableListOf() - for (i in 0 until numCodecs) { - val codecInfo = MediaCodecList.getCodecInfoAt(i) - if (!codecInfo.isEncoder) { - continue - } - - val types = codecInfo.supportedTypes - for (j in types.indices) { - if (types[j].equals(mimeType, ignoreCase = true)) { - validCodecs.add(codecInfo) -// return codecInfo - } - } - } - /** - * OMX.qcom.video.encoder.avc - * OMX.google.h264.encoder - */ - - validCodecs.forEach { - Timber.d("VALID CODEC name = ${it.name}") - } - - return validCodecs.firstOrNull() - } - - /** - * Returns a color format that is supported by the codec and by this test - * code. If no match is found, this throws a test failure -- the set of - * formats known to the test should be expanded for new platforms. - */ - private fun selectColorFormat(codecInfo: MediaCodecInfo, mimeType: String): Int { - - val capabilities = codecInfo.getCapabilitiesForType(mimeType) - - capabilities.colorFormats.forEach { - Timber.d(">>> Color Format = $it") - } - - for (i in capabilities.colorFormats.indices) { - val colorFormat = capabilities.colorFormats[i] - if (isRecognizedFormat(colorFormat)) { - return colorFormat - } - } - return 0 // not reached - } - - /** - * Returns true if this is a color format that this test code understands - * (i.e. we know how to read and generate frames in this format). - */ - private fun isRecognizedFormat(colorFormat: Int): Boolean { - return when (colorFormat) { - CodecCapabilities.COLOR_FormatYUV420Planar, - CodecCapabilities.COLOR_FormatYUV420PackedPlanar, - CodecCapabilities.COLOR_FormatYUV420SemiPlanar, - CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar, - CodecCapabilities.COLOR_TI_FormatYUV420PackedSemiPlanar -> true - else -> false - } - } - - private fun Logd(Mess: String) { - Timber.d(Mess) -// if (DEBUG) { -// Log.d(TAG, Mess) -// } - } - - private fun Loge(Mess: String?) { - Timber.e("$Mess") -// Log.e(TAG, Mess) - } - } -}