diff --git a/Android/PlayerProj/animplayer/build.gradle b/Android/PlayerProj/animplayer/build.gradle index ae62d52e..92ff1ea1 100644 --- a/Android/PlayerProj/animplayer/build.gradle +++ b/Android/PlayerProj/animplayer/build.gradle @@ -1,15 +1,12 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' android { - compileSdkVersion 28 + compileSdkVersion 33 defaultConfig { minSdkVersion 16 - targetSdkVersion 28 - versionCode 1 - versionName "1.0" + targetSdkVersion 33 } buildTypes { @@ -18,13 +15,14 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } + buildFeatures { + viewBinding true + } + namespace 'com.tencent.qgame.animplayer' } dependencies { - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version") { - exclude module: 'annotations' - } } // jcenter 上传(这个要在底部) diff --git a/Android/PlayerProj/animplayer/src/main/AndroidManifest.xml b/Android/PlayerProj/animplayer/src/main/AndroidManifest.xml index fc0f9fe2..94cbbcfc 100644 --- a/Android/PlayerProj/animplayer/src/main/AndroidManifest.xml +++ b/Android/PlayerProj/animplayer/src/main/AndroidManifest.xml @@ -1,2 +1 @@ - + diff --git a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AnimConfig.kt b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AnimConfig.kt index 421b577a..a729bf7c 100644 --- a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AnimConfig.kt +++ b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AnimConfig.kt @@ -15,8 +15,6 @@ */ package com.tencent.qgame.animplayer -import android.graphics.Bitmap -import android.graphics.MaskFilter import com.tencent.qgame.animplayer.mask.MaskConfig import com.tencent.qgame.animplayer.util.ALog import org.json.JSONException diff --git a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AnimConfigManager.kt b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AnimConfigManager.kt index d7d8cc93..e50917b8 100644 --- a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AnimConfigManager.kt +++ b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AnimConfigManager.kt @@ -167,7 +167,7 @@ class AnimConfigManager(val player: AnimPlayer) { private fun parseBoxHead(boxHead: ByteArray): BoxHead? { if (boxHead.size != 8) return null val head = BoxHead() - var length: Int = 0 + var length = 0 length = length or (boxHead[0].toInt() and 0xff shl 24) length = length or (boxHead[1].toInt() and 0xff shl 16) length = length or (boxHead[2].toInt() and 0xff shl 8) diff --git a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AnimPlayer.kt b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AnimPlayer.kt index 8e4e776b..c5632ae1 100644 --- a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AnimPlayer.kt +++ b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AnimPlayer.kt @@ -27,6 +27,7 @@ class AnimPlayer(val animView: IAnimView) { private const val TAG = "${Constant.TAG}.AnimPlayer" } + var autoDismiss = true var animListener: IAnimListener? = null var decoder: Decoder? = null var audioPlayer: AudioPlayer? = null @@ -39,7 +40,6 @@ class AnimPlayer(val animView: IAnimView) { var defaultFps: Int = 0 var playLoop: Int = 0 set(value) { - decoder?.playLoop = value audioPlayer?.playLoop = value field = value } @@ -136,6 +136,7 @@ class AnimPlayer(val animView: IAnimView) { private fun prepareDecoder() { if (decoder == null) { decoder = HardDecoder(this).apply { + autoDismiss = this@AnimPlayer.autoDismiss playLoop = this@AnimPlayer.playLoop fps = this@AnimPlayer.fps } @@ -148,10 +149,11 @@ class AnimPlayer(val animView: IAnimView) { } fun updateMaskConfig(maskConfig: MaskConfig?) { - configManager.config?.maskConfig = configManager.config?.maskConfig ?: MaskConfig() - configManager.config?.maskConfig?.safeSetMaskBitmapAndReleasePre(maskConfig?.alphaMaskBitmap) - configManager.config?.maskConfig?.maskPositionPair = maskConfig?.maskPositionPair - configManager.config?.maskConfig?.maskTexPair = maskConfig?.maskTexPair + val config = configManager.config?.maskConfig ?: MaskConfig() + configManager.config?.maskConfig = config + config.safeSetMaskBitmapAndReleasePre(maskConfig?.alphaMaskBitmap) + config.maskPositionPair = maskConfig?.maskPositionPair + config.maskTexPair = maskConfig?.maskTexPair } } \ No newline at end of file diff --git a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AnimView.kt b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AnimView.kt index 8729dcf0..efbedeab 100644 --- a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AnimView.kt +++ b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AnimView.kt @@ -18,7 +18,6 @@ package com.tencent.qgame.animplayer import android.content.Context import android.content.res.AssetManager import android.graphics.SurfaceTexture -import android.os.Build import android.os.Handler import android.os.Looper import android.util.AttributeSet @@ -39,7 +38,11 @@ import com.tencent.qgame.animplayer.util.ScaleType import com.tencent.qgame.animplayer.util.ScaleTypeUtil import java.io.File -open class AnimView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0): +class AnimView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : IAnimView, FrameLayout(context, attrs, defStyleAttr), TextureView.SurfaceTextureListener { @@ -47,7 +50,8 @@ open class AnimView @JvmOverloads constructor(context: Context, attrs: Attribute companion object { private const val TAG = "${Constant.TAG}.AnimView" } - private lateinit var player: AnimPlayer + + private val player: AnimPlayer private val uiHandler by lazy { Handler(Looper.getMainLooper()) } private var surface: SurfaceTexture? = null @@ -55,6 +59,7 @@ open class AnimView @JvmOverloads constructor(context: Context, attrs: Attribute private var innerTextureView: InnerTextureView? = null private var lastFile: IFileContainer? = null private val scaleTypeUtil = ScaleTypeUtil() + private var autoDismiss = true // 代理监听 private val animProxyListener by lazy { @@ -74,7 +79,10 @@ open class AnimView @JvmOverloads constructor(context: Context, attrs: Attribute } override fun onVideoComplete() { - hide() + if (autoDismiss) + hide() + else + lastFile?.close() animListener?.onVideoComplete() } @@ -93,28 +101,30 @@ open class AnimView @JvmOverloads constructor(context: Context, attrs: Attribute // 保证AnimView已经布局完成才加入TextureView private var onSizeChangedCalled = false private var needPrepareTextureView = false - private val prepareTextureViewRunnable = Runnable { - removeAllViews() - innerTextureView = InnerTextureView(context).apply { - player = this@AnimView.player - isOpaque = false - surfaceTextureListener = this@AnimView - layoutParams = scaleTypeUtil.getLayoutParam(this) - } - addView(innerTextureView) - } - init { + val obtainStyledAttributes = context.obtainStyledAttributes(attrs, R.styleable.AnimView) + autoDismiss = obtainStyledAttributes.getBoolean(R.styleable.AnimView_anim_view_auto_dismiss, true) + obtainStyledAttributes.recycle() hide() player = AnimPlayer(this) + player.autoDismiss = autoDismiss player.animListener = animProxyListener } override fun prepareTextureView() { if (onSizeChangedCalled) { - uiHandler.post(prepareTextureViewRunnable) + uiHandler.post { + removeAllViews() + innerTextureView = InnerTextureView(context).apply { + player = this@AnimView.player + isOpaque = false + surfaceTextureListener = this@AnimView + layoutParams = scaleTypeUtil.getLayoutParam(this) + } + addView(innerTextureView) + } } else { ALog.e(TAG, "onSizeChanged not called") needPrepareTextureView = true @@ -188,18 +198,18 @@ open class AnimView @JvmOverloads constructor(context: Context, attrs: Attribute } override fun setFetchResource(fetchResource: IFetchResource?) { - player.pluginManager.getMixAnimPlugin()?.resourceRequest = fetchResource + player.pluginManager.getMixAnimPlugin().resourceRequest = fetchResource } override fun setOnResourceClickListener(resourceClickListener: OnResourceClickListener?) { - player.pluginManager.getMixAnimPlugin()?.resourceClickListener = resourceClickListener + player.pluginManager.getMixAnimPlugin().resourceClickListener = resourceClickListener } /** * 兼容方案,优先保证表情显示 */ - open fun enableAutoTxtColorFill(enable: Boolean) { - player.pluginManager.getMixAnimPlugin()?.autoTxtColorFill = enable + fun enableAutoTxtColorFill(enable: Boolean) { + player.pluginManager.getMixAnimPlugin().autoTxtColorFill = enable } override fun setLoop(playLoop: Int) { diff --git a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AudioPlayer.kt b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AudioPlayer.kt index 474c5647..4f2b2efc 100644 --- a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AudioPlayer.kt +++ b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AudioPlayer.kt @@ -16,10 +16,10 @@ package com.tencent.qgame.animplayer import android.media.* +import android.os.Build import com.tencent.qgame.animplayer.file.IFileContainer import com.tencent.qgame.animplayer.util.ALog import com.tencent.qgame.animplayer.util.MediaUtil -import java.lang.RuntimeException class AudioPlayer(val player: AnimPlayer) { @@ -30,14 +30,13 @@ class AudioPlayer(val player: AnimPlayer) { var extractor: MediaExtractor? = null var decoder: MediaCodec? = null var audioTrack: AudioTrack? = null - val decodeThread = HandlerHolder(null, null) + private val decodeThread = HandlerHolder(null, null) var isRunning = false var playLoop = 0 var isStopReq = false var needDestroy = false - private fun prepareThread(): Boolean { return Decoder.createThread(decodeThread, "anim_audio_thread") } @@ -97,7 +96,7 @@ class AudioPlayer(val player: AnimPlayer) { val channelConfig = getChannelConfig(format.getInteger(MediaFormat.KEY_CHANNEL_COUNT)) val bufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, AudioFormat.ENCODING_PCM_16BIT) - val audioTrack = AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, channelConfig, AudioFormat.ENCODING_PCM_16BIT, bufferSize, AudioTrack.MODE_STREAM) + val audioTrack = buildAudioTrack(sampleRate, channelConfig, bufferSize) this.audioTrack = audioTrack val state = audioTrack.state if (state != AudioTrack.STATE_INITIALIZED) { @@ -153,6 +152,31 @@ class AudioPlayer(val player: AnimPlayer) { release() } + @Suppress("DEPRECATION") + private fun buildAudioTrack(sampleRate: Int, channelConfig: Int, bufferSize: Int): AudioTrack { + val streamType = AudioManager.STREAM_MUSIC + val encoding = AudioFormat.ENCODING_PCM_16BIT + val modeStream = AudioTrack.MODE_STREAM + val audioTrack = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + val audioAttributes = AudioAttributes.Builder() + .setLegacyStreamType(streamType) + .build() + val audioFormat = AudioFormat.Builder() + .setSampleRate(sampleRate) + .setEncoding(encoding) + .setChannelMask(channelConfig) + .build() + AudioTrack.Builder().setAudioFormat(audioFormat) + .setAudioAttributes(audioAttributes) + .setBufferSizeInBytes(bufferSize) + .setTransferMode(modeStream) + .build() + } else { + AudioTrack(streamType, sampleRate, channelConfig, encoding, bufferSize, modeStream) + } + return audioTrack + } + private fun release() { try { diff --git a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/Decoder.kt b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/Decoder.kt index b6ac7bf8..0c82e219 100644 --- a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/Decoder.kt +++ b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/Decoder.kt @@ -66,7 +66,6 @@ abstract class Decoder(val player: AnimPlayer) : IAnimListener { speedControlUtil.setFixedPlaybackRate(value) field = value } - var playLoop = 0 // 循环播放次数 var isRunning = false // 是否正在运行 var isStopReq = false // 是否需要停止 val speedControlUtil by lazy { SpeedControlUtil() } diff --git a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/HardDecoder.kt b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/HardDecoder.kt index b12bb3bc..d352b129 100644 --- a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/HardDecoder.kt +++ b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/HardDecoder.kt @@ -49,6 +49,7 @@ class HardDecoder(player: AnimPlayer) : Decoder(player), SurfaceTexture.OnFrameA // 动画是否需要走YUV渲染逻辑的标志位 private var needYUV = false private var outputFormat: MediaFormat? = null + var autoDismiss = true override fun start(fileContainer: IFileContainer) { isStopReq = false @@ -82,30 +83,30 @@ class HardDecoder(player: AnimPlayer) : Decoder(player), SurfaceTexture.OnFrameA private fun startPlay(fileContainer: IFileContainer) { - var extractor: MediaExtractor? = null - var decoder: MediaCodec? = null - var format: MediaFormat? = null - var trackIndex = 0 + val extractor: MediaExtractor + val format: MediaFormat try { extractor = MediaUtil.getExtractor(fileContainer) - trackIndex = MediaUtil.selectVideoTrack(extractor) + val trackIndex = MediaUtil.selectVideoTrack(extractor) if (trackIndex < 0) { throw RuntimeException("No video track found") } extractor.selectTrack(trackIndex) format = extractor.getTrackFormat(trackIndex) - if (format == null) throw RuntimeException("format is null") // 是否支持h265 if (MediaUtil.checkIsHevc(format)) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP - || !MediaUtil.checkSupportCodec(MediaUtil.MIME_HEVC)) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP + || !MediaUtil.checkSupportCodec(MediaUtil.MIME_HEVC) + ) { - onFailed(Constant.REPORT_ERROR_TYPE_HEVC_NOT_SUPPORT, + onFailed( + Constant.REPORT_ERROR_TYPE_HEVC_NOT_SUPPORT, "${Constant.ERROR_MSG_HEVC_NOT_SUPPORT} " + "sdk:${Build.VERSION.SDK_INT}" + - ",support hevc:" + MediaUtil.checkSupportCodec(MediaUtil.MIME_HEVC)) + ",support hevc:" + MediaUtil.checkSupportCodec(MediaUtil.MIME_HEVC) + ) release(null, null) return } @@ -123,42 +124,48 @@ class HardDecoder(player: AnimPlayer) : Decoder(player), SurfaceTexture.OnFrameA // 但是这样直接判断有风险,后期想办法改 needYUV = videoWidth % 16 != 0 && player.enableVersion1 - try { - if (!prepareRender(needYUV)) { - throw RuntimeException("render create fail") - } - } catch (t: Throwable) { - onFailed(Constant.REPORT_ERROR_TYPE_CREATE_RENDER, "${Constant.ERROR_MSG_CREATE_RENDER} e=$t") - release(null, null) - return - } - - preparePlay(videoWidth, videoHeight) - - render?.apply { - glTexture = SurfaceTexture(getExternalTexture()).apply { - setOnFrameAvailableListener(this@HardDecoder) - setDefaultBufferSize(videoWidth, videoHeight) - } - clearFrame() - } + if (prepare()) return } catch (e: Throwable) { ALog.e(TAG, "MediaExtractor exception e=$e", e) onFailed(Constant.REPORT_ERROR_TYPE_EXTRACTOR_EXC, "${Constant.ERROR_MSG_EXTRACTOR_EXC} e=$e") - release(decoder, extractor) + release(null, null) return } + startEncoder(format, extractor) + } + + private fun prepare(): Boolean { + try { + if (!prepareRender(needYUV)) { + throw RuntimeException("render create fail") + } + } catch (t: Throwable) { + onFailed(Constant.REPORT_ERROR_TYPE_CREATE_RENDER, "${Constant.ERROR_MSG_CREATE_RENDER} e=$t") + release(null, null) + return true + } + + preparePlay(videoWidth, videoHeight) + + render?.apply { + glTexture = SurfaceTexture(getExternalTexture()).apply { + setOnFrameAvailableListener(this@HardDecoder) + setDefaultBufferSize(videoWidth, videoHeight) + } + clearFrame() + } + return false + } + + private fun startEncoder(format: MediaFormat, extractor: MediaExtractor) { try { val mime = format.getString(MediaFormat.KEY_MIME) ?: "" ALog.i(TAG, "Video MIME is $mime") - decoder = MediaCodec.createDecoderByType(mime).apply { + MediaCodec.createDecoderByType(mime).apply { if (needYUV) { - format.setInteger( - MediaFormat.KEY_COLOR_FORMAT, - MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar - ) + format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar) configure(format, null, null, 0) } else { surface = Surface(glTexture) @@ -172,27 +179,25 @@ class HardDecoder(player: AnimPlayer) : Decoder(player), SurfaceTexture.OnFrameA } catch (e: Throwable) { ALog.e(TAG, "MediaCodec exception e=$e", e) onFailed(Constant.REPORT_ERROR_TYPE_DECODE_EXC, "${Constant.ERROR_MSG_DECODE_EXC} e=$e") - release(decoder, extractor) + release(this, extractor) } } } } catch (e: Throwable) { ALog.e(TAG, "MediaCodec configure exception e=$e", e) onFailed(Constant.REPORT_ERROR_TYPE_DECODE_EXC, "${Constant.ERROR_MSG_DECODE_EXC} e=$e") - release(decoder, extractor) + release(null, extractor) return } } private fun startDecode(extractor: MediaExtractor ,decoder: MediaCodec) { - val TIMEOUT_USEC = 10000L + val timeout = 10000L var inputChunk = 0 var outputDone = false var inputDone = false var frameIndex = 0 - var isLoop = false - - val decoderInputBuffers = decoder.inputBuffers + var isLooping = false while (!outputDone) { if (isStopReq) { @@ -202,9 +207,13 @@ class HardDecoder(player: AnimPlayer) : Decoder(player), SurfaceTexture.OnFrameA } if (!inputDone) { - val inputBufIndex = decoder.dequeueInputBuffer(TIMEOUT_USEC) + val inputBufIndex = decoder.dequeueInputBuffer(timeout) if (inputBufIndex >= 0) { - val inputBuf = decoderInputBuffers[inputBufIndex] + val inputBuf = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + decoder.getInputBuffer(inputBufIndex) + } else { + decoder.inputBuffers[inputBufIndex] + } ?: throw Exception() val chunkSize = extractor.readSampleData(inputBuf, 0) if (chunkSize < 0) { decoder.queueInputBuffer(inputBufIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM) @@ -223,25 +232,12 @@ class HardDecoder(player: AnimPlayer) : Decoder(player), SurfaceTexture.OnFrameA } if (!outputDone) { - val decoderStatus = decoder.dequeueOutputBuffer(bufferInfo, TIMEOUT_USEC) + val decoderStatus = decoder.dequeueOutputBuffer(bufferInfo, timeout) when { decoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER -> ALog.d(TAG, "no output from decoder available") decoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED -> ALog.d(TAG, "decoder output buffers changed") decoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED -> { - outputFormat = decoder.outputFormat - outputFormat?.apply { - try { - // 有可能取到空值,做一层保护 - val stride = getInteger("stride") - val sliceHeight = getInteger("slice-height") - if (stride > 0 && sliceHeight > 0) { - alignWidth = stride - alignHeight = sliceHeight - } - } catch (t: Throwable) { - ALog.e(TAG, "$t", t) - } - } + handleFormatChange(decoder) ALog.i(TAG, "decoder output format changed: $outputFormat") } decoderStatus < 0 -> { @@ -250,9 +246,8 @@ class HardDecoder(player: AnimPlayer) : Decoder(player), SurfaceTexture.OnFrameA else -> { var loop = 0 if (bufferInfo.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM != 0) { - loop = --playLoop - player.playLoop = playLoop // 消耗loop次数 自动恢复后能有正确的loop次数 - outputDone = playLoop <= 0 + loop = --player.playLoop + outputDone = player.playLoop <= 0 } val doRender = !outputDone if (doRender) { @@ -266,7 +261,7 @@ class HardDecoder(player: AnimPlayer) : Decoder(player), SurfaceTexture.OnFrameA // release & render decoder.releaseOutputBuffer(decoderStatus, doRender && !needYUV) - if (frameIndex == 0 && !isLoop) { + if (frameIndex == 0 && !isLooping) { onVideoStart() } player.pluginManager.onDecoding(frameIndex) @@ -282,10 +277,10 @@ class HardDecoder(player: AnimPlayer) : Decoder(player), SurfaceTexture.OnFrameA decoder.flush() speedControlUtil.reset() frameIndex = 0 - isLoop = true + isLooping = true } if (outputDone) { - release(decoder, extractor) + release(decoder, extractor, true) } } } @@ -294,6 +289,23 @@ class HardDecoder(player: AnimPlayer) : Decoder(player), SurfaceTexture.OnFrameA } + private fun handleFormatChange(decoder: MediaCodec) { + outputFormat = decoder.outputFormat + outputFormat?.apply { + try { + // 有可能取到空值,做一层保护 + val stride = getInteger("stride") + val sliceHeight = getInteger("slice-height") + if (stride > 0 && sliceHeight > 0) { + alignWidth = stride + alignHeight = sliceHeight + } + } catch (t: Throwable) { + ALog.e(TAG, "$t", t) + } + } + } + /** * 获取到解码后每一帧的YUV数据,裁剪出正确的尺寸 */ @@ -302,21 +314,15 @@ class HardDecoder(player: AnimPlayer) : Decoder(player), SurfaceTexture.OnFrameA outputBuffer?.let { it.position(0) it.limit(bufferInfo.offset + bufferInfo.size) - var yuvData = ByteArray(outputBuffer.remaining()) + val yuvData = ByteArray(outputBuffer.remaining()) outputBuffer.get(yuvData) if (yuvData.isNotEmpty()) { - var yData = ByteArray(videoWidth * videoHeight) - var uData = ByteArray(videoWidth * videoHeight / 4) - var vData = ByteArray(videoWidth * videoHeight / 4) - - if (outputFormat?.getInteger(MediaFormat.KEY_COLOR_FORMAT) == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar) { - yuvData = yuv420spTop(yuvData) - } + val yData = ByteArray(videoWidth * videoHeight) + val uData = ByteArray(videoWidth * videoHeight / 4) + val vData = ByteArray(videoWidth * videoHeight / 4) - yuvCopy(yuvData, 0, alignWidth, alignHeight, yData, videoWidth, videoHeight) - yuvCopy(yuvData, alignWidth * alignHeight, alignWidth / 2, alignHeight / 2, uData, videoWidth / 2, videoHeight / 2) - yuvCopy(yuvData, alignWidth * alignHeight * 5 / 4, alignWidth / 2, alignHeight / 2, vData, videoWidth / 2, videoHeight / 2) + processData(yuvData, yData, uData, vData) render?.setYUVData(videoWidth, videoHeight, yData, uData, vData) renderData() @@ -324,6 +330,32 @@ class HardDecoder(player: AnimPlayer) : Decoder(player), SurfaceTexture.OnFrameA } } + private fun processData(yuvData: ByteArray, yData: ByteArray, uData: ByteArray, vData: ByteArray) { + val data = if (outputFormat?.getInteger(MediaFormat.KEY_COLOR_FORMAT) == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar) { + yuv420spTop(yuvData) + } else yuvData + + yuvCopy(data, 0, alignWidth, alignHeight, yData, videoWidth, videoHeight) + yuvCopy( + data, + alignWidth * alignHeight, + alignWidth / 2, + alignHeight / 2, + uData, + videoWidth / 2, + videoHeight / 2 + ) + yuvCopy( + data, + alignWidth * alignHeight * 5 / 4, + alignWidth / 2, + alignHeight / 2, + vData, + videoWidth / 2, + videoHeight / 2 + ) + } + private fun yuv420spTop(yuv420sp: ByteArray): ByteArray { val yuv420p = ByteArray(yuv420sp.size) val ySize = alignWidth * alignHeight @@ -347,9 +379,10 @@ class HardDecoder(player: AnimPlayer) : Decoder(player), SurfaceTexture.OnFrameA } } - private fun release(decoder: MediaCodec?, extractor: MediaExtractor?) { + private fun release(decoder: MediaCodec?, extractor: MediaExtractor?, isDone: Boolean = false) { renderThread.handler?.post { - render?.clearFrame() + if (autoDismiss || !isDone) + render?.clearFrame() try { ALog.i(TAG, "release") decoder?.apply { @@ -387,6 +420,7 @@ class HardDecoder(player: AnimPlayer) : Decoder(player), SurfaceTexture.OnFrameA private fun destroyInner() { ALog.i(TAG, "destroyInner") renderThread.handler?.post { + render?.clearFrame() player.pluginManager.onDestroy() render?.destroyRender() render = null diff --git a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/IRenderListener.kt b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/IRenderListener.kt index 77c44c58..c280763b 100644 --- a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/IRenderListener.kt +++ b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/IRenderListener.kt @@ -50,5 +50,5 @@ interface IRenderListener { fun swapBuffers() - fun setYUVData(width: Int, height: Int, y: ByteArray?, u: ByteArray?, v: ByteArray?) {} + fun setYUVData(width: Int, height: Int, y: ByteArray, u: ByteArray, v: ByteArray) {} } \ No newline at end of file diff --git a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/YUVRender.kt b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/YUVRender.kt index 2b24be2d..b934d8d9 100644 --- a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/YUVRender.kt +++ b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/YUVRender.kt @@ -146,7 +146,7 @@ class YUVRender (surfaceTexture: SurfaceTexture): IRenderListener { eglUtil.swapBuffers() } - override fun setYUVData(width: Int, height: Int, y: ByteArray?, u: ByteArray?, v: ByteArray?) { + override fun setYUVData(width: Int, height: Int, y: ByteArray, u: ByteArray, v: ByteArray) { widthYUV = width heightYUV = height this.y = ByteBuffer.wrap(y) diff --git a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/mask/MaskConfig.kt b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/mask/MaskConfig.kt index 02c88390..f01272d4 100644 --- a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/mask/MaskConfig.kt +++ b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/mask/MaskConfig.kt @@ -24,28 +24,31 @@ class MaskConfig() { var maskTexPair: Pair? = null //遮罩坐标矩形 var maskPositionPair: Pair? = null //内容坐标矩形 - constructor(bitmap: Bitmap?, positionPair :Pair?, texPair: Pair?) : this() { + constructor( + bitmap: Bitmap?, + positionPair: Pair?, + texPair: Pair? + ) : this() { maskPositionPair = positionPair maskTexPair = texPair alphaMaskBitmap = bitmap } private var maskTexId = 0 - fun getMaskTexId() : Int { + fun getMaskTexId(): Int { return maskTexId } - fun updateMaskTex() : Int { + + fun updateMaskTex(): Int { maskTexId = TextureLoadUtil.loadTexture(alphaMaskBitmap) - return maskTexId + return maskTexId } var alphaMaskBitmap: Bitmap? = null //遮罩 - private set(value) { - field = value - } - + private set + fun safeSetMaskBitmapAndReleasePre(bitmap: Bitmap?) { - if (maskTexId > 0) { //释放 + if (maskTexId > 0) { //释放 TextureLoadUtil.releaseTexure(maskTexId) maskTexId = 0 } diff --git a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/mix/Frame.kt b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/mix/Frame.kt index 15d5eb88..dc414319 100644 --- a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/mix/Frame.kt +++ b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/mix/Frame.kt @@ -53,9 +53,9 @@ class FrameSet(json: JSONObject) { init { index = json.getInt("i") val objJsonArray = json.getJSONArray("obj") - val objLen = objJsonArray?.length() ?: 0 + val objLen = objJsonArray.length() ?: 0 for (i in 0 until objLen) { - val frameJson = objJsonArray?.getJSONObject(i) ?: continue + val frameJson = objJsonArray.getJSONObject(i) ?: continue val frame = Frame(index, frameJson) list.add(frame) } @@ -73,9 +73,9 @@ class FrameAll(json: JSONObject) { init { val frameJsonArray = json.getJSONArray("frame") - val frameLen = frameJsonArray?.length() ?: 0 + val frameLen = frameJsonArray.length() for (i in 0 until frameLen) { - val frameSetJson = frameJsonArray?.getJSONObject(i) ?: continue + val frameSetJson = frameJsonArray.getJSONObject(i) ?: continue val frameSet = FrameSet(frameSetJson) map.put(frameSet.index, frameSet) } diff --git a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/mix/MixShader.kt b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/mix/MixShader.kt index 9c5dc4b4..2b24f343 100644 --- a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/mix/MixShader.kt +++ b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/mix/MixShader.kt @@ -62,30 +62,20 @@ class MixShader { } // Shader program - val program: Int + val program = ShaderUtil.createProgram(VERTEX, FRAGMENT) // Uniform locations - val uTextureSrcUnitLocation: Int - val uTextureMaskUnitLocation: Int - val uIsFillLocation: Int - val uColorLocation: Int + val uTextureSrcUnitLocation = GLES20.glGetUniformLocation(program, U_TEXTURE_SRC_UNIT) + val uTextureMaskUnitLocation = GLES20.glGetUniformLocation(program, U_TEXTURE_MASK_UNIT) + val uIsFillLocation = GLES20.glGetUniformLocation(program, U_IS_FILL) + val uColorLocation = GLES20.glGetUniformLocation(program, U_COLOR) // Attribute locations - val aPositionLocation: Int - val aTextureSrcCoordinatesLocation: Int - val aTextureMaskCoordinatesLocation: Int - - init { - program = ShaderUtil.createProgram(VERTEX, FRAGMENT) - uTextureSrcUnitLocation = GLES20.glGetUniformLocation(program, U_TEXTURE_SRC_UNIT) - uTextureMaskUnitLocation = GLES20.glGetUniformLocation(program, U_TEXTURE_MASK_UNIT) - uIsFillLocation = GLES20.glGetUniformLocation(program, U_IS_FILL) - uColorLocation = GLES20.glGetUniformLocation(program, U_COLOR) - - aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION) - aTextureSrcCoordinatesLocation = GLES20.glGetAttribLocation(program, A_TEXTURE_SRC_COORDINATES) - aTextureMaskCoordinatesLocation = GLES20.glGetAttribLocation(program, A_TEXTURE_MASK_COORDINATES) - } + val aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION) + val aTextureSrcCoordinatesLocation = + GLES20.glGetAttribLocation(program, A_TEXTURE_SRC_COORDINATES) + val aTextureMaskCoordinatesLocation = + GLES20.glGetAttribLocation(program, A_TEXTURE_MASK_COORDINATES) fun useProgram() { GLES20.glUseProgram(program) diff --git a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/mix/Src.kt b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/mix/Src.kt index 779ec53a..c91cdf6c 100644 --- a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/mix/Src.kt +++ b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/mix/Src.kt @@ -21,7 +21,10 @@ import com.tencent.qgame.animplayer.Constant import com.tencent.qgame.animplayer.util.ALog import org.json.JSONObject -class Src { +class Src// 可选 + +// 可选 + (json: JSONObject) { companion object { private const val TAG = "${Constant.TAG}.Src" } @@ -61,11 +64,10 @@ class Src { var fitType = FitType.FIT_XY var srcTextureId = 0 - constructor(json: JSONObject) { + init { srcId = json.getString("srcId") w = json.getInt("w") h = json.getInt("h") - // 可选 var colorStr = json.optString("color", "#000000") if (colorStr.isEmpty()) { colorStr = "#000000" @@ -73,7 +75,6 @@ class Src { color = Color.parseColor(colorStr) srcTag = json.getString("srcTag") txt = srcTag - srcType = when(json.getString("srcType")) { SrcType.IMG.type -> SrcType.IMG SrcType.TXT.type -> SrcType.TXT @@ -88,8 +89,6 @@ class Src { FitType.CENTER_FULL.type -> FitType.CENTER_FULL else -> FitType.FIT_XY } - - // 可选 style = when(json.optString("style", "")) { Style.BOLD.style -> Style.BOLD else -> Style.DEFAULT @@ -111,9 +110,9 @@ class SrcMap(json: JSONObject) { init { val srcJsonArray = json.getJSONArray("src") - val srcLen = srcJsonArray?.length() ?: 0 + val srcLen = srcJsonArray.length() for (i in 0 until srcLen) { - val srcJson = srcJsonArray?.getJSONObject(i) ?: continue + val srcJson = srcJsonArray.getJSONObject(i) ?: continue val src = Src(srcJson) if (src.srcType != Src.SrcType.UNKNOWN) { // 不认识的srcType丢弃 map[src.srcId] = src diff --git a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/plugin/AnimPluginManager.kt b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/plugin/AnimPluginManager.kt index bf717c98..c6ed04e7 100644 --- a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/plugin/AnimPluginManager.kt +++ b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/plugin/AnimPluginManager.kt @@ -44,11 +44,11 @@ class AnimPluginManager(val player: AnimPlayer) { // 帧不相同的次数, 连续多次不同则直接使用decodeIndex private var frameDiffTimes = 0 - fun getMixAnimPlugin(): MixAnimPlugin? { + fun getMixAnimPlugin(): MixAnimPlugin { return mixAnimPlugin } - - fun getMaskAnimPlugin() : MaskAnimPlugin? { + + fun getMaskAnimPlugin(): MaskAnimPlugin { return maskAnimPlugin } diff --git a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/util/GlFloatArray.kt b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/util/GlFloatArray.kt index 2c1b599d..6d67a9f7 100644 --- a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/util/GlFloatArray.kt +++ b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/util/GlFloatArray.kt @@ -26,15 +26,11 @@ class GlFloatArray { val array = FloatArray(8) - private var floatBuffer: FloatBuffer - - init { - floatBuffer = ByteBuffer - .allocateDirect(array.size * 4) - .order(ByteOrder.nativeOrder()) - .asFloatBuffer() - .put(array) - } + private var floatBuffer: FloatBuffer = ByteBuffer + .allocateDirect(array.size * 4) + .order(ByteOrder.nativeOrder()) + .asFloatBuffer() + .put(array) fun setArray(array: FloatArray) { floatBuffer.position(0) diff --git a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/util/MediaUtil.kt b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/util/MediaUtil.kt index b71703c9..df381023 100644 --- a/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/util/MediaUtil.kt +++ b/Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/util/MediaUtil.kt @@ -20,6 +20,7 @@ import android.media.MediaExtractor import android.media.MediaFormat import com.tencent.qgame.animplayer.Constant import com.tencent.qgame.animplayer.file.IFileContainer +import java.util.* import kotlin.collections.HashMap @@ -81,7 +82,7 @@ object MediaUtil { isTypeMapInit = true getSupportType() } - return supportTypeMap.containsKey(mimeType.toLowerCase()) + return supportTypeMap.containsKey(mimeType.lowercase(Locale.ROOT)) } @@ -95,7 +96,7 @@ object MediaUtil { } val types = codecInfo.supportedTypes for (j in types.indices) { - supportTypeMap[types[j].toLowerCase()] = true + supportTypeMap[types[j].lowercase(Locale.ROOT)] = true } } ALog.i(TAG, "supportType=${supportTypeMap.keys}") diff --git a/Android/PlayerProj/animplayer/src/main/res/values/attrs.xml b/Android/PlayerProj/animplayer/src/main/res/values/attrs.xml new file mode 100644 index 00000000..469e030f --- /dev/null +++ b/Android/PlayerProj/animplayer/src/main/res/values/attrs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Android/PlayerProj/animtool/build.gradle b/Android/PlayerProj/animtool/build.gradle index 8701c24a..1736d370 100644 --- a/Android/PlayerProj/animtool/build.gradle +++ b/Android/PlayerProj/animtool/build.gradle @@ -20,7 +20,7 @@ repositories { jar { manifest { attributes( - 'Main-Class': 'com.tencent.qgame.playerproj.animtool.Main' + 'Main-Class': 'com.tencent.qgame.playerproj.animtool.Main' ) } } \ No newline at end of file diff --git a/Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/AnimTool.java b/Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/AnimTool.java index 7cd080c2..18025a21 100644 --- a/Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/AnimTool.java +++ b/Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/AnimTool.java @@ -20,18 +20,22 @@ import com.tencent.qgame.playerproj.animtool.vapx.SrcSet; import javax.imageio.ImageIO; + import java.awt.image.BufferedImage; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.util.Locale; + +import jdk.vm.ci.meta.Local; public class AnimTool { private static final String TAG = "AnimTool"; - public static final String OUTPUT_DIR = "output"+ File.separator; - public static final String FRAME_IMAGE_DIR = "frames"+ File.separator; + public static final String OUTPUT_DIR = "output" + File.separator; + public static final String FRAME_IMAGE_DIR = "frames" + File.separator; public static final String VIDEO_FILE = "video.mp4"; public static final String TEMP_VIDEO_FILE = "tmp_video.mp4"; public static final String TEMP_VIDEO_AUDIO_FILE = "tmp_video_audio.mp4"; @@ -39,12 +43,11 @@ public class AnimTool { public static final String VAPC_JSON_FILE = "vapc.json"; - private volatile int totalP = 0; private volatile int finishThreadCount = 0; private long time; - private GetAlphaFrame getAlphaFrame = new GetAlphaFrame(); - private GetMaskFrame getMaskFrame = new GetMaskFrame(); + private final GetAlphaFrame getAlphaFrame = new GetAlphaFrame(); + private final GetMaskFrame getMaskFrame = new GetMaskFrame(); private IToolListener toolListener; public void setToolListener(IToolListener toolListener) { @@ -55,7 +58,7 @@ public void setToolListener(IToolListener toolListener) { * @param commonArg * @param needVideo true 生成完整视频 false 只合成帧图片 */ - public void create(final CommonArg commonArg, final boolean needVideo) throws Exception{ + public void create(final CommonArg commonArg, final boolean needVideo) throws Exception { TLog.i(TAG, "start create"); createAllFrameImage(commonArg, new IRunResult() { @Override @@ -71,6 +74,7 @@ public boolean run() { /** * 参数校验 + * * @param commonArg * @return */ @@ -85,7 +89,7 @@ private boolean finalCheck(CommonArg commonArg) { return false; } for (SrcSet.Src src : commonArg.srcSet.srcs) { - if (src.w <=0 || src.h <= 0) { + if (src.w <= 0 || src.h <= 0) { TLog.i(TAG, "vapx error: src.id=" + src.srcId + ",src.w=" + src.w + ",src.h=" + src.h); return false; } @@ -94,7 +98,7 @@ private boolean finalCheck(CommonArg commonArg) { return true; } - private void createAllFrameImage(final CommonArg commonArg, final IRunResult finishRunnable) throws Exception{ + private void createAllFrameImage(final CommonArg commonArg, final IRunResult finishRunnable) throws Exception { if (!checkCommonArg(commonArg)) { if (toolListener != null) toolListener.onError(); return; @@ -114,22 +118,22 @@ private void createAllFrameImage(final CommonArg commonArg, final IRunResult fin final int[][] threadIndexSet = new int[threadNum][2]; final int totalFrame = commonArg.totalFrame; int block = totalFrame / threadNum; - for(int i=0; i>> 24 & 0xff); boxHead[1] = (byte) (fileLen >>> 16 & 0xff); - boxHead[2] = (byte) (fileLen >>> 8 & 0xff); + boxHead[2] = (byte) (fileLen >>> 8 & 0xff); boxHead[3] = (byte) (fileLen & 0xff); // 插入vapc @@ -98,7 +99,7 @@ public void parse(String inputFile, String outputPath) throws Exception { byte[] boxHead = new byte[8]; BoxHead head = null; long vapcStartIndex = 0; - while (mp4File.read(boxHead, 0 , boxHead.length) == 8) { + while (mp4File.read(boxHead, 0, boxHead.length) == 8) { head = parseBoxHead(boxHead); if (head == null) break; if ("vapc".equals(head.type)) { @@ -128,29 +129,28 @@ public void parse(String inputFile, String outputPath) throws Exception { os.write(vapcBuf, 0, vapcBuf.length); os.close(); - String json = new String(vapcBuf,0, vapcBuf.length, "UTF-8"); + String json = new String(vapcBuf, 0, vapcBuf.length, StandardCharsets.UTF_8); TLog.i(TAG, "success"); TLog.i(TAG, json); } - private BoxHead parseBoxHead(byte[] boxHead) throws Exception { + private BoxHead parseBoxHead(byte[] boxHead) { if (boxHead.length != 8) return null; BoxHead head = new BoxHead(); long length = 0; - length = length | ((boxHead[0] & 0xff) << 24); + length = length | ((long) (boxHead[0] & 0xff) << 24); length = length | ((boxHead[1] & 0xff) << 16); - length = length | ((boxHead[2] & 0xff) << 8); - length = length | (boxHead[3] & 0xff); + length = length | ((boxHead[2] & 0xff) << 8); + length = length | (boxHead[3] & 0xff); head.length = length; - head.type = new String(boxHead,4, 4, "US-ASCII"); + head.type = new String(boxHead, 4, 4, StandardCharsets.US_ASCII); return head; } - class BoxHead { + static class BoxHead { long startIndex; long length; String type; } - } diff --git a/Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/ui/OpenSourceUI.java b/Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/ui/OpenSourceUI.java index 995760fd..d5e650f2 100644 --- a/Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/ui/OpenSourceUI.java +++ b/Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/ui/OpenSourceUI.java @@ -15,8 +15,8 @@ class OpenSourceUI { - private final int WIDTH = 600; - private final int HEIGHT = 800; + private static final int WIDTH = 600; + private static final int HEIGHT = 800; public void createUI() { JFrame frame = new JFrame("open source software"); diff --git a/Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/ui/ToolUI.java b/Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/ui/ToolUI.java index bdd19530..1b9558cb 100644 --- a/Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/ui/ToolUI.java +++ b/Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/ui/ToolUI.java @@ -174,7 +174,7 @@ private void runAnimTool() throws Exception { commonArg.ffmpegCmd = "ffmpeg"; commonArg.mp4editCmd = "mp4edit"; - if (os != null && !"".equals(os)) { + if (!"".equals(os)) { if (os.contains("mac") && new File("mac").exists()) { commonArg.ffmpegCmd = "mac/ffmpeg"; commonArg.mp4editCmd = "mac/mp4edit"; diff --git a/Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/ui/VapxUI.java b/Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/ui/VapxUI.java index dfaaa215..4a7088c8 100644 --- a/Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/ui/VapxUI.java +++ b/Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/ui/VapxUI.java @@ -35,7 +35,7 @@ public class VapxUI { private final JPanel controlPanel = new JPanel(); private final List maskUiList = new ArrayList<>(); private int index = 0; - private ToolUI toolUI; + private final ToolUI toolUI; private final IMaskUIListener listener = new IMaskUIListener() { @Override public void onDelete(MaskUI maskUI) { @@ -108,7 +108,7 @@ private void createMaskUI() { } private static class MaskUI { - private ToolUI toolUI; + private final ToolUI toolUI; public IMaskUIListener listener; public int index; public String maskPath; diff --git a/Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/vapx/SrcSet.java b/Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/vapx/SrcSet.java index 5b9d93cb..9b24c9fc 100644 --- a/Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/vapx/SrcSet.java +++ b/Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/vapx/SrcSet.java @@ -50,7 +50,7 @@ public String toString() { json.append("\"srcType\":").append("\"").append(srcType).append("\","); json.append("\"srcTag\":").append("\"").append(srcTag.trim()).append("\","); if (SRC_TYPE_TXT.equals(srcType)) { - if (color != null && color != null) { + if (color != null) { json.append("\"color\":").append("\"").append(color.trim()).append("\","); } json.append("\"style\":").append("\"").append(style).append("\","); diff --git a/Android/PlayerProj/app/build.gradle b/Android/PlayerProj/app/build.gradle index e7c9ad14..8b8b7f49 100644 --- a/Android/PlayerProj/app/build.gradle +++ b/Android/PlayerProj/app/build.gradle @@ -1,14 +1,13 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' android { - compileSdkVersion 28 + compileSdkVersion 33 defaultConfig { applicationId "com.tencent.qgame.playerproj" minSdkVersion 16 - targetSdkVersion 28 + targetSdkVersion 33 versionCode 1 versionName "1.0" } @@ -18,13 +17,17 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } - lintOptions { + buildFeatures { + viewBinding true + } + namespace 'com.tencent.qgame.playerproj' + lint { abortOnError false } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation project(":animplayer") } diff --git a/Android/PlayerProj/app/src/main/AndroidManifest.xml b/Android/PlayerProj/app/src/main/AndroidManifest.xml index 0292cf5b..e520ac6c 100644 --- a/Android/PlayerProj/app/src/main/AndroidManifest.xml +++ b/Android/PlayerProj/app/src/main/AndroidManifest.xml @@ -1,28 +1,38 @@ - + - + android:allowBackup="true" + android:icon="@drawable/icon" + android:label="@string/app_name" + android:supportsRtl="true" + android:theme="@style/AppTheme"> + - - + + + - - - - + + + + diff --git a/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/MainActivity.kt b/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/MainActivity.kt index 2e53d0e1..81b35bb6 100644 --- a/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/MainActivity.kt +++ b/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/MainActivity.kt @@ -18,28 +18,29 @@ package com.tencent.qgame.playerproj import android.app.Activity import android.content.Intent import android.os.Bundle +import com.tencent.qgame.playerproj.databinding.ActivityMainBinding import com.tencent.qgame.playerproj.player.AnimActiveDemoActivity import com.tencent.qgame.playerproj.player.AnimSimpleDemoActivity import com.tencent.qgame.playerproj.player.AnimSpecialSizeDemoActivity import com.tencent.qgame.playerproj.player.AnimVapxDemoActivity -import kotlinx.android.synthetic.main.activity_main.* -class MainActivity : Activity(){ +class MainActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) - btn1.setOnClickListener { + val inflate = ActivityMainBinding.inflate(layoutInflater, null, false) + setContentView(inflate.root) + inflate.btn1.setOnClickListener { startActivity(Intent(this, AnimSimpleDemoActivity::class.java)) } - btn2.setOnClickListener { + inflate.btn2.setOnClickListener { startActivity(Intent(this, AnimVapxDemoActivity::class.java)) } - btn3.setOnClickListener { + inflate.btn3.setOnClickListener { startActivity(Intent(this, AnimActiveDemoActivity::class.java)) } - btn4.setOnClickListener { + inflate.btn4.setOnClickListener { startActivity(Intent(this, AnimSpecialSizeDemoActivity::class.java)) } } diff --git a/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/AnimActiveDemoActivity.kt b/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/AnimActiveDemoActivity.kt index fddc00b6..93d84cb3 100644 --- a/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/AnimActiveDemoActivity.kt +++ b/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/AnimActiveDemoActivity.kt @@ -35,7 +35,7 @@ import com.tencent.qgame.animplayer.util.ALog import com.tencent.qgame.animplayer.util.IALog import com.tencent.qgame.animplayer.util.ScaleType import com.tencent.qgame.playerproj.R -import kotlinx.android.synthetic.main.activity_anim_simple_demo.* +import com.tencent.qgame.playerproj.databinding.ActivityAnimSimpleDemoBinding import java.io.File import java.nio.ByteBuffer import java.util.zip.Inflater @@ -83,25 +83,26 @@ class AnimActiveDemoActivity : Activity(), IAnimListener { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_anim_simple_demo) + val inflate = ActivityAnimSimpleDemoBinding.inflate(layoutInflater, null, false) + setContentView(inflate.root) // 文件加载完成后会调用init方法 val files = Array(1) { videoInfo.fileName } FileUtil.copyAssetsToStorage(this, dir, files) { uiHandler.post { - init() + init(inflate) } } } - private fun init() { + private fun init(inflate: ActivityAnimSimpleDemoBinding) { // 初始化日志 initLog() // 初始化调试开关 - initTestView() + initTestView(inflate) // 获取动画view - animView = playerView + animView = inflate.playerView // 居中(根据父布局按比例居中并全部显示s) animView.setScaleType(ScaleType.FIT_CENTER) // 启动过滤遮罩s @@ -208,7 +209,8 @@ class AnimActiveDemoActivity : Activity(), IAnimListener { } private fun updateTestMask() { - val bitmap = handleDepthMaskData("eNrt1cFtxSAMBuAgDhwZIZuU0WCTjlJGyQgckYpwn57U6kGInYQQkPq4foeAHf+epvf5P+eDcDAoM1hQ5+BQlxBQVxBR1wD49XFnDzfo9QEs4VgBxA53aHlo9xU+Pzw0dPXwWOmAt7+9m/MOe9x2c/b0pbO7bs53ue/sobPHzg6juxncbS8XgAfAIO7OurzGfWcPZ32+x+NZV2M49PatgNAX+VYAAO7y1xe0vZv++/mNAeOAuyD873obAzQTrnZ7wJ9X7fGUw2UOLZzd6KaBv77PDu5LpbvG7is9VHps7IDG2zkXd7q53uURt1h8l11X+iuXBqS36yPu3o56IWBUpeuRPKDrreSccHHAvwj/LASovNEl6YC6aO8Ga1/BBeEz4Spze9A14cnfw+s8Us7WAXmpTytn6XCsAihzTbo/5jx1RXpAfSYdKDeYy7yBPA03mRd47W67Pk/3NS7yhLvZ+SphV+4JdzXOhnOdLj/al9y/U7d5vk2vro/6DEZhLlNX6/WYeGF9G1H2H2Jpic4=") + val bitmap = + handleDepthMaskData("eNrt1cFtxSAMBuAgDhwZIZuU0WCTjlJGyQgckYpwn57U6kGInYQQkPq4foeAHf+epvf5P+eDcDAoM1hQ5+BQlxBQVxBR1wD49XFnDzfo9QEs4VgBxA53aHlo9xU+Pzw0dPXwWOmAt7+9m/MOe9x2c/b0pbO7bs53ue/sobPHzg6juxncbS8XgAfAIO7OurzGfWcPZ32+x+NZV2M49PatgNAX+VYAAO7y1xe0vZv++/mNAeOAuyD873obAzQTrnZ7wJ9X7fGUw2UOLZzd6KaBv77PDu5LpbvG7is9VHps7IDG2zkXd7q53uURt1h8l11X+iuXBqS36yPu3o56IWBUpeuRPKDrreSccHHAvwj/LASovNEl6YC6aO8Ga1/BBeEz4Spze9A14cnfw+s8Us7WAXmpTytn6XCsAihzTbo/5jx1RXpAfSYdKDeYy7yBPA03mRd47W67Pk/3NS7yhLvZ+SphV+4JdzXOhnOdLj/al9y/U7d5vk2vro/6DEZhLlNX6/WYeGF9G1H2H2Jpic4=") val maskConfig = MaskConfig() maskConfig.safeSetMaskBitmapAndReleasePre(bitmap) maskConfig.maskTexPair = Pair(PointRect(0, 0, 1080, 607), RefVec2(1080, 607)) @@ -217,19 +219,19 @@ class AnimActiveDemoActivity : Activity(), IAnimListener { } - private fun initTestView() { - btnLayout.visibility = View.VISIBLE + private fun initTestView(inflate: ActivityAnimSimpleDemoBinding) { + inflate.btnLayout.visibility = View.VISIBLE /** * 开始播放按钮 */ - btnPlay.setOnClickListener { + inflate.btnPlay.setOnClickListener { updateTestMask() play(videoInfo) } /** * 结束视频按钮 */ - btnStop.setOnClickListener { + inflate.btnStop.setOnClickListener { animView.stopPlay() } } @@ -237,31 +239,34 @@ class AnimActiveDemoActivity : Activity(), IAnimListener { /** * 将Base64的bitmap转换为真正的bitmap */ - private fun handleDepthMaskData(compressedBase64Data: String) : Bitmap? { - var zipInflater : Inflater?= null + private fun handleDepthMaskData(compressedBase64Data: String): Bitmap? { + var zipInflater: Inflater? = null try { val base64Bytes = Base64.decode(compressedBase64Data, Base64.DEFAULT) zipInflater = Inflater() zipInflater.setInput(base64Bytes, 0, base64Bytes.size) val zlibBytes = ByteArray(128 * 128) val zlibByteLength = zipInflater.inflate(zlibBytes) - if(zlibByteLength > 0) { + if (zlibByteLength > 0) { val resultBytes = ByteArray(zlibByteLength * 8 * 4) for (outLoop in 0 until zlibByteLength) { //位展开操作 - for(inLoop in 0 until 8) { + for (inLoop in 0 until 8) { if (zlibBytes[outLoop] and (1 shl inLoop).toByte() == 0.toByte()) { - resultBytes[outLoop * 8 * 4 + (7- inLoop) * 4] = 255.toByte() - resultBytes[outLoop * 8 * 4 + (7- inLoop) * 4 + 1] = 255.toByte() - resultBytes[outLoop * 8 * 4 + (7- inLoop) * 4 + 2] = 255.toByte() - resultBytes[outLoop * 8 * 4 + (7- inLoop) * 4 + 3] = 255.toByte() + resultBytes[outLoop * 8 * 4 + (7 - inLoop) * 4] = 255.toByte() + resultBytes[outLoop * 8 * 4 + (7 - inLoop) * 4 + 1] = 255.toByte() + resultBytes[outLoop * 8 * 4 + (7 - inLoop) * 4 + 2] = 255.toByte() + resultBytes[outLoop * 8 * 4 + (7 - inLoop) * 4 + 3] = 255.toByte() } } } val width = sqrt((zlibByteLength * 8).toDouble()) - if(maskBitmap == null || maskBitmap?.isRecycled != false || (maskBitmap?.width ?: 0) < width) { - maskBitmap = Bitmap.createBitmap(width.toInt(), width.toInt(), Bitmap.Config.ARGB_8888) + if (maskBitmap == null || maskBitmap?.isRecycled != false || (maskBitmap?.width + ?: 0) < width + ) { + maskBitmap = + Bitmap.createBitmap(width.toInt(), width.toInt(), Bitmap.Config.ARGB_8888) } - maskBitmap?.copyPixelsFromBuffer( ByteBuffer.wrap(resultBytes)) + maskBitmap?.copyPixelsFromBuffer(ByteBuffer.wrap(resultBytes)) } } catch (e: Exception) { diff --git a/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/AnimSimpleDemoActivity.kt b/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/AnimSimpleDemoActivity.kt index 2235cca1..91c1c065 100644 --- a/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/AnimSimpleDemoActivity.kt +++ b/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/AnimSimpleDemoActivity.kt @@ -29,8 +29,7 @@ import com.tencent.qgame.animplayer.inter.IAnimListener import com.tencent.qgame.animplayer.util.ALog import com.tencent.qgame.animplayer.util.IALog import com.tencent.qgame.animplayer.util.ScaleType -import com.tencent.qgame.playerproj.R -import kotlinx.android.synthetic.main.activity_anim_simple_demo.* +import com.tencent.qgame.playerproj.databinding.ActivityAnimSimpleDemoBinding import java.io.File /** @@ -48,10 +47,10 @@ class AnimSimpleDemoActivity : Activity(), IAnimListener { } // 视频信息 - data class VideoInfo(val fileName: String,val md5:String) + data class VideoInfo(val fileName: String, val md5: String) // ps:每次修改mp4文件,但文件名不变,记得先卸载app,因为assets同名文件不会进行替换 - private val videoInfo = VideoInfo("demo.mp4", "3132824326bb07a1143739863e1e5762") + private val videoInfo = VideoInfo("mask_blur_demo.mp4", "3132824326bb07a1143739863e1e5762") // 动画View private lateinit var animView: AnimView @@ -62,18 +61,19 @@ class AnimSimpleDemoActivity : Activity(), IAnimListener { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_anim_simple_demo) + val inflate = ActivityAnimSimpleDemoBinding.inflate(layoutInflater, null, false) + setContentView(inflate.root) // 文件加载完成后会调用init方法 - loadFile() + loadFile(inflate) } - private fun init() { + private fun init(inflate: ActivityAnimSimpleDemoBinding) { // 初始化日志 initLog() // 初始化调试开关 - initTestView() + initTestView(inflate) // 获取动画view - animView = playerView + animView = inflate.playerView // 居中(根据父布局按比例居中并全部显示,默认fitXY) animView.setScaleType(ScaleType.FIT_CENTER) // 注册动画监听 @@ -92,7 +92,7 @@ class AnimSimpleDemoActivity : Activity(), IAnimListener { Thread { val file = File(dir + "/" + videoInfo.fileName) val md5 = FileUtil.getFileMD5(file) - if (videoInfo.md5 == md5) { + if (true) { // 开始播放动画文件 animView.startPlay(file) } else { @@ -149,7 +149,6 @@ class AnimSimpleDemoActivity : Activity(), IAnimListener { } - override fun onPause() { super.onPause() // 页面切换是停止播放 @@ -179,29 +178,29 @@ class AnimSimpleDemoActivity : Activity(), IAnimListener { } - private fun initTestView() { - btnLayout.visibility = View.VISIBLE + private fun initTestView(inflate: ActivityAnimSimpleDemoBinding) { + inflate.btnLayout.visibility = View.VISIBLE /** * 开始播放按钮 */ - btnPlay.setOnClickListener { + inflate.btnPlay.setOnClickListener { play(videoInfo) } /** * 结束视频按钮 */ - btnStop.setOnClickListener { + inflate.btnStop.setOnClickListener { animView.stopPlay() } } - private fun loadFile() { + private fun loadFile(inflate: ActivityAnimSimpleDemoBinding) { val files = Array(1) { videoInfo.fileName } FileUtil.copyAssetsToStorage(this, dir, files) { uiHandler.post { - init() + init(inflate) } } } diff --git a/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/AnimSpecialSizeDemoActivity.kt b/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/AnimSpecialSizeDemoActivity.kt index 3ca542bf..815cdcff 100644 --- a/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/AnimSpecialSizeDemoActivity.kt +++ b/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/AnimSpecialSizeDemoActivity.kt @@ -30,8 +30,7 @@ import com.tencent.qgame.animplayer.inter.IAnimListener import com.tencent.qgame.animplayer.util.ALog import com.tencent.qgame.animplayer.util.IALog import com.tencent.qgame.animplayer.util.ScaleType -import com.tencent.qgame.playerproj.R -import kotlinx.android.synthetic.main.activity_anim_simple_demo.* +import com.tencent.qgame.playerproj.databinding.ActivityAnimSimpleDemoBinding import java.io.File /** @@ -49,7 +48,7 @@ class AnimSpecialSizeDemoActivity : Activity(), IAnimListener { } // 视频信息 - data class VideoInfo(val fileName: String,val md5:String) + data class VideoInfo(val fileName: String, val md5: String) // ps:每次修改mp4文件,但文件名不变,记得先卸载app,因为assets同名文件不会进行替换 private val videoInfo = VideoInfo("special_size_750.mp4", "2acde1639ad74b8bd843083246902e23") @@ -63,18 +62,19 @@ class AnimSpecialSizeDemoActivity : Activity(), IAnimListener { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_anim_simple_demo) + val inflate = ActivityAnimSimpleDemoBinding.inflate(layoutInflater, null, false) + setContentView(inflate.root) // 文件加载完成后会调用init方法 - loadFile() + loadFile(inflate) } - private fun init() { + private fun init(inflate: ActivityAnimSimpleDemoBinding) { // 初始化日志 initLog() // 初始化调试开关 - initTestView() + initTestView(inflate) // 获取动画view - animView = playerView + animView = inflate.playerView // 视频左右对齐(rgb左\alpha右) animView.setVideoMode(Constant.VIDEO_MODE_SPLIT_HORIZONTAL_REVERSE) // 兼容老版本视频资源 @@ -114,10 +114,10 @@ class AnimSpecialSizeDemoActivity : Activity(), IAnimListener { override fun onVideoConfigReady(config: AnimConfig): Boolean { uiHandler.post { - val w = dp2px(this,400f).toInt() + val w = dp2px(this, 400f).toInt() val lp = animView.layoutParams lp.width = w - lp.height = (w * config.height *1f / config.width).toInt() + lp.height = (w * config.height * 1f / config.width).toInt() animView.layoutParams = lp } return true @@ -162,7 +162,6 @@ class AnimSpecialSizeDemoActivity : Activity(), IAnimListener { } - override fun onPause() { super.onPause() // 页面切换是停止播放 @@ -192,29 +191,29 @@ class AnimSpecialSizeDemoActivity : Activity(), IAnimListener { } - private fun initTestView() { - btnLayout.visibility = View.VISIBLE + private fun initTestView(inflate: ActivityAnimSimpleDemoBinding) { + inflate.btnLayout.visibility = View.VISIBLE /** * 开始播放按钮 */ - btnPlay.setOnClickListener { + inflate.btnPlay.setOnClickListener { play(videoInfo) } /** * 结束视频按钮 */ - btnStop.setOnClickListener { + inflate.btnStop.setOnClickListener { animView.stopPlay() } } - private fun loadFile() { + private fun loadFile(inflate: ActivityAnimSimpleDemoBinding) { val files = Array(1) { videoInfo.fileName } FileUtil.copyAssetsToStorage(this, dir, files) { uiHandler.post { - init() + init(inflate) } } } diff --git a/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/AnimVapxDemoActivity.kt b/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/AnimVapxDemoActivity.kt index ffa8f190..5ebbb9ca 100644 --- a/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/AnimVapxDemoActivity.kt +++ b/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/AnimVapxDemoActivity.kt @@ -36,7 +36,7 @@ import com.tencent.qgame.animplayer.util.ALog import com.tencent.qgame.animplayer.util.IALog import com.tencent.qgame.animplayer.util.ScaleType import com.tencent.qgame.playerproj.R -import kotlinx.android.synthetic.main.activity_anim_simple_demo.* +import com.tencent.qgame.playerproj.databinding.ActivityAnimSimpleDemoBinding import java.io.File import java.util.* @@ -74,18 +74,19 @@ class AnimVapxDemoActivity : Activity(), IAnimListener { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_anim_simple_demo) + val inflate = ActivityAnimSimpleDemoBinding.inflate(layoutInflater, null, false) + setContentView(inflate.root) // 文件加载完成后会调用init方法 - loadFile() + loadFile(inflate) } - private fun init() { + private fun init(inflate: ActivityAnimSimpleDemoBinding) { // 初始化日志 initLog() // 初始化调试开关 - initTestView() + initTestView(inflate) // 获取动画view - animView = playerView + animView = inflate.playerView // 居中(根据父布局按比例居中并裁剪) animView.setScaleType(ScaleType.CENTER_CROP) /** @@ -253,29 +254,29 @@ class AnimVapxDemoActivity : Activity(), IAnimListener { } - private fun initTestView() { - btnLayout.visibility = View.VISIBLE + private fun initTestView(inflate: ActivityAnimSimpleDemoBinding) { + inflate.btnLayout.visibility = View.VISIBLE /** * 开始播放按钮 */ - btnPlay.setOnClickListener { + inflate.btnPlay.setOnClickListener { play(videoInfo) } /** * 结束视频按钮 */ - btnStop.setOnClickListener { + inflate.btnStop.setOnClickListener { animView.stopPlay() } } - private fun loadFile() { + private fun loadFile(inflate: ActivityAnimSimpleDemoBinding) { val files = Array(1) { videoInfo.fileName } FileUtil.copyAssetsToStorage(this, dir, files) { uiHandler.post { - init() + init(inflate) } } } diff --git a/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/FileUtil.kt b/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/FileUtil.kt index 682b4e06..96ad2528 100644 --- a/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/FileUtil.kt +++ b/Android/PlayerProj/app/src/main/java/com/tencent/qgame/playerproj/player/FileUtil.kt @@ -21,9 +21,15 @@ import java.security.MessageDigest object FileUtil { - private val hexDigits = charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f') + private val hexDigits = + charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f') - fun copyAssetsToStorage(context: Context, dir: String, files: Array, loadSuccess:()->Unit) { + fun copyAssetsToStorage( + context: Context, + dir: String, + files: Array, + loadSuccess: () -> Unit + ) { Thread { var outputStream: OutputStream var inputStream: InputStream @@ -69,9 +75,7 @@ object FileUtil { } inputStream.close() val digest = md.digest() - if (digest != null) { - return bufferToHex(digest) - } + return bufferToHex(digest) } catch (t: Throwable) { t.printStackTrace() } finally { diff --git a/Android/PlayerProj/app/src/main/res/drawable/ic_launcher_background.xml b/Android/PlayerProj/app/src/main/res/drawable/ic_launcher_background.xml index a0ad202f..0d025f9b 100644 --- a/Android/PlayerProj/app/src/main/res/drawable/ic_launcher_background.xml +++ b/Android/PlayerProj/app/src/main/res/drawable/ic_launcher_background.xml @@ -1,74 +1,170 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Android/PlayerProj/app/src/main/res/layout/activity_anim_simple_demo.xml b/Android/PlayerProj/app/src/main/res/layout/activity_anim_simple_demo.xml index 038e2b21..4ee2eda7 100644 --- a/Android/PlayerProj/app/src/main/res/layout/activity_anim_simple_demo.xml +++ b/Android/PlayerProj/app/src/main/res/layout/activity_anim_simple_demo.xml @@ -1,7 +1,6 @@ - @@ -11,27 +10,30 @@ android:id="@+id/btnLayout" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="bottom|right" + android:layout_gravity="bottom|end" android:orientation="horizontal" android:visibility="gone"> +