Skip to content

Instantly share code, notes, and snippets.

@Andrew0000
Last active October 17, 2023 10:20
Show Gist options
  • Save Andrew0000/ed2140b28204fa94516c1d8775996d3f to your computer and use it in GitHub Desktop.
Save Andrew0000/ed2140b28204fa94516c1d8775996d3f to your computer and use it in GitHub Desktop.
VideoUtils, Scaling ExoPlayer, AspectRatioScaler
import android.annotation.SuppressLint
import android.view.View
import android.widget.FrameLayout
import androidx.core.view.updateLayoutParams
import com.google.android.exoplayer2.TracksInfo
import com.google.android.exoplayer2.util.MimeTypes
import com.google.android.exoplayer2.video.VideoSize
import timber.log.Timber
object VideoUtils {
/**
* It's useful because:
* videoScalingMode = C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
* doesn't work after pause and on emulator.
* Or perform actual scaling after first frame appearance so there is a twitching.
*/
fun updateVideoViewRatio(
videoSize: VideoSize,
videoView: View,
parentFrame: FrameLayout? = null,
) {
updateVideoViewRatio(
videoSize.width,
videoSize.height,
videoView,
parentFrame,
videoSize.pixelWidthHeightRatio,
)
}
fun updateVideoViewRatio(
videoWidth: Int,
videoHeight: Int,
videoView: View,
parentFrame: FrameLayout? = null,
pixelWidthHeightRatio: Float = 1f,
) {
val parent = parentFrame ?: videoView.parentView() ?: return
Timber.d("[Video Utils] ratio videoSize: $videoWidth / $videoHeight / $pixelWidthHeightRatio")
Timber.d("[Video Utils] ratio parent: ${parent.width} / ${parent.height}")
if (videoWidth == 0 || videoHeight == 0) {
return
}
val videoWidthScaled = (videoWidth * pixelWidthHeightRatio).toInt()
AspectRatioScaler
.fit(videoWidthScaled, videoHeight)
.into(parent.width, parent.height)
.let { (w, h) ->
Timber.d("[Video Utils] size calc: $w / $h")
if (w > 0 && h > 0) {
videoView.scaleX = 1f
videoView.scaleY = 1f
videoView.updateLayoutParams {
width = w
height = h
}
}
}
}
}
fun TracksInfo?.containsAudioTrack(): Boolean {
if (this == null) {
return false
}
for (i in 0 until trackGroupInfos.size) {
val trackGroup = trackGroupInfos[i].trackGroup
for (j in 0 until trackGroup.length) {
if (MimeTypes.isAudio(trackGroup.getFormat(j).sampleMimeType)) {
return true
}
}
}
return false
}
@SuppressLint("BinaryOperationInTimber")
fun TracksInfo?.findVideoSize(): Pair<Int, Int>? {
if (this == null) {
return null
}
for (i in 0 until trackGroupInfos.size) {
val trackGroup = trackGroupInfos[i].trackGroup
for (j in 0 until trackGroup.length) {
val format = trackGroup.getFormat(j)
Timber.i("[Video Utils] findVideoSize: ${format.width} / ${format.height} / " +
"${format.sampleMimeType} : ${MimeTypes.isVideo(format.sampleMimeType)}")
if (format.width > 0 && format.height > 0) {
return format.width to format.height
}
}
}
return null
}
object AspectRatioScaler {
fun fit(w: Int, h: Int) = Src(w, h)
private fun fitToOuter(srcW: Float, srcH: Float, outerW: Float, outerH: Float): Pair<Int, Int> {
val srcToOuterRatioW = srcW / outerW
val srcToOuterRatioH = srcH / outerH
val smallestToOuterRatio = minOf(srcToOuterRatioW, srcToOuterRatioH)
return (srcW / smallestToOuterRatio).toInt() to (srcH / smallestToOuterRatio).toInt()
}
data class Src(private val srcW: Int, private val srcH: Int) {
fun into(w: Int, h: Int) =
fitToOuter(srcW.toFloat(), srcH.toFloat(), w.toFloat(), h.toFloat())
}
}
player = ExoPlayer.Builder(context).build().also { player ->
player.addListener(object : Player.Listener {
override fun onVideoSizeChanged(videoSize: VideoSize) {
if (isResumed) {
VideoUtils.updateVideoViewRatio(videoSize, surfaceView, parentFrame = this@OnboardingVideoView)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment