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">
+
+ android:text="PLAY" />
+
+ android:text="STOP" />
-
+
-
+ android:layout_gravity="center"
+ app:anim_view_auto_dismiss="false" />
+
\ No newline at end of file
diff --git a/Android/PlayerProj/app/src/main/res/values/styles.xml b/Android/PlayerProj/app/src/main/res/values/styles.xml
index 43ae491e..0eeeb471 100644
--- a/Android/PlayerProj/app/src/main/res/values/styles.xml
+++ b/Android/PlayerProj/app/src/main/res/values/styles.xml
@@ -1,7 +1,6 @@
-
+
diff --git a/Android/PlayerProj/app/src/test/java/com/tencent/qgame/playerproj/ExampleUnitTest.kt b/Android/PlayerProj/app/src/test/java/com/tencent/qgame/playerproj/ExampleUnitTest.kt
index 29f0e358..b57b3966 100644
--- a/Android/PlayerProj/app/src/test/java/com/tencent/qgame/playerproj/ExampleUnitTest.kt
+++ b/Android/PlayerProj/app/src/test/java/com/tencent/qgame/playerproj/ExampleUnitTest.kt
@@ -1,17 +1 @@
package com.tencent.qgame.playerproj
-
-import org.junit.Test
-
-import org.junit.Assert.*
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-class ExampleUnitTest {
- @Test
- fun addition_isCorrect() {
- assertEquals(4, 2 + 2)
- }
-}
diff --git a/Android/PlayerProj/build.gradle b/Android/PlayerProj/build.gradle
index 27143119..f81f91cf 100644
--- a/Android/PlayerProj/build.gradle
+++ b/Android/PlayerProj/build.gradle
@@ -1,14 +1,13 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = '1.3.50'
+ ext.kotlin_version = '1.7.10'
repositories {
google()
- // jcenter()
mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.2.1'
+ classpath 'com.android.tools.build:gradle:8.0.0-rc01'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
// classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
@@ -20,7 +19,6 @@ buildscript {
allprojects {
repositories {
google()
- // jcenter()
mavenCentral()
}
tasks.withType(Javadoc).all { enabled = false }
diff --git a/Android/PlayerProj/gradle/wrapper/gradle-wrapper.jar b/Android/PlayerProj/gradle/wrapper/gradle-wrapper.jar
index f6b961fd..249e5832 100644
Binary files a/Android/PlayerProj/gradle/wrapper/gradle-wrapper.jar and b/Android/PlayerProj/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/Android/PlayerProj/gradle/wrapper/gradle-wrapper.properties b/Android/PlayerProj/gradle/wrapper/gradle-wrapper.properties
index 9a4163a4..da1db5f0 100644
--- a/Android/PlayerProj/gradle/wrapper/gradle-wrapper.properties
+++ b/Android/PlayerProj/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/Android/PlayerProj/gradlew b/Android/PlayerProj/gradlew
index cccdd3d5..a69d9cb6 100755
--- a/Android/PlayerProj/gradlew
+++ b/Android/PlayerProj/gradlew
@@ -1,78 +1,129 @@
-#!/usr/bin/env sh
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
##############################################################################
-##
-## Gradle start up script for UN*X
-##
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
##############################################################################
# Attempt to set APP_HOME
+
# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
+APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
warn () {
echo "$*"
-}
+} >&2
die () {
echo
echo "$*"
echo
exit 1
-}
+} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
- NONSTOP* )
- nonstop=true
- ;;
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
+ JAVACMD=$JAVA_HOME/jre/sh/java
else
- JAVACMD="$JAVA_HOME/bin/java"
+ JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -81,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
- JAVACMD="java"
+ JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@@ -89,84 +140,101 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
fi
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
fi
- i=$((i+1))
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
done
- case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
fi
-# Escape application args
-save () {
- for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
- echo " "
-}
-APP_ARGS=$(save "$@")
-
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
- cd "$(dirname "$0")"
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
fi
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
exec "$JAVACMD" "$@"
diff --git a/Android/PlayerProj/gradlew.bat b/Android/PlayerProj/gradlew.bat
index f9553162..f127cfd4 100644
--- a/Android/PlayerProj/gradlew.bat
+++ b/Android/PlayerProj/gradlew.bat
@@ -1,4 +1,20 @@
-@if "%DEBUG%" == "" @echo off
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -9,19 +25,22 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -35,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -45,38 +64,26 @@ echo location of your Java installation.
goto fail
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
diff --git a/README.md b/README.md
index e73533a1..3f40c1a6 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
# VAP
+增加最后一帧停止的功能
+
[](http://opensource.org/licenses/MIT)
简体中文 | [English](./README_en.md)