背景
我们录制用户脸部的视频,通常脸部位于视频的上半部分.
稍后我们希望观看视频,但PlayerVIEw的宽高比可能与视频的宽高比不同,因此需要进行一些缩放和裁剪.
问题
我发现缩放PlayerVIEw的唯一方法是将它显示在它拥有的整个空间中,但保持纵横比(当然需要裁剪时),使用app:resize_mode =“zoom “.以下是中心作物:http://s000.tinyupload.com/?file_id=00574047057406286563的工作原理示例.显示内容的视图具有相似的宽高比越多,所需的裁剪越少.
但这仅适用于中心,这意味着它需要0.5×0.5的视频点,并从那一点开始进行缩放.这导致许多丢失视频重要内容的情况.
例如,如果我们有一个以纵向拍摄的视频,并且我们有一个方形的PlayerVIEw并想要显示顶部区域,那么这将是可见的部分:
当然,如果内容本身是正方形,并且视图也是正方形,则应该显示整个内容,而不进行裁剪.
我试过的
我试过通过互联网,StackOverflow(这里)和Github搜索,但我找不到如何做到这一点.我发现的唯一线索是关于AspectRatioFrameLayout和AspectRatioTextureVIEw,但我没有找到如何将它们用于此任务,如果它甚至可能的话.
我被告知(here)我应该使用普通的TextureVIEw,并使用SimpleExoPlayer.setVIDeoTextureVIEw将其直接提供给SimpleExoPlayer.并使用TextureVIEw.settransform为其设置特殊转换.
经过大量尝试最好的使用(并查看video-crop repository,SuperImageView repository和JCropImageView repository,其中包含ImageVIEw和视频的缩放/裁剪示例),我发布了一个似乎正确显示视频的工作示例,但我我仍然不确定它,因为我也使用在它开始播放之前显示在它上面的ImageVIEw(有一个更好的过渡而不是黑色内容).
这是当前的代码:
class MainActivity : AppCompatActivity() { private val imageResID = R.drawable.test private val vIDeoResID = R.raw.test private val percentageY = 0.2f private var player: SimpleExoPlayer? = null overrIDe fun onCreate(savedInstanceState: Bundle?) { window.setBackgroundDrawable(colorDrawable(0xff000000.toInt())) super.onCreate(savedInstanceState) if (cache == null) { cache = SimpleCache(file(cacheDir, "media"), LeastRecentlyUsedCacheevictor(MAX_PREVIEW_CACHE_SIZE_IN_BYTES)) } setContentVIEw(R.layout.activity_main)// imageVIEw.visibility = VIEw.INVISIBLE imageVIEw.setimageResource(imageResID) imageVIEw.doOnPreDraw { imageVIEw.imageMatrix = prepareMatrixForImageVIEw(imageVIEw, imageVIEw.drawable.intrinsicWIDth.tofloat(), imageVIEw.drawable.intrinsicHeight.tofloat())// imageVIEw.imageMatrix = prepareMatrix(imageVIEw, imageVIEw.drawable.intrinsicWIDth.tofloat(), imageVIEw.drawable.intrinsicHeight.tofloat())// imageVIEw.visibility = VIEw.VISIBLE } } overrIDe fun onStart() { super.onStart() playVIDeo() } private fun prepareMatrix(vIEw: VIEw, contentWIDth: float, contentHeight: float): Matrix { var scaleX = 1.0f var scaleY = 1.0f val vIEwWIDth = vIEw.measureDWIDth.tofloat() val vIEwHeight = vIEw.measuredHeight.tofloat() Log.d("AppLog", "vIEwWIDth $vIEwWIDth vIEwHeight $vIEwHeight contentWIDth:$contentWIDth contentHeight:$contentHeight") if (contentWIDth > vIEwWIDth && contentHeight > vIEwHeight) { scaleX = contentWIDth / vIEwWIDth scaleY = contentHeight / vIEwHeight } else if (contentWIDth < vIEwWIDth && contentHeight < vIEwHeight) { scaleY = vIEwWIDth / contentWIDth scaleX = vIEwHeight / contentHeight } else if (vIEwWIDth > contentWIDth) scaleY = vIEwWIDth / contentWIDth / (vIEwHeight / contentHeight) else if (vIEwHeight > contentHeight) scaleX = vIEwHeight / contentHeight / (vIEwWIDth / contentWIDth) val matrix = Matrix() val pivotPercentageX = 0.5f val pivotPercentageY = percentageY matrix.setScale(scaleX, scaleY, vIEwWIDth * pivotPercentageX, vIEwHeight * pivotPercentageY) return matrix } private fun prepareMatrixForVIDeo(vIEw: VIEw, contentWIDth: float, contentHeight: float): Matrix { val msWIDth = vIEw.measureDWIDth val msHeight = vIEw.measuredHeight val matrix = Matrix() matrix.setScale(1f, (contentHeight / contentWIDth) * (msWIDth.tofloat() / msHeight), msWIDth / 2f, percentageY * msHeight) /*,msWIDth/2f,msHeight/2f*/ return matrix } private fun prepareMatrixForImageVIEw(vIEw: VIEw, contentWIDth: float, contentHeight: float): Matrix { val DW = contentWIDth val dh = contentHeight val msWIDth = vIEw.measureDWIDth val msHeight = vIEw.measuredHeight// Log.d("AppLog", "vIEwWIDth $msWIDth vIEwHeight $msHeight contentWIDth:$contentWIDth contentHeight:$contentHeight") val scalew = msWIDth.tofloat() / DW val theoryh = (dh * scalew).toInt() val scaleh = msHeight.tofloat() / dh val theoryw = (DW * scaleh).toInt() val scale: float var dx = 0 var dy = 0 if (scalew > scaleh) { // fit wIDth scale = scalew// dy = ((msHeight - theoryh) * 0.0f + 0.5f).toInt() // + 0.5f for rounding } else { scale = scaleh dx = ((msWIDth - theoryw) * 0.5f + 0.5f).toInt() // + 0.5f for rounding } dy = ((msHeight - theoryh) * percentageY + 0.5f).toInt() // + 0.5f for rounding val matrix = Matrix()// Log.d("AppLog", "scale:$scale dx:$dx dy:$dy") matrix.setScale(scale, scale) matrix.postTranslate(dx.tofloat(), dy.tofloat()) return matrix } private fun playVIDeo() { player = ExoPlayerFactory.newSimpleInstance(this@MainActivity, DefaultTrackSelector()) player!!.setVIDeoTextureVIEw(textureVIEw) player!!.addVIDeoListener(object : VIDeoListener { overrIDe fun onVIDeoSizeChanged(wIDth: Int, height: Int, unapplIEdRotationdegrees: Int, pixelWIDthHeightRatio: float) { super.onVIDeoSizeChanged(wIDth, height, unapplIEdRotationdegrees, pixelWIDthHeightRatio) Log.d("AppLog", "onVIDeoSizeChanged: $wIDth $height") val vIDeoWIDth = if (unapplIEdRotationdegrees % 180 == 0) wIDth else height val vIDeoHeight = if (unapplIEdRotationdegrees % 180 == 0) height else wIDth val matrix = prepareMatrixForVIDeo(textureVIEw, vIDeoWIDth.tofloat(), vIDeoHeight.tofloat()) textureVIEw.settransform(matrix) } overrIDe fun onRenderedFirstFrame() { Log.d("AppLog", "onRenderedFirstFrame") player!!.removeVIDeoListener(this)// imageVIEw.animate().Alpha(0f).setDuration(5000).start() imageVIEw.visibility = VIEw.INVISIBLE } }) player!!.volume = 0f player!!.repeatMode = Player.REPEAT_MODE_ALL player!!.playRawVIDeo(this, vIDeoResID) player!!.playWhenReady = true // player!!.playVIDeoFromUrl(this, "https://sample-vIDeos.com/vIDeo123/mkv/240/big_buck_bunny_240p_20mb.mkv", cache!!) // player!!.playVIDeoFromUrl(this, "https://sample-vIDeos.com/vIDeo123/mkv/720/big_buck_bunny_720p_1mb.mkv", cache!!) // player!!.playVIDeoFromUrl(this@MainActivity, "https://sample-vIDeos.com/vIDeo123/mkv/720/big_buck_bunny_720p_1mb.mkv") } overrIDe fun onStop() { super.onStop() player!!.setVIDeoTextureVIEw(null) // playerVIEw.player = null player!!.release() player = null } companion object { const val MAX_PREVIEW_CACHE_SIZE_IN_BYTES = 20L * 1024L * 1024L var cache: com.Google.androID.exoplayer2.upstream.cache.Cache? = null @JvmStatic fun getUserAgent(context: Context): String { val packageManager = context.packageManager val info = packageManager.getPackageInfo(context.packagename, 0) val appname = info.applicationInfo.loadLabel(packageManager).toString() return Util.getUserAgent(context, appname) } } fun SimpleExoPlayer.playRawVIDeo(context: Context, @RawRes rawVIDeoRes: Int) { val dataSpec = DataSpec(RawResourceDataSource.buildrawResourceUri(rawVIDeoRes)) val rawResourceDataSource = RawResourceDataSource(context) rawResourceDataSource.open(dataSpec) val factory: DataSource.Factory = DataSource.Factory { rawResourceDataSource } prepare(LooPingMediaSource(ExtractorMediaSource.Factory(factory).createMediaSource(rawResourceDataSource.uri))) } fun SimpleExoPlayer.playVIDeoFromUrl(context: Context, url: String, cache: Cache? = null) = playVIDeoFromUri(context, Uri.parse(url), cache) fun SimpleExoPlayer.playVIDeofile(context: Context, file: file) = playVIDeoFromUri(context, Uri.fromfile(file)) fun SimpleExoPlayer.playVIDeoFromUri(context: Context, uri: Uri, cache: Cache? = null) { val factory = if (cache != null) CacheDataSourceFactory(cache, DefaulthttpDataSourceFactory(getUserAgent(context))) else DefaultDataSourceFactory(context, MainActivity.getUserAgent(context)) val mediaSource = ExtractorMediaSource.Factory(factory).createMediaSource(uri) prepare(mediaSource) }}
在我遇到目前的情况之前,我遇到了各种各样的问题,并且我已经多次更新了这个问题.现在它甚至适用于我所谈论的百分比,所以如果我愿意,我可以将其设置为视频顶部的20%.但是,我仍然认为它有可能出现问题,因为当我尝试将其设置为50%时,我注意到内容可能不适合整个VIEw.
我甚至查看了ImageVIEw(here)的源代码,看看如何使用中心裁剪.当应用于ImageVIEw时,它仍然可以作为中心裁剪,但是当我在视频上使用相同的技术时,它给了我一个非常错误的结果.
问题
我的目标是显示ImageVIEw和视频,以便它可以平滑地从静态图像转换为视频.所有这一切都同时具有从顶部20%的顶级作物(例如).我已经发布了一个示例项目here,试用它并分享我发现的人.
所以现在我的问题是为什么这对于imageVIEw和/或视频似乎不太好用:
>事实证明,我尝试过的矩阵创作都不适用于ImageVIEw或视频.这究竟是什么问题?如何更改它们才能看起来一样?例如,从前20%进行规模裁剪?
>我尝试使用两者的精确矩阵,但似乎每个都需要不同,即使两者具有完全相同的大小和内容大小.为什么我需要每个不同的矩阵?
编辑:在回答了这个问题之后,我决定制作一个如何使用它的小样本(Github存储库可用here):
import androID.content.Contextimport androID.graphics.Matriximport androID.graphics.PointFimport androID.net.Uriimport androID.os.Bundleimport androID.vIEw.TextureVIEwimport androID.vIEw.VIEwimport androIDx.annotation.RawResimport androIDx.appcompat.app.AppCompatActivityimport androIDx.core.vIEw.doOnPreDrawimport com.Google.androID.exoplayer2.ExoPlayerFactoryimport com.Google.androID.exoplayer2.Playerimport com.Google.androID.exoplayer2.SimpleExoPlayerimport com.Google.androID.exoplayer2.source.ExtractorMediaSourceimport com.Google.androID.exoplayer2.source.LooPingMediaSourceimport com.Google.androID.exoplayer2.trackselection.DefaultTrackSelectorimport com.Google.androID.exoplayer2.upstream.*import com.Google.androID.exoplayer2.upstream.cache.Cacheimport com.Google.androID.exoplayer2.upstream.cache.CacheDataSourceFactoryimport com.Google.androID.exoplayer2.upstream.cache.LeastRecentlyUsedCacheevictorimport com.Google.androID.exoplayer2.upstream.cache.SimpleCacheimport com.Google.androID.exoplayer2.util.Utilimport com.Google.androID.exoplayer2.vIDeo.VIDeoListenerimport kotlinx.androID.synthetic.main.activity_main.*import java.io.file// https://stackoverflow.com/questions/54216273/how-to-have-similar-mechanism-of-center-crop-on-exoplayers-playervIEw-but-notclass MainActivity : AppCompatActivity() { companion object { private val FOCAL_POINT = PointF(0.5f, 0.2f) private const val IMAGE_RES_ID = R.drawable.test private const val VIDEO_RES_ID = R.raw.test private var cache: Cache? = null private const val MAX_PREVIEW_CACHE_SIZE_IN_BYTES = 20L * 1024L * 1024L @JvmStatic fun getUserAgent(context: Context): String { val packageManager = context.packageManager val info = packageManager.getPackageInfo(context.packagename, 0) val appname = info.applicationInfo.loadLabel(packageManager).toString() return Util.getUserAgent(context, appname) } } private var player: SimpleExoPlayer? = null overrIDe fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentVIEw(R.layout.activity_main) if (cache == null) cache = SimpleCache(file(cacheDir, "media"), LeastRecentlyUsedCacheevictor(MAX_PREVIEW_CACHE_SIZE_IN_BYTES)) // imageVIEw.visibility = VIEw.INVISIBLE imageVIEw.setimageResource(IMAGE_RES_ID) } private fun prepareMatrix(vIEw: VIEw, mediawidth: float, mediaHeight: float, focalPoint: PointF): Matrix? { if (vIEw.visibility == VIEw.GONE) return null val vIEwHeight = (vIEw.height - vIEw.paddingtop - vIEw.paddingBottom).tofloat() val vIEwWIDth = (vIEw.wIDth - vIEw.paddingStart - vIEw.paddingEnd).tofloat() if (vIEwWIDth <= 0 || vIEwHeight <= 0) return null val matrix = Matrix() if (vIEw is TextureVIEw) // Restore true media size for further manipulation. matrix.setScale(mediawidth / vIEwWIDth, mediaHeight / vIEwHeight) val scaleFactorY = vIEwHeight / mediaHeight val scaleFactor: float var px = 0f var py = 0f if (mediawidth * scaleFactorY >= vIEwWIDth) { // Fit height scaleFactor = scaleFactorY px = -(mediawidth * scaleFactor - vIEwWIDth) * focalPoint.x / (1 - scaleFactor) } else { // Fit wIDth scaleFactor = vIEwWIDth / mediawidth py = -(mediaHeight * scaleFactor - vIEwHeight) * focalPoint.y / (1 - scaleFactor) } matrix.postscale(scaleFactor, scaleFactor, px, py) return matrix } private fun playVIDeo() { player = ExoPlayerFactory.newSimpleInstance(this@MainActivity, DefaultTrackSelector()) player!!.setVIDeoTextureVIEw(textureVIEw) player!!.addVIDeoListener(object : VIDeoListener { overrIDe fun onVIDeoSizeChanged(vIDeoWIDth: Int, vIDeoHeight: Int, unapplIEdRotationdegrees: Int, pixelWIDthHeightRatio: float) { super.onVIDeoSizeChanged(vIDeoWIDth, vIDeoHeight, unapplIEdRotationdegrees, pixelWIDthHeightRatio) textureVIEw.settransform(prepareMatrix(textureVIEw, vIDeoWIDth.tofloat(), vIDeoHeight.tofloat(), FOCAL_POINT)) } overrIDe fun onRenderedFirstFrame() { // Log.d("AppLog", "onRenderedFirstFrame") player!!.removeVIDeoListener(this) imageVIEw.animate().Alpha(0f).setDuration(2000).start() // imageVIEw.visibility = VIEw.INVISIBLE } }) player!!.volume = 0f player!!.repeatMode = Player.REPEAT_MODE_ALL player!!.playRawVIDeo(this, VIDEO_RES_ID) player!!.playWhenReady = true // player!!.playVIDeoFromUrl(this, "https://sample-vIDeos.com/vIDeo123/mkv/240/big_buck_bunny_240p_20mb.mkv", cache!!) // player!!.playVIDeoFromUrl(this, "https://sample-vIDeos.com/vIDeo123/mkv/720/big_buck_bunny_720p_1mb.mkv", cache!!) // player!!.playVIDeoFromUrl(this@MainActivity, "https://sample-vIDeos.com/vIDeo123/mkv/720/big_buck_bunny_720p_1mb.mkv") } overrIDe fun onStart() { super.onStart() imageVIEw.doOnPreDraw { val imageWIDth: float = imageVIEw.drawable.intrinsicWIDth.tofloat() val imageHeight: float = imageVIEw.drawable.intrinsicHeight.tofloat() imageVIEw.imageMatrix = prepareMatrix(imageVIEw, imageWIDth, imageHeight, FOCAL_POINT) } playVIDeo() } overrIDe fun onStop() { super.onStop() if (player != null) { player!!.setVIDeoTextureVIEw(null) // playerVIEw.player = null player!!.release() player = null } } overrIDe fun onDestroy() { super.onDestroy() if (!isChangingConfigurations) cache?.release() } fun SimpleExoPlayer.playRawVIDeo(context: Context, @RawRes rawVIDeoRes: Int) { val dataSpec = DataSpec(RawResourceDataSource.buildrawResourceUri(rawVIDeoRes)) val rawResourceDataSource = RawResourceDataSource(context) rawResourceDataSource.open(dataSpec) val factory: DataSource.Factory = DataSource.Factory { rawResourceDataSource } prepare(LooPingMediaSource(ExtractorMediaSource.Factory(factory).createMediaSource(rawResourceDataSource.uri))) } fun SimpleExoPlayer.playVIDeoFromUrl(context: Context, url: String, cache: Cache? = null) = playVIDeoFromUri(context, Uri.parse(url), cache) fun SimpleExoPlayer.playVIDeofile(context: Context, file: file) = playVIDeoFromUri(context, Uri.fromfile(file)) fun SimpleExoPlayer.playVIDeoFromUri(context: Context, uri: Uri, cache: Cache? = null) { val factory = if (cache != null) CacheDataSourceFactory(cache, DefaulthttpDataSourceFactory(getUserAgent(context))) else DefaultDataSourceFactory(context, MainActivity.getUserAgent(context)) val mediaSource = ExtractorMediaSource.Factory(factory).createMediaSource(uri) prepare(mediaSource) }}
如果需要,这里是ImageVIEw的解决方案:
class ScaleCropImageVIEw(context: Context, attrs: AttributeSet?) : AppCompatimageVIEw(context, attrs) { var focalPoint = PointF(0.5f, 0.5f) set(value) { fIEld = value updateMatrix() } private val vIEwWIDth: float get() = (wIDth - paddingleft - paddingRight).tofloat() private val vIEwHeight: float get() = (height - paddingtop - paddingBottom).tofloat() init { scaleType = ScaleType.MATRIX } overrIDe fun onSizeChanged(w: Int, h: Int, olDW: Int, oldh: Int) { super.onSizeChanged(w, h, olDW, oldh) updateMatrix() } overrIDe fun setimageDrawable(drawable: Drawable?) { super.setimageDrawable(drawable) updateMatrix() } @Suppress("MemberVisibilityCanBePrivate") fun updateMatrix() { if (scaleType != ImageVIEw.ScaleType.MATRIX) return val dr = drawable ?: return imageMatrix = prepareMatrix( vIEwWIDth, vIEwHeight, dr.intrinsicWIDth.tofloat(), dr.intrinsicHeight.tofloat(), focalPoint, Matrix() ) } private fun prepareMatrix( vIEwWIDth: float, vIEwHeight: float, mediawidth: float, mediaHeight: float, focalPoint: PointF, matrix: Matrix ): Matrix? { if (vIEwWIDth <= 0 || vIEwHeight <= 0) return null var scaleFactor = vIEwHeight / mediaHeight if (mediawidth * scaleFactor >= vIEwWIDth) { // Fit height matrix.postscale(scaleFactor, scaleFactor, -(mediawidth * scaleFactor - vIEwWIDth) * focalPoint.x / (1 - scaleFactor), 0f) } else { // Fit wIDth scaleFactor = vIEwWIDth / mediawidth matrix.postscale(scaleFactor, scaleFactor, 0f, -(mediaHeight * scaleFactor - vIEwHeight) * focalPoint.y / (1 - scaleFactor)) } return matrix }}
解决方法:
问题是如何 *** 作像ImageView.ScaleType.CENTER_CROP
这样的图像,但是将焦点从中心移动到距离图像顶部20%的另一个位置.首先,让我们看一下CENTER_CROP的作用:
从documentation开始:
CENTER_CROP
Scale the image uniformly (maintain the image’s aspect ratio) so that both dimensions (wIDth and height) of the image will be equal to or larger than the corresponding dimension of the vIEw (minus padding). The image is then centered in the vIEw. From XML, use this Syntax:
androID:scaleType="centerCrop"
.
换句话说,缩放图像而不失真,使得图像的宽度或高度(或宽度和高度)都适合视图,以便视图完全被图像填充(无间隙).
另一种想到这一点的方法是将图像的中心“固定”到视图的中心.然后缩放图像以满足上述标准.
在下面的视频中,白线标出图像的中心;红线标出视图的中心.比例类型是CENTER_CROP.注意图像的中心点和视图是如何重合的.当视图改变大小时,无论视图大小如何,这两个点都会继续重叠并始终显示在视图的中心.
那么,在不同的位置(如距离顶部20%)具有类似中心作物的行为意味着什么?与中心裁剪一样,我们可以指定距离图像顶部20%的点和距离视图顶部20%的点将像50%点一样“固定”在中心裁剪中“固定”.此点的水平位置保持在图像和视图的50%.现在可以缩放图像以满足中心裁剪的其他条件,其指定图像的宽度和/或高度将适合视图而没有间隙. (视图大小被理解为视图大小减去填充.)
这是20%作物行为的简短视频.在此视频中,白线显示图像的中间,红线显示视图中的固定点,显示在水平红线后面的蓝线表示距图像顶部20%. (演示项目于GitHub.
以下结果显示了所提供的完整图像以及从静止图像过渡的方框中的视频. .
MainActivity.kt
prepareMatrix()是确定如何缩放/裁剪图像的工作方法.视频还有一些额外的工作要做,因为当分配给TextureVIEw时,视频看起来适合TextureVIEwas的比例类型“FIT_XY”.由于此缩放,必须在为视频调用prepareMatrix()之前恢复媒体大小
class MainActivity : AppCompatActivity() { private val imageResID = R.drawable.test private val vIDeoResID = R.raw.test private var player: SimpleExoPlayer? = null private val mFocalPoint = PointF(0.5f, 0.2f) overrIDe fun onCreate(savedInstanceState: Bundle?) { window.setBackgroundDrawable(colorDrawable(0xff000000.toInt())) super.onCreate(savedInstanceState) if (cache == null) { cache = SimpleCache(file(cacheDir, "media"), LeastRecentlyUsedCacheevictor(MAX_PREVIEW_CACHE_SIZE_IN_BYTES)) } setContentVIEw(R.layout.activity_main) // imageVIEw.visibility = VIEw.INVISIBLE imageVIEw.setimageResource(imageResID) imageVIEw.doOnPreDraw { imageVIEw.scaleType = ImageVIEw.ScaleType.MATRIX val imageWIDth: float = ContextCompat.getDrawable(this, imageResID)!!.intrinsicWIDth.tofloat() val imageHeight: float = ContextCompat.getDrawable(this, imageResID)!!.intrinsicHeight.tofloat() imageVIEw.imageMatrix = prepareMatrix(imageVIEw, imageWIDth, imageHeight, mFocalPoint, Matrix()) val b = BitmapFactory.decodeResource(resources, imageResID) val d = BitmapDrawable(resources, b.copy(Bitmap.Config.ARGB_8888, true)) val c = Canvas(d.bitmap) val p = Paint() p.color = resources.getcolor(androID.R.color.holo_red_dark) p.style = Paint.Style.stroke val strokeWIDth = 10 p.strokeWIDth = strokeWIDth.tofloat() // Horizontal line c.drawline(0f, imageHeight * mFocalPoint.y, imageWIDth, imageHeight * mFocalPoint.y, p) // Vertical line c.drawline(imageWIDth * mFocalPoint.x, 0f, imageWIDth * mFocalPoint.x, imageHeight, p) // line in horizontal and vertical center p.color = resources.getcolor(androID.R.color.white) c.drawline(imageWIDth / 2, 0f, imageWIDth / 2, imageHeight, p) c.drawline(0f, imageHeight / 2, imageWIDth, imageHeight / 2, p) imageVIEw.setimageBitmap(d.bitmap) imageVIEwFull.setimageBitmap(d.bitmap) } } fun startPlay(vIEw: VIEw) { playVIDeo() } private fun getVIEwWIDth(vIEw: VIEw): float { return (vIEw.wIDth - vIEw.paddingStart - vIEw.paddingEnd).tofloat() } private fun getVIEwHeight(vIEw: VIEw): float { return (vIEw.height - vIEw.paddingtop - vIEw.paddingBottom).tofloat() } private fun prepareMatrix(targetVIEw: VIEw, mediawidth: float, mediaHeight: float, focalPoint: PointF, matrix: Matrix): Matrix { if (targetVIEw.visibility != VIEw.VISIBLE) { return matrix } val vIEwHeight = getVIEwHeight(targetVIEw) val vIEwWIDth = getVIEwWIDth(targetVIEw) val scaleFactorY = vIEwHeight / mediaHeight val scaleFactor: float val px: float val py: float if (mediawidth * scaleFactorY >= vIEwWIDth) { // Fit height scaleFactor = scaleFactorY px = -(mediawidth * scaleFactor - vIEwWIDth) * focalPoint.x / (1 - scaleFactor) py = 0f } else { // Fit wIDth scaleFactor = vIEwWIDth / mediawidth px = 0f py = -(mediaHeight * scaleFactor - vIEwHeight) * focalPoint.y / (1 - scaleFactor) } matrix.postscale(scaleFactor, scaleFactor, px, py) return matrix } private fun playVIDeo() { player = ExoPlayerFactory.newSimpleInstance(this@MainActivity, DefaultTrackSelector()) player!!.setVIDeoTextureVIEw(textureVIEw) player!!.addVIDeoListener(object : VIDeoListener { overrIDe fun onVIDeoSizeChanged(wIDth: Int, height: Int, unapplIEdRotationdegrees: Int, pixelWIDthHeightRatio: float) { super.onVIDeoSizeChanged(wIDth, height, unapplIEdRotationdegrees, pixelWIDthHeightRatio) val matrix = Matrix() // Restore true media size for further manipulation. matrix.setScale(wIDth / getVIEwWIDth(textureVIEw), height / getVIEwHeight(textureVIEw)) textureVIEw.settransform(prepareMatrix(textureVIEw, wIDth.tofloat(), height.tofloat(), mFocalPoint, matrix)) } overrIDe fun onRenderedFirstFrame() { Log.d("AppLog", "onRenderedFirstFrame") player!!.removeVIDeoListener(this) imageVIEw.animate().Alpha(0f).setDuration(2000).start() imageVIEw.visibility = VIEw.INVISIBLE } }) player!!.volume = 0f player!!.repeatMode = Player.REPEAT_MODE_ALL player!!.playRawVIDeo(this, vIDeoResID) player!!.playWhenReady = true // player!!.playVIDeoFromUrl(this, "https://sample-vIDeos.com/vIDeo123/mkv/240/big_buck_bunny_240p_20mb.mkv", cache!!) // player!!.playVIDeoFromUrl(this, "https://sample-vIDeos.com/vIDeo123/mkv/720/big_buck_bunny_720p_1mb.mkv", cache!!) // player!!.playVIDeoFromUrl(this@MainActivity, "https://sample-vIDeos.com/vIDeo123/mkv/720/big_buck_bunny_720p_1mb.mkv") } overrIDe fun onStop() { super.onStop() if (player != null) { player!!.setVIDeoTextureVIEw(null) // playerVIEw.player = null player!!.release() player = null } } companion object { const val MAX_PREVIEW_CACHE_SIZE_IN_BYTES = 20L * 1024L * 1024L var cache: com.Google.androID.exoplayer2.upstream.cache.Cache? = null @JvmStatic fun getUserAgent(context: Context): String { val packageManager = context.packageManager val info = packageManager.getPackageInfo(context.packagename, 0) val appname = info.applicationInfo.loadLabel(packageManager).toString() return Util.getUserAgent(context, appname) } } fun SimpleExoPlayer.playRawVIDeo(context: Context, @RawRes rawVIDeoRes: Int) { val dataSpec = DataSpec(RawResourceDataSource.buildrawResourceUri(rawVIDeoRes)) val rawResourceDataSource = RawResourceDataSource(context) rawResourceDataSource.open(dataSpec) val factory: DataSource.Factory = DataSource.Factory { rawResourceDataSource } prepare(LooPingMediaSource(ExtractorMediaSource.Factory(factory).createMediaSource(rawResourceDataSource.uri))) } fun SimpleExoPlayer.playVIDeoFromUrl(context: Context, url: String, cache: Cache? = null) = playVIDeoFromUri(context, Uri.parse(url), cache) fun SimpleExoPlayer.playVIDeofile(context: Context, file: file) = playVIDeoFromUri(context, Uri.fromfile(file)) fun SimpleExoPlayer.playVIDeoFromUri(context: Context, uri: Uri, cache: Cache? = null) { val factory = if (cache != null) CacheDataSourceFactory(cache, DefaulthttpDataSourceFactory(getUserAgent(context))) else DefaultDataSourceFactory(context, MainActivity.getUserAgent(context)) val mediaSource = ExtractorMediaSource.Factory(factory).createMediaSource(uri) prepare(mediaSource) }}
总结 以上是内存溢出为你收集整理的android – 如何在ExoPlayer的PlayerView上使用类似的中心裁剪机制,但不在中心?全部内容,希望文章能够帮你解决android – 如何在ExoPlayer的PlayerView上使用类似的中心裁剪机制,但不在中心?所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)