设置视频画面比例

之前用的EXOplayer1.0版本的,是GitHub上面别人修改过的一个开源demo,里面直接就集成了画面比例的方法,叫做setScaleType,最近播放器要升级发现原来Exoplayer1.0版本的setScaleType方法对于EXOplayer2.0并不适用后来参考IjkPlayerView的方法,找到了一个叫做setMeasuredDimension()的方法,这个方法相信大家并不陌生哦。这里做下简单介绍吧:setMeasuredDimension(width,height)接受width和height两个参数用于设置当前view的大小。其实说白了设置视频画面比例不就是重新设置view的大小吗?对吧。下面直接贴上设置画面比例的逻辑吧,核心就是如何计算view的宽和高,完了就调用上面的setMeasuredDimension(width,height)方法设置一下即可。

详细讲解参考博客:
Android自定义视图(一)——onMeasure,MeasureSpec源码 流程 思路详解

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Log.i(TAG, "onMeasure " + " [" + this.hashCode() + "] ");
        int mVideoRotationDegree = (int) getRotation();
        int mVideoWidth = mVideoSize.x;
        int mVideoHeight = mVideoSize.y;
        Log.i(TAG, "videoWidth = " + mVideoWidth + ", videoHeight = " + mVideoHeight + ", " +
                "viewRotation = " + mVideoRotationDegree);

        // 如果旋转了90°或270°则宽高测量值进行互换
        if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) {
            int tempMeasureSpec = widthMeasureSpec;
            widthMeasureSpec = heightMeasureSpec;
            heightMeasureSpec = tempMeasureSpec;
        }

        // 获取默认的测量宽高值
        int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
        int height = getDefaultSize(mVideoHeight, heightMeasureSpec);

        if (mCurrentAspectRatio == AR_MATCH_PARENT) {
            // 在 AR_MATCH_PARENT 模式下直接用原始测量值
            width = widthMeasureSpec;
            height = heightMeasureSpec;
        } else if (mVideoWidth > 0 && mVideoHeight > 0) {
            int widthSpecMode = View.MeasureSpec.getMode(widthMeasureSpec);
            int widthSpecSize = View.MeasureSpec.getSize(widthMeasureSpec);
            int heightSpecMode = View.MeasureSpec.getMode(heightMeasureSpec);
            int heightSpecSize = View.MeasureSpec.getSize(heightMeasureSpec);
            // modify,把&&操作符换为||
            if (widthSpecMode == View.MeasureSpec.AT_MOST || heightSpecMode == View.MeasureSpec
                    .AT_MOST) {
                // 测量宽高比,对应的视图的宽高比
                float specAspectRatio = (float) widthSpecSize / (float) heightSpecSize;
                // 显示宽高比,要显示的视频宽高比
                float displayAspectRatio;
                // 这里计算显示宽高比
                switch (mCurrentAspectRatio) {
                    case AR_16_9_FIT_PARENT:
                        // 16:9
                        displayAspectRatio = 16.0f / 9.0f;
                        if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270)
                            displayAspectRatio = 1.0f / displayAspectRatio;
                        break;
                    case AR_4_3_FIT_PARENT:
                        // 4:3
                        displayAspectRatio = 4.0f / 3.0f;
                        if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270)
                            displayAspectRatio = 1.0f / displayAspectRatio;
                        break;
                    case AR_ASPECT_FIT_PARENT:
                    case AR_ASPECT_FILL_PARENT:
                    case AR_ASPECT_WRAP_CONTENT:
                    default:
                        // 按视频来源宽高比
                        displayAspectRatio = (float) mVideoWidth / (float) mVideoHeight;
//                        if (mVideoSarNum > 0 && mVideoSarDen > 0)
//                            displayAspectRatio = displayAspectRatio * mVideoSarNum / mVideoSarDen;
                        break;
                }
                // 是否要显示视频宽度比例较大
                boolean shouldBeWider = displayAspectRatio > specAspectRatio;
                // 这里确定最终宽高
                switch (mCurrentAspectRatio) {
                    case AR_ASPECT_FIT_PARENT:
                    case AR_16_9_FIT_PARENT:
                    case AR_4_3_FIT_PARENT:
                        if (shouldBeWider) {
                            // too wide, fix width;宽度比较大,固定宽度,使用测量宽度,按显示比例缩放高度
                            width = widthSpecSize;
                            height = (int) (width / displayAspectRatio);
                        } else {
                            // too high, fix height;高度比较大,固定高度,使用测量高度,按显示比例缩放宽度
                            height = heightSpecSize;
                            width = (int) (height * displayAspectRatio);
                        }
                        break;
                    case AR_ASPECT_FILL_PARENT: // 填充满控件模式
                        if (shouldBeWider) {
                            // not high enough, fix height;宽度比较大,固定高度,缩放宽度
                            height = heightSpecSize;
                            width = (int) (height * displayAspectRatio);
                        } else {
                            // not wide enough, fix width;高度比较大,固定宽度,缩放高度
                            width = widthSpecSize;
                            height = (int) (width / displayAspectRatio);
                        }
                        break;
                    case AR_ASPECT_WRAP_CONTENT:
                    default:
                        if (shouldBeWider) {
                            // too wide, fix width;和第一个类似,这里取 (mVideoWidth, widthSpecSize) 最小的值
                            width = Math.min(mVideoWidth, widthSpecSize);
                            height = (int) (width / displayAspectRatio);
                        } else {
                            // too high, fix height
                            height = Math.min(mVideoHeight, heightSpecSize);
                            width = (int) (height * displayAspectRatio);
                        }
                        break;
                }
            } else if (widthSpecMode == View.MeasureSpec.EXACTLY && heightSpecMode == View
                    .MeasureSpec.EXACTLY) {
                // the size is fixed
                width = widthSpecSize;
                height = heightSpecSize;

                // for compatibility, we adjust size based on aspect ratio
                // 这里做的是缩小某一边的大小以达到和视频原始尺寸的比例
                if (mVideoWidth * height < width * mVideoHeight) {
                    width = height * mVideoWidth / mVideoHeight;
                } else if (mVideoWidth * height > width * mVideoHeight) {
                    height = width * mVideoHeight / mVideoWidth;
                }
            } else if (widthSpecMode == View.MeasureSpec.EXACTLY) {
                // only the width is fixed, adjust the height to match aspect ratio if possible
                width = widthSpecSize;
                height = width * mVideoHeight / mVideoWidth;
                if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) {
                    // couldn't match aspect ratio within the constraints,不让高度超出测量高度
                    height = heightSpecSize;
                }
            } else if (heightSpecMode == View.MeasureSpec.EXACTLY) {
                // only the height is fixed, adjust the width to match aspect ratio if possible
                height = heightSpecSize;
                width = height * mVideoWidth / mVideoHeight;
                if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) {
                    // couldn't match aspect ratio within the constraints,不让宽度超出测量宽度
                    width = widthSpecSize;
                }
            } else {
                // neither the width nor the height are fixed, try to use actual video size
                width = mVideoWidth;
                height = mVideoHeight;
                if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) {
                    // too tall, decrease both width and height
                    height = heightSpecSize;
                    width = height * mVideoWidth / mVideoHeight;
                }
                if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) {
                    // too wide, decrease both width and height
                    width = widthSpecSize;
                    height = width * mVideoHeight / mVideoWidth;
                }
            }
        } else {
            // no size yet, just adopt the given spec sizes
        }

        setMeasuredDimension(width, height);
    }

好了,简单吧。下面我还是要强烈安利一下——IjkPlayerView
目前集成的主要功能:

沉浸式全屏播放,隐藏状态栏和虚拟键如果有的话,用的时候有些需要注意的地方放后面说;
弹幕功能,包括发射弹幕和弹幕基本样式设置:大小、颜色和类型(顶部、底部和滚动弹幕),效果同Bilibili;
竖屏和横屏的切换,其实就是小屏和全屏的切换,提供了重力感应来切换竖横屏功能;
触屏控制,竖直方向左边控制亮度,右边控制声音,水平方向控制播放进度;
三指旋转缩放,当三个手指触屏时就可以进行视频界面的旋转缩放,效果同Bilibili;
视频源切换,可设置流畅、清晰、高清、超清和1080p等5种视频源;
视频宽高比例设置,包括16:9、4:3、视频内嵌填充界面和填充屏幕等4种;
记录上次播放进度的跳转功能;
其它的如截屏功能,电池电量显示,时间显示,播放常亮,跑马灯标题和锁屏处理;

怎么样?还是很全面的吧,应该就差个gif动图截取的功能了,有兴趣的好好学习下吧,O(∩_∩)O~

GitHub 加速计划 / ex / ExoPlayer
0
1
下载
最近提交(Master分支:4 个月前 )
dd430f70 - 4 个月前
c00f90aa (cherry picked from commit 5b2b7f4e6147678dc56ce28826682ba21c4c9508) 6 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐