ExoPlayer实现截图功能和设置画面比例功能

来源:互联网 发布:网络统考英语过不去 编辑:程序博客网 时间:2024/05/17 03:08

最近公司项目里又在做播放器相关的功能了,本次鄙人收获的是截图功能和设置画面比例的功能。

截图功能

首先说说截图功能吧,一开始想到的是截取视频某一帧的画面,可是这么做并不能实现实时截图的效果。后来网上看到一个仿bilibli的开源播放器IjkPlayerView,大家应该都有所耳闻吧,话说这个例子写的还真不错,简单使用,于是我参考这个例子的源码终于找到了方法,其实本身TextureView已经给我们提供一个方法:public Bitmap getBitmap();这个方法就可以获取视频画面截图了。

getBitmap()
Returns a Bitmap representation of the content of the associated surface texture.
The bitmap returned by this method uses the ARGB_8888 pixel format and its dimensions are the same as this view’s.
意思是这个方法将返回一个和播放器view大小相同的一个位图。

最近还没有研究TextureView的源码和使用方法,这里先给大家放一篇入门教程TextureView简易教程,大致了解下TextureView的用法,后续我会再放一个详细的讲解博文。

最后放上踩坑历程,跟这个大兄弟的经历差不多,大家可以参考下,留个心眼。Android播放网络视频截图

设置视频画面比例

之前用的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~

原创粉丝点击