视频播放1
This commit is contained in:
@@ -81,12 +81,6 @@ dependencies {
|
|||||||
implementation("com.github.bumptech.glide:glide:4.16.0")
|
implementation("com.github.bumptech.glide:glide:4.16.0")
|
||||||
// ZXing 二维码扫描库
|
// ZXing 二维码扫描库
|
||||||
implementation("com.google.zxing:core:3.5.2")
|
implementation("com.google.zxing:core:3.5.2")
|
||||||
// ExoPlayer 核心库
|
|
||||||
implementation("androidx.media3:media3-exoplayer:1.9.0")
|
|
||||||
// ExoPlayer UI组件库,提供PlayerView等
|
|
||||||
implementation("androidx.media3:media3-ui:1.9.0")
|
|
||||||
// ExoPlayer 通用库
|
|
||||||
implementation("androidx.media3:media3-common:1.9.0")
|
|
||||||
// 基础依赖包,必须要依赖
|
// 基础依赖包,必须要依赖
|
||||||
implementation("com.geyifeng.immersionbar:immersionbar:3.2.2")
|
implementation("com.geyifeng.immersionbar:immersionbar:3.2.2")
|
||||||
// kotlin扩展(可选)
|
// kotlin扩展(可选)
|
||||||
@@ -107,5 +101,7 @@ dependencies {
|
|||||||
implementation("com.yanzhenjie.recyclerview:x:1.3.2")
|
implementation("com.yanzhenjie.recyclerview:x:1.3.2")
|
||||||
//Android-PickerView-时间弹窗
|
//Android-PickerView-时间弹窗
|
||||||
implementation("com.contrarywind:Android-PickerView:4.1.9")
|
implementation("com.contrarywind:Android-PickerView:4.1.9")
|
||||||
|
//基于exoPlayer 自定义播放器 JPlayer支持功能
|
||||||
|
implementation("com.ycjiang:VideoPlayModule-Lite:2.3.61")
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,55 +2,40 @@ package com.example.defenseapplication.liveVideo
|
|||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.ActivityInfo
|
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.media.AudioManager
|
|
||||||
import android.media.MediaPlayer
|
|
||||||
import android.media.MediaRecorder
|
import android.media.MediaRecorder
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Environment
|
import android.util.Log
|
||||||
import android.view.SurfaceHolder
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.WindowManager
|
|
||||||
import android.view.animation.Animation
|
|
||||||
import android.view.animation.LinearInterpolator
|
|
||||||
import android.view.animation.ScaleAnimation
|
import android.view.animation.ScaleAnimation
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.OnBackPressedDispatcher
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import chuangyuan.ycj.videolibrary.video.ExoUserPlayer
|
||||||
import com.example.defenseapplication.R
|
import com.example.defenseapplication.R
|
||||||
import com.example.defenseapplication.base.BaseActivity
|
import com.example.defenseapplication.base.BaseActivity
|
||||||
import com.example.defenseapplication.databinding.LiveVideoActivityBinding
|
import com.example.defenseapplication.databinding.LiveVideoActivityBinding
|
||||||
import com.example.defenseapplication.utils.ActivityManager
|
import com.example.defenseapplication.utils.ActivityManager
|
||||||
import com.example.defenseapplication.utils.DeviceIdEvent
|
|
||||||
import com.gyf.immersionbar.ImmersionBar
|
import com.gyf.immersionbar.ImmersionBar
|
||||||
import com.gyf.immersionbar.ktx.destroyImmersionBar
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import androidx.activity.OnBackPressedCallback
|
||||||
|
import chuangyuan.ycj.videolibrary.listener.VideoInfoListener
|
||||||
|
import chuangyuan.ycj.videolibrary.video.VideoPlayerManager
|
||||||
|
|
||||||
private const val TAG = "LiveVideoActivity"
|
private const val TAG = "LiveVideoActivity"
|
||||||
//智能防御机A1
|
//智能防御机A1
|
||||||
class LiveVideoActivity : BaseActivity(), SurfaceHolder.Callback {
|
class LiveVideoActivity : BaseActivity() {
|
||||||
private lateinit var binding: LiveVideoActivityBinding
|
private lateinit var binding: LiveVideoActivityBinding
|
||||||
|
|
||||||
private var mediaPlayer: MediaPlayer? = null
|
private lateinit var exoPlayerManager: ExoUserPlayer
|
||||||
private var isFullscreen = false
|
|
||||||
private var isPlaying = false
|
|
||||||
private var isVoiceEnabled = false
|
private var isVoiceEnabled = false
|
||||||
private var isLightOn = false
|
private var isLightOn = false
|
||||||
private var isRecording = false
|
private var isRecording = false
|
||||||
private var mediaRecorder: MediaRecorder? = null
|
private var mediaRecorder: MediaRecorder? = null
|
||||||
private var micPulseAnimation: ScaleAnimation? = null
|
private var micPulseAnimation: ScaleAnimation? = null
|
||||||
|
|
||||||
private var videoWidth = 0
|
|
||||||
private var videoHeight = 0
|
|
||||||
|
|
||||||
private val testVideoUrl = "https://vjs.zencdn.net/v/oceans.mp4"
|
|
||||||
|
|
||||||
private val requestPermissionLauncher = registerForActivityResult(
|
private val requestPermissionLauncher = registerForActivityResult(
|
||||||
ActivityResultContracts.RequestPermission()
|
ActivityResultContracts.RequestPermission()
|
||||||
) { isGranted ->
|
) { isGranted ->
|
||||||
@@ -78,93 +63,55 @@ class LiveVideoActivity : BaseActivity(), SurfaceHolder.Callback {
|
|||||||
binding.tvTitle.text = deviceName
|
binding.tvTitle.text = deviceName
|
||||||
}
|
}
|
||||||
|
|
||||||
initSurfaceView()
|
// 初始化播放器
|
||||||
|
initVideoPlayer()
|
||||||
initListener()
|
initListener()
|
||||||
}
|
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
|
||||||
|
override fun handleOnBackPressed() {
|
||||||
private fun initSurfaceView() {
|
if (exoPlayerManager.onBackPressed()) {
|
||||||
binding.surfaceView.holder.addCallback(this)
|
return
|
||||||
}
|
|
||||||
|
|
||||||
override fun surfaceCreated(holder: SurfaceHolder) {
|
|
||||||
initMediaPlayer(holder)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
|
|
||||||
adjustSurfaceViewSize()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun surfaceDestroyed(holder: SurfaceHolder) {
|
|
||||||
releaseMediaPlayer()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initMediaPlayer(holder: SurfaceHolder) {
|
|
||||||
mediaPlayer = MediaPlayer().apply {
|
|
||||||
setDisplay(holder)
|
|
||||||
setAudioStreamType(AudioManager.STREAM_MUSIC)
|
|
||||||
|
|
||||||
try {
|
|
||||||
setDataSource(this@LiveVideoActivity, Uri.parse(testVideoUrl))
|
|
||||||
prepareAsync()
|
|
||||||
|
|
||||||
setOnPreparedListener { mp ->
|
|
||||||
this@LiveVideoActivity.videoWidth = mp.videoWidth
|
|
||||||
this@LiveVideoActivity.videoHeight = mp.videoHeight
|
|
||||||
adjustSurfaceViewSize()
|
|
||||||
mp.isLooping = true
|
|
||||||
mp.start()
|
|
||||||
this@LiveVideoActivity.isPlaying = true
|
|
||||||
Toast.makeText(this@LiveVideoActivity, R.string.video_ready, Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
}
|
||||||
|
// 无全屏时执行默认返回逻辑(如 finish)
|
||||||
setOnCompletionListener {
|
finish()
|
||||||
this@LiveVideoActivity.isPlaying = false
|
|
||||||
Toast.makeText(this@LiveVideoActivity, R.string.playback_complete, Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
|
|
||||||
setOnErrorListener { _, what, extra ->
|
|
||||||
Toast.makeText(this@LiveVideoActivity, getString(R.string.video_error_format, what, extra), Toast.LENGTH_SHORT).show()
|
|
||||||
releaseMediaPlayer()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
setOnBufferingUpdateListener { _, percent ->
|
|
||||||
if (percent < 100) {
|
|
||||||
Toast.makeText(this@LiveVideoActivity, getString(R.string.buffering_format, percent), Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (e: IOException) {
|
|
||||||
e.printStackTrace()
|
|
||||||
Toast.makeText(this@LiveVideoActivity, R.string.cannot_load_video, Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
private fun initVideoPlayer() {
|
||||||
|
val videoPlayerView = binding.exoPlayContextId
|
||||||
|
|
||||||
private fun adjustSurfaceViewSize() {
|
exoPlayerManager = VideoPlayerManager.Builder(VideoPlayerManager.TYPE_PLAY_GESTURE, videoPlayerView)
|
||||||
if (videoWidth == 0 || videoHeight == 0) return
|
.setPlayUri("https://media.w3.org/2010/05/sintel/trailer.mp4")//真实地址
|
||||||
|
.setPosition(0)
|
||||||
val screenWidth = resources.displayMetrics.widthPixels
|
.addVideoInfoListener(object : VideoInfoListener {
|
||||||
val screenHeight = resources.displayMetrics.heightPixels
|
// 注意:此处的 p0: Long 是视频开始播放时的位置信息,可以按需使用
|
||||||
val aspectRatio = videoWidth.toFloat() / videoHeight.toFloat()
|
override fun onPlayStart(p0: Long) {
|
||||||
|
Log.d(TAG, "视频开始播放")
|
||||||
val params = binding.surfaceView.layoutParams
|
}
|
||||||
|
|
||||||
if (isFullscreen) {
|
override fun onLoadingChanged() {
|
||||||
if (screenWidth.toFloat() / screenHeight.toFloat() > aspectRatio) {
|
// 视频加载状态变化
|
||||||
params.width = (screenHeight * aspectRatio).toInt()
|
}
|
||||||
params.height = screenHeight
|
|
||||||
} else {
|
override fun onPlayerError(p0: com.google.android.exoplayer2.ExoPlaybackException?) {
|
||||||
params.width = screenWidth
|
Toast.makeText(this@LiveVideoActivity, "播放失败", Toast.LENGTH_SHORT).show()
|
||||||
params.height = (screenWidth / aspectRatio).toInt()
|
}
|
||||||
}
|
|
||||||
} else {
|
override fun onPlayEnd() {
|
||||||
val containerHeight = binding.videoContainer.height
|
Log.d(TAG, "播放结束")
|
||||||
params.width = (containerHeight * aspectRatio).toInt()
|
}
|
||||||
params.height = containerHeight
|
|
||||||
}
|
// 修正点:库的接口要求必须实现 isPlaying 方法
|
||||||
|
override fun isPlaying(p0: Boolean) {
|
||||||
binding.surfaceView.layoutParams = params
|
// p0 表示当前是否正在播放
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onRepeatModeChanged(p0: Int) {
|
||||||
|
// 循环模式改变时的回调
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.create()
|
||||||
|
|
||||||
|
exoPlayerManager.startPlayer()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initListener() {
|
private fun initListener() {
|
||||||
@@ -180,15 +127,6 @@ class LiveVideoActivity : BaseActivity(), SurfaceHolder.Callback {
|
|||||||
val intent = Intent(this, SettingsActivity::class.java)
|
val intent = Intent(this, SettingsActivity::class.java)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.ivFullscreen.setOnClickListener {
|
|
||||||
toggleFullscreen()
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.surfaceView.setOnClickListener {
|
|
||||||
togglePlayPause()
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.llVoice.setOnClickListener {
|
binding.llVoice.setOnClickListener {
|
||||||
toggleVoice()
|
toggleVoice()
|
||||||
}
|
}
|
||||||
@@ -212,90 +150,14 @@ class LiveVideoActivity : BaseActivity(), SurfaceHolder.Callback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun togglePlayPause() {
|
|
||||||
mediaPlayer?.let { mp ->
|
|
||||||
if (mp.isPlaying) {
|
|
||||||
mp.pause()
|
|
||||||
isPlaying = false
|
|
||||||
Toast.makeText(this, R.string.paused, Toast.LENGTH_SHORT).show()
|
|
||||||
} else {
|
|
||||||
mp.start()
|
|
||||||
isPlaying = true
|
|
||||||
Toast.makeText(this, R.string.resume_playback, Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun toggleFullscreen() {
|
|
||||||
isFullscreen = !isFullscreen
|
|
||||||
|
|
||||||
if (isFullscreen) {
|
|
||||||
enterFullscreen()
|
|
||||||
} else {
|
|
||||||
exitFullscreen()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun enterFullscreen() {
|
|
||||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
|
||||||
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
|
||||||
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
|
|
||||||
|
|
||||||
binding.topBar.visibility = View.GONE
|
|
||||||
binding.bitRateBar.visibility = View.GONE
|
|
||||||
binding.functionBar.visibility = View.GONE
|
|
||||||
|
|
||||||
val alarmLogParent = binding.llAlarmLog.parent.parent as View
|
|
||||||
alarmLogParent.visibility = View.GONE
|
|
||||||
|
|
||||||
val containerParams = binding.videoContainer.layoutParams
|
|
||||||
containerParams.width = ViewGroup.LayoutParams.MATCH_PARENT
|
|
||||||
containerParams.height = ViewGroup.LayoutParams.MATCH_PARENT
|
|
||||||
binding.videoContainer.layoutParams = containerParams
|
|
||||||
|
|
||||||
val surfaceParams = binding.surfaceView.layoutParams
|
|
||||||
surfaceParams.width = resources.displayMetrics.widthPixels
|
|
||||||
surfaceParams.height = resources.displayMetrics.heightPixels
|
|
||||||
binding.surfaceView.layoutParams = surfaceParams
|
|
||||||
|
|
||||||
binding.ivFullscreen.setImageResource(com.example.defenseapplication.R.drawable.back)
|
|
||||||
|
|
||||||
Toast.makeText(this, R.string.entered_fullscreen, Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun exitFullscreen() {
|
|
||||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
|
||||||
window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
|
||||||
window.clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
|
|
||||||
|
|
||||||
binding.topBar.visibility = View.VISIBLE
|
|
||||||
binding.bitRateBar.visibility = View.VISIBLE
|
|
||||||
binding.functionBar.visibility = View.VISIBLE
|
|
||||||
|
|
||||||
val alarmLogParent = binding.llAlarmLog.parent.parent as View
|
|
||||||
alarmLogParent.visibility = View.VISIBLE
|
|
||||||
|
|
||||||
val containerParams = binding.videoContainer.layoutParams
|
|
||||||
containerParams.width = ViewGroup.LayoutParams.MATCH_PARENT
|
|
||||||
containerParams.height = (220 * resources.displayMetrics.density).toInt()
|
|
||||||
binding.videoContainer.layoutParams = containerParams
|
|
||||||
|
|
||||||
adjustSurfaceViewSize()
|
|
||||||
|
|
||||||
binding.ivFullscreen.setImageResource(com.example.defenseapplication.R.drawable.full_screen)
|
|
||||||
|
|
||||||
Toast.makeText(this, R.string.exited_fullscreen, Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun toggleVoice() {
|
private fun toggleVoice() {
|
||||||
isVoiceEnabled = !isVoiceEnabled
|
isVoiceEnabled = !isVoiceEnabled
|
||||||
|
|
||||||
if (isVoiceEnabled) {
|
if (isVoiceEnabled) {
|
||||||
mediaPlayer?.setVolume(1.0f, 1.0f)
|
|
||||||
binding.ivVoice.setImageResource(com.example.defenseapplication.R.drawable.voice_on_open)
|
binding.ivVoice.setImageResource(com.example.defenseapplication.R.drawable.voice_on_open)
|
||||||
Toast.makeText(this, R.string.sound_on, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.sound_on, Toast.LENGTH_SHORT).show()
|
||||||
} else {
|
} else {
|
||||||
mediaPlayer?.setVolume(0.0f, 0.0f)
|
|
||||||
binding.ivVoice.setImageResource(com.example.defenseapplication.R.drawable.voice)
|
binding.ivVoice.setImageResource(com.example.defenseapplication.R.drawable.voice)
|
||||||
Toast.makeText(this, R.string.sound_off, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.sound_off, Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
@@ -378,20 +240,6 @@ class LiveVideoActivity : BaseActivity(), SurfaceHolder.Callback {
|
|||||||
Toast.makeText(this, R.string.stop_control_mode, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.stop_control_mode, Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
// private fun startMicPulseAnimation() {
|
|
||||||
// micPulseAnimation = ScaleAnimation(
|
|
||||||
// 1.0f, 1.3f,
|
|
||||||
// 1.0f, 1.3f,
|
|
||||||
// Animation.RELATIVE_TO_SELF, 0.5f,
|
|
||||||
// Animation.RELATIVE_TO_SELF, 0.5f
|
|
||||||
// ).apply {
|
|
||||||
// duration = 500
|
|
||||||
// repeatCount = Animation.INFINITE
|
|
||||||
// repeatMode = Animation.REVERSE
|
|
||||||
// interpolator = LinearInterpolator()
|
|
||||||
// }
|
|
||||||
// binding.ivVoice.startAnimation(micPulseAnimation)
|
|
||||||
// }
|
|
||||||
|
|
||||||
private fun stopMicPulseAnimation() {
|
private fun stopMicPulseAnimation() {
|
||||||
micPulseAnimation?.let {
|
micPulseAnimation?.let {
|
||||||
@@ -434,32 +282,26 @@ class LiveVideoActivity : BaseActivity(), SurfaceHolder.Callback {
|
|||||||
mediaRecorder = null
|
mediaRecorder = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
override fun onResume() {
|
||||||
private fun releaseMediaPlayer() {
|
super.onResume()
|
||||||
mediaPlayer?.let {
|
exoPlayerManager.onResume()
|
||||||
if (it.isPlaying) {
|
|
||||||
it.stop()
|
|
||||||
}
|
|
||||||
it.release()
|
|
||||||
mediaPlayer = null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
mediaPlayer?.pause()
|
exoPlayerManager.onPause()
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
mediaPlayer?.start()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
releaseMediaPlayer()
|
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
exoPlayerManager.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||||
|
super.onConfigurationChanged(newConfig)
|
||||||
|
// 横竖屏切换时通知播放器
|
||||||
|
exoPlayerManager.onConfigurationChanged(newConfig)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,9 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="#F5F6F6"
|
android:background="#F5F6F6"
|
||||||
|
android:name=".liveVideo.LiveVideoActivity"
|
||||||
|
android:configChanges="orientation|screenSize|keyboardHidden"
|
||||||
|
android:screenOrientation="portrait"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<!-- 顶部导航栏 -->
|
<!-- 顶部导航栏 -->
|
||||||
@@ -41,68 +44,12 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- 视频流信息 -->
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/bitRateBar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="32dp"
|
|
||||||
android:background="#FFFFFF"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:paddingLeft="16dp"
|
|
||||||
android:paddingRight="16dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tvBitRate"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center"
|
|
||||||
android:text="120 B/S"
|
|
||||||
android:textColor="@color/black"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<!-- 视频播放区域 -->
|
<!-- 视频播放区域 -->
|
||||||
<FrameLayout
|
<chuangyuan.ycj.videolibrary.widget.VideoPlayerView
|
||||||
android:id="@+id/videoContainer"
|
android:id="@+id/exoPlayContextId"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="220dp"
|
android:layout_height="250dp"
|
||||||
android:background="#000000">
|
android:background="@android:color/transparent"/>
|
||||||
|
|
||||||
<SurfaceView
|
|
||||||
android:id="@+id/surface_view"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_gravity="center" />
|
|
||||||
|
|
||||||
<!-- 全屏按钮 -->
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/ivFullscreen"
|
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_gravity="bottom|end"
|
|
||||||
android:layout_margin="16dp"
|
|
||||||
android:src="@drawable/full_screen"/>
|
|
||||||
|
|
||||||
<!-- 播放控制按钮 -->
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/playControl"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center"
|
|
||||||
android:visibility="gone">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/ivPlay"
|
|
||||||
android:layout_width="64dp"
|
|
||||||
android:layout_height="64dp"
|
|
||||||
android:src="@drawable/full_screen" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
<!-- 功能按钮区域 -->
|
<!-- 功能按钮区域 -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|||||||
@@ -12,4 +12,6 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
|||||||
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
|
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
|
||||||
# org.gradle.parallel=true
|
# org.gradle.parallel=true
|
||||||
# Kotlin code style for this project: "official" or "obsolete":
|
# Kotlin code style for this project: "official" or "obsolete":
|
||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
|
android.useAndroidX=true
|
||||||
|
android.enableJetifier=true
|
||||||
Reference in New Issue
Block a user