Android中使用TextureView编程实现多视频裁剪与播放问题求助
Android TextureView多视频播放与裁剪问题解决
一、先解决surfaceTexture must not be null异常
问题根源
你在onCreate里直接调用videoView1.getSurfaceTexture()时,TextureView的SurfaceTexture还没完成初始化,返回了null,传给new Surface()自然就触发参数异常了。TextureView的SurfaceTexture是在视图完成绘制后才会创建的,必须等它可用后再绑定MediaPlayer。
修复后的代码
给每个TextureView设置SurfaceTextureListener,在回调里处理MediaPlayer的初始化:
import androidx.appcompat.app.AppCompatActivity; import android.media.MediaPlayer; import android.os.Bundle; import android.graphics.Matrix; import android.view.Surface; import android.view.TextureView; import java.io.IOException; public class MainActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener { private TextureView videoView1; private TextureView videoView2; private MediaPlayer mediaPlayer1; private MediaPlayer mediaPlayer2; private final String videoPath = "android.resource://" + getPackageName() + "/" + R.raw.patila; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); videoView1 = findViewById(R.id.video_view_1); videoView2 = findViewById(R.id.video_view_2); // 设置SurfaceTexture监听 videoView1.setSurfaceTextureListener(this); videoView2.setSurfaceTextureListener(this); } @Override public void onSurfaceTextureAvailable(TextureView surface, int width, int height) { // 根据TextureView的ID初始化对应MediaPlayer if (surface.getId() == R.id.video_view_1) { initMediaPlayer(mediaPlayer1, surface); } else if (surface.getId() == R.id.video_view_2) { initMediaPlayer(mediaPlayer2, surface); } } @Override public void onSurfaceTextureSizeChanged(TextureView surface, int width, int height) { // 视图尺寸变化时重新调整裁剪 adjustVideoCrop(surface); } @Override public boolean onSurfaceTextureDestroyed(TextureView surface) { // 释放对应MediaPlayer资源 if (surface.getId() == R.id.video_view_1) { releaseMediaPlayer(mediaPlayer1); } else if (surface.getId() == R.id.video_view_2) { releaseMediaPlayer(mediaPlayer2); } return true; } @Override public void onSurfaceTextureUpdated(TextureView surface) { // 视频帧更新回调,无需额外处理 } // 初始化MediaPlayer的通用方法 private void initMediaPlayer(MediaPlayer player, TextureView textureView) { if (player != null) { player.release(); } player = new MediaPlayer(); try { player.setDataSource(videoPath); player.setSurface(new Surface(textureView.getSurfaceTexture())); player.setOnPreparedListener(mp -> { mp.start(); // 视频准备完成后设置裁剪 adjustVideoCrop(textureView); }); player.prepareAsync(); } catch (IOException e) { e.printStackTrace(); } // 更新引用 if (textureView.getId() == R.id.video_view_1) { mediaPlayer1 = player; } else { mediaPlayer2 = player; } } // 释放MediaPlayer资源 private void releaseMediaPlayer(MediaPlayer player) { if (player != null) { player.stop(); player.release(); } } @Override protected void onDestroy() { super.onDestroy(); releaseMediaPlayer(mediaPlayer1); releaseMediaPlayer(mediaPlayer2); } }
二、多视频裁剪实现
TextureView的裁剪通过设置变换矩阵实现,你可以自定义裁剪区域(比如只显示视频的左半部分、上半部分),或者调整显示比例。
示例:裁剪视频的上半部分
在adjustVideoCrop方法中添加矩阵变换逻辑:
private void adjustVideoCrop(TextureView textureView) { MediaPlayer player = textureView.getId() == R.id.video_view_1 ? mediaPlayer1 : mediaPlayer2; if (player == null || !player.isPlaying()) return; int videoWidth = player.getVideoWidth(); int videoHeight = player.getVideoHeight(); int viewWidth = textureView.getWidth(); int viewHeight = textureView.getHeight(); Matrix matrix = new Matrix(); // 缩放高度为2倍,再向上平移半个视图高度,实现只显示上半部分 float scaleY = 2f; matrix.setScale(1f, scaleY); matrix.postTranslate(0, -viewHeight / 2f); textureView.setTransform(matrix); }
其他裁剪场景
- 裁剪左半部分:设置
scaleX=2f,postTranslate(-viewWidth/2f, 0) - 自定义矩形区域:通过组合缩放、平移矩阵实现任意区域裁剪
- 比例适配裁剪:先计算视频与视图的比例,调整矩阵避免画面拉伸
注意事项
- 每个MediaPlayer对应一个TextureView,避免资源冲突
- 务必在
onSurfaceTextureDestroyed和onDestroy中释放MediaPlayer,防止内存泄漏 - 该裁剪是视图层的显示变换,不会修改原视频文件
内容的提问来源于stack exchange,提问作者ashwyll solutions
相关产品推荐
相关产品推荐

