Android SurfaceView视频缩放平移旋转及背景色处理技术问题
视频编辑功能迁移至SurfaceView的旋转问题
我正在开发一个视频编辑上传功能:从相册选择视频,编辑后上传至后端服务器。目前遇到以下瓶颈:
- 项目依赖第三方SDK,必须使用SurfaceView实例处理视频/图像编辑
- 需要实现类似Instagram的捏合缩放、全屏拖动视频至任意位置的功能
- 可为视频帧外部区域设置背景色
- 最终需导出包含所有上述编辑效果的视频
我已基于TextureView实现了所有功能,但切换到SurfaceView后无法正常工作。以下是TextureView的可运行代码及布局文件:
class VideoEditActivity : ComponentActivity() { private lateinit var textureView: TextureView private lateinit var mediaPlayer: MediaPlayer private lateinit var videoContainer: FrameLayout private var scaleGestureDetector: ScaleGestureDetector? = null private var gestureDetector: GestureDetector? = null private var scaleFactor = 1.0f private var translationX = 0f private var translationY = 0f private var rotationDegrees = 0f private var initialRotationDegrees = 0f private lateinit var selectedFilePath: String override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_video_edit) textureView = findViewById(R.id.textureView) videoContainer = findViewById(R.id.videoContainer) videoContainer.setBackgroundResource(R.color.purple_200) selectedFilePath = getPathFromUri(Uri.parse(intent.getStringExtra(INTENT_DATA))) Logger.log("Selected file path: $selectedFilePath") findViewById<ImageView>(R.id.ivVideoPlay).setOnClickListener { // captureAndCreateVideo() } setupMediaPlayer() setupGestures() } private fun setupMediaPlayer() { textureView.surfaceTextureListener = object : TextureView.SurfaceTextureListener { override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) { val selectedMediaUri = Uri.parse(intent.getStringExtra(INTENT_DATA)) selectedMediaUri?.let { mediaPlayer = MediaPlayer.create(this@VideoEditActivity, it) // Adjust the source accordingly } mediaPlayer.setSurface(Surface(surface)) mediaPlayer.isLooping = true mediaPlayer.start() } override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {} override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean { mediaPlayer.release() return true } override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {} } } private fun setupGestures() { scaleGestureDetector = ScaleGestureDetector(this, object : ScaleGestureDetector.SimpleOnScaleGestureListener() { override fun onScale(detector: ScaleGestureDetector): Boolean { scaleFactor *= detector.scaleFactor scaleFactor = max(0.1f, min(scaleFactor, 5.0f)) // Limit scaling textureView.scaleX = scaleFactor textureView.scaleY = scaleFactor return true } }) gestureDetector = GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() { override fun onScroll(e1: MotionEvent?, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean { translationX -= distanceX translationY -= distanceY textureView.translationX = translationX textureView.translationY = translationY return true } }) videoContainer.setOnTouchListener { _, event -> if (event.pointerCount == 2) { if (event.actionMasked == MotionEvent.ACTION_POINTER_DOWN) { initialRotationDegrees = rotation(event) } else if (event.actionMasked == MotionEvent.ACTION_MOVE) { val currentRotationDegrees = rotation(event) val deltaDegrees = initialRotationDegrees - currentRotationDegrees rotationDegrees -= deltaDegrees textureView.rotation = rotationDegrees initialRotationDegrees = currentRotationDegrees } } scaleGestureDetector?.onTouchEvent(event) gestureDetector?.onTouchEvent(event) true } } private fun rotation(event: MotionEvent): Float { val dx = (event.getX(0) - event.getX(1)).toDouble() val dy = (event.getY(0) - event.getY(1)).toDouble() return Math.toDegrees(atan2(dy, dx)).toFloat() } private fun getPathFromUri(uri: Uri): String { var filePath: String? = null val projection = arrayOf(MediaStore.Video.Media.DATA) val cursor = contentResolver.query(uri, projection, null, null, null) if (cursor != null && cursor.moveToFirst()) { val columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA) filePath = cursor.getString(columnIndex) cursor.close() } return filePath ?: "" } }
XML布局文件:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:id="@+id/mainLayout" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/ivSelectedImage" android:src="@drawable/app_logo" android:layout_centerInParent="true" android:foregroundGravity="center" android:visibility="gone" android:contentDescription="selected_image" /> <FrameLayout android:id="@+id/videoContainer" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- Background color --> <TextureView android:id="@+id/textureView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> </FrameLayout> <ImageView android:layout_width="50dp" android:layout_height="50dp" android:src="@drawable/play_icon" android:layout_centerInParent="true" android:visibility="gone" android:id="@+id/ivVideoPlay"/> </RelativeLayout>
更新:我已实现SurfaceView的捏合缩放功能,但旋转效果不符合预期——仅容器旋转,SurfaceView内的视频内容未同步旋转。当前SurfaceView手势实现代码如下:
private fun setupSurfaceGestures() { scaleGestureDetector = ScaleGestureDetector(this, object : ScaleGestureDetector.SimpleOnScaleGestureListener() { override fun onScale(detector: ScaleGestureDetector): Boolean { scaleFactor *= detector.scaleFactor scaleFactor = max(0.1f, min(scaleFactor, 5.0f)) // Limit scaling // Update the SurfaceView scale here if possible or handle via custom drawing surfaceView.scaleX = scaleFactor surfaceView.scaleY = scaleFactor return true } }) gestureDetector = GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() { override fun onScroll(e1: MotionEvent?, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean { translationX -= distanceX translationY -= distanceY // Update the SurfaceView translation here if possible or handle via custom drawing surfaceView.translationX = translationX surfaceView.translationY = translationY return true } }) videoContainer.setOnTouchListener { _, event -> if (event.pointerCount == 2) { if (event.actionMasked == MotionEvent.ACTION_POINTER_DOWN) { initialRotationDegrees = rotation(event) } else if (event.actionMasked == MotionEvent.ACTION_MOVE) { val currentRotationDegrees = rotation(event) val deltaDegrees = initialRotationDegrees - currentRotationDegrees rotationDegrees -= deltaDegrees surfaceView.rotation = rotationDegrees initialRotationDegrees = currentRotationDegrees } } scaleGestureDetector?.onTouchEvent(event) gestureDetector?.onTouchEvent(event) true } }
内容的提问来源于stack exchange,提问作者CoderDev
相关产品推荐
相关产品推荐

