如何实现视频画面大小与比例的
ijkplayer 支持软解硬解播放
- 软解是用OpenGL ES / NDK ANativeWindow 进行渲染播放
- 硬解是用MediaCodec configure Surface 直接渲染到 Surface
无论是OpenGL ES 还是 ANativeWindow 都能随意处理图像,MediaCodec 也提提供了setVideoScalingMode(int mode) 这个接口。而ijkplayer 内部实现没有运用上面的机制来渲染图片以用来调整画面大小与比例。
相关概念
1、Surface 理解为引用了一块内存缓冲区(也可以称画布),程序可以间接控制这个画布的大小,就是像素的长与宽,系统底层也会按照设置的format申请合适的缓冲区大小。
2、SurfaceHolder.Callback surfaceChanged 回调的width、height 并不是View 的大小 这一点一定要注意,官方文档描述的非常清楚。它是SurfaceView 对应的Surface 的大小 ,只不过第一次创建Surface 大小默认值等于SurfaceView 的大小,参考 setSizeFromLayout()。
3、onMeasure 函数用来决定View大小的
void [onMeasure](https://developer.android.com/reference/android/view/View.html#onMeasure(int, int)) (int widthMeasureSpec, int heightMeasureSpec)
4、视频分辨率、屏幕分辨率
参考 百度百科 视频分辨率 屏幕分辨率
5、视频旋转角度,有的视频流中是自带旋转角度信息的,比如:Android Camera 拍摄的横屏、竖屏视频的分辨率都一样的。不过竖屏拍的视频流有元数据角度信息 90。
6、屏幕旋转角度就是我们熟知的手机物理旋转角度
7、画面播放比例 Display Aspect Ratio 有常见的下列:
* 16:9/fit_parent
* 4:3/fit_parent
* wrapContent
* aspect_fit_parent
* fill_parent
实现画面大小与比例
ijkplayer 在下面的函数中设置画面大小与比例
public void doMeasure(int widthMeasureSpec, int heightMeasureSpec)
仅仅设置好了View的大小就能搞定所有的一切?这里就简单描述一下背后的原理以及为何这样做就可以了。这样Android 播放器UI 定制就非常清楚了。
1、绘制视频帧
OpenGL ES、NDK ANativeWindow 、MediaCodec 这些实现过程中都没有做裁剪、放大、缩放、旋转操作,无论提供多大画布(Surface width/height)都绘制到整个画布上面。不过绘制的时候处理了视频旋转角度信息,就是width/height 互换。SurfaceFlinger 合成Surface 到屏幕上的时候自动会根据对应的View大小进行Scale 操作。
2、视频播放的比例 Display Aspect Ratio
只要设置好SurfaceView View的位置与大小,视频将按照View 的位置与大小显示。代码可以参见 doMeasure
3、屏幕旋转角度的变化只是改变了View 的宽/高, doMeasure会重现计算View新的大小
4、屏幕分辨率不影响,因为SurfaceFlinger 最后会自动 Scale 到屏幕硬解缓冲区
然很多博客介绍ijkplayer 视频播放比例大小选择的时候都是不太严谨的。不是视频在View 上裁剪、缩放操作,而是视频渲染到整个View 区域。我们变化View 来适配画面播放比例。
下面是HLS流 (480 * 270)实时切换画面比例情况下,打印 输出 SurfaceRenderView 的 onSizeChanged 事件,大家可以试一试。不过注意不要打印输出IjkVideoView 这个View的变化了。