音视频直播技术–视频画中画
- 2020 年 4 月 2 日
- 筆記

多视频
前言
大家好,今天我为大家介绍一下如何在Android系统下实现实时直播互动中的多视频展示功能。 我们现在都清楚实时直播互动中多路视频的展示是目前比较流行的趋势,因为大家都想看到更多视频画面的需求,是非常符合人类的习惯的。
大家都知道,在Android系统下显示视频主要有三种View,分别是SurfaceView、GLSurfaceView及TextureView。它们的区别大家可以看我的另一篇文章 视频的渲染与展示 一文的介绍。我们今天这个例子是通过 SurfaceView来给大家演示的。
基本流程
在这个项目中使用了两个SurfaceView,一个SurfaceView作为Camera摄像头预览View,另一个SurfaceView用于Player View。Camera preview的大小与屏幕大小相同,并把它作为背景,而Player View是一个小窗口,它浮在 Camera preview的上面,用户可以在屏幕内任意的拖动它。
注意,之所以我们在这个项目中使用 SurfaceView,主要是因为SurfaceView更为灵活,便于我们更好的控制它。当然它同时带来的缺点是,与其它View相比开发变得比较复杂。
技术实现
在资源文件中定义两个 SurfaceView
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/main" tools:context="com.daka.live.multisurfaceview.MainActivity"> <SurfaceView android:id="@+id/surfaceview1" android:layout_width="match_parent" android:layout_height="match_parent" /> <SurfaceView android:id="@+id/surfaceview2" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
生成SurfaceView对象并设置属性
我们在生成Player View时,要设置它的大小,位置及在顶层展示,否则它会被Camera preview覆盖掉。
...... mSurfaceView1 = (SurfaceView)findViewById(R.id.surfaceview1); RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(320, 240); // set size params.setMargins(100, 50, 0, 0); // set position mSurfaceView2 = (SurfaceView)findViewById(R.id.surfaceview2); mSurfaceView2.setLayoutParams(params); //设置view大小 mSurfaceView2.setOnTouchListener(this); //用于拖动 sh = mSurfaceView2.getHolder(); sh.addCallback(this); sh.setFormat(PixelFormat.TRANSLUCENT); mSurfaceView2.setZOrderMediaOverlay(true); mSurfaceView2.setZOrderOnTop(true); //设置在最顶层展示 ......
实现OnTouch接口
- 添加 View.OnTouchListener 实现
public class MainActivity extends Activity implements View.OnTouchListener { }
- 实现 onTouch 方法
public boolean onTouch(View view, MotionEvent event) { final int X = (int) event.getRawX(); final int Y = (int) event.getRawY(); switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams(); mXDelta = X - lParams.leftMargin; mYDelta = Y - lParams.topMargin; break; case MotionEvent.ACTION_UP: break; case MotionEvent.ACTION_POINTER_DOWN: break; case MotionEvent.ACTION_POINTER_UP: break; case MotionEvent.ACTION_MOVE: RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams(); layoutParams.leftMargin = X - mXDelta; layoutParams.topMargin = Y - mYDelta; layoutParams.rightMargin = -250; layoutParams.bottomMargin = -250; view.setLayoutParams(layoutParams); break; } mRoot.invalidate(); return true; }
完整例子
多视频展示代码下载地址:https://github.com/garrylea/MultiSurfaceView