美文网首页
如何使用rotation-degrees手动旋转(rotate)

如何使用rotation-degrees手动旋转(rotate)

作者: vb12 | 来源:发表于2018-08-31 15:01 被阅读176次

    效果展示

    旋转前的显示:


    image.png

    旋转处理后的效果:


    image.png

    如何实现

    方法一. 最直接的想法是进行横竖屏切换.

    Activity变成横屏显示了, 视频播放自然也就全屏了. 没什么可细说的.
    这个做法也有缺点: 有些情况下某些页面不允许进行横竖屏切换, 或者横竖屏切换后, 仍然要保持其他显示元素与竖屏时一样. 我们现在这个产品的需求就是这么要求的. 那就需要另想办法了.

    方法二. 旋转view控件.

    对于exoplayer2 来说支持surface view 和texture view两种显示. surface view基本就没办法旋转了.
    官方的issue里有这方面的讨论, 及示例做法:
    https://github.com/google/ExoPlayer/issues/3843
    然后这个办法最后呈现出来的效果, 却不是我想要的. 简单的旋转view之后, 效果是这样的:

    image.png

    方法三. 定制MediaCodecVideoRenderer, 设置rotation-degrees参数

    目前我们产品用的exoplayer2的版本是2.6.1 对于最新版本的2.8.3, 做法稍有不同, 但是同样的思路都能实现.
    具体来说就是扩展默认的MediaCodecVideoRenderer和DefaultRenderersFactory

    先是自定义SogoDefaultRenderersFactory 扩展DefaultRenderersFactory , 从而能够返回我们自定义的MediaCodecVideoRenderer类实例

    public class SogoDefaultRenderersFactory extends DefaultRenderersFactory {
    
        public SogoDefaultRenderersFactory(Context context) {
            super(context);
        }
    
        public SogoDefaultRenderersFactory(Context context, @Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager) {
            super(context, drmSessionManager);
        }
    
        public SogoDefaultRenderersFactory(Context context, @Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager, int extensionRendererMode) {
            super(context, drmSessionManager, extensionRendererMode);
        }
    
        public SogoDefaultRenderersFactory(Context context, @Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager, int extensionRendererMode, long allowedVideoJoiningTimeMs) {
            super(context, drmSessionManager, extensionRendererMode, allowedVideoJoiningTimeMs);
        }
    
    
        @Override
        protected void buildVideoRenderers(Context context, @Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager, long allowedVideoJoiningTimeMs, Handler eventHandler, VideoRendererEventListener eventListener, int extensionRendererMode, ArrayList<Renderer> out) {
            super.buildVideoRenderers(context, drmSessionManager, allowedVideoJoiningTimeMs, eventHandler, eventListener, extensionRendererMode, out);
            for (int i = out.size() - 1; i >= 0; i--) {
                Renderer renderer = out.get(i);
                if (renderer instanceof MediaCodecVideoRenderer) {
                    out.remove(renderer);
                    out.add(i, new SogoMediaCodecVideoRenderer(context, MediaCodecSelector.DEFAULT,
                            allowedVideoJoiningTimeMs, drmSessionManager, false, eventHandler, eventListener,
                            MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY));
                }
            }
        }
    }
    

    下面是自定义扩展MediaCodecVideoRenderer类: 在getMediaFormat中对生成的MediaFormat 设置旋转角度. 这里是90度.

    ublic class SogoMediaCodecVideoRenderer extends MediaCodecVideoRenderer {
        public SogoMediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector) {
            super(context, mediaCodecSelector);
        }
    
        public SogoMediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector, long allowedJoiningTimeMs) {
            super(context, mediaCodecSelector, allowedJoiningTimeMs);
        }
    
        public SogoMediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector, long allowedJoiningTimeMs, @Nullable Handler eventHandler, @Nullable VideoRendererEventListener eventListener, int maxDroppedFrameCountToNotify) {
            super(context, mediaCodecSelector, allowedJoiningTimeMs, eventHandler, eventListener, maxDroppedFrameCountToNotify);
        }
    
        public SogoMediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector, long allowedJoiningTimeMs, @Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager, boolean playClearSamplesWithoutKeys, @Nullable Handler eventHandler, @Nullable VideoRendererEventListener eventListener, int maxDroppedFramesToNotify) {
            super(context, mediaCodecSelector, allowedJoiningTimeMs, drmSessionManager, playClearSamplesWithoutKeys, eventHandler, eventListener, maxDroppedFramesToNotify);
        }
    
        @Override
        protected MediaFormat getMediaFormat(Format format, CodecMaxValues codecMaxValues, boolean deviceNeedsAutoFrcWorkaround, int tunnelingAudioSessionId) {
            MediaFormat mediaFormat = super.getMediaFormat(format, codecMaxValues, deviceNeedsAutoFrcWorkaround, tunnelingAudioSessionId);
            mediaFormat.setInteger("rotation-degrees", 90);
            return mediaFormat;
        }
    }
    

    对于竖屏比例视频和横屏比例视频混杂的情况下, 怎么才能判断当前是横屏视频呢?
    -- 可以通过为exoplayer设置VideoListener, 来监听视频流的宽高比. 具体接口实现:

    public interface VideoListener {
    
        .............
        void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
            float pixelWidthHeightRatio);
    ....
      }
    

    通过width和heigh参数可知视频流的宽高.
    当发现是横屏视频流之后, 我的做法是马上重建了一个exoplayer播放器, 并在创建这个新的播放器时,使用上面定义的两个扩展类.

    .....
     var player = ExoPlayerFactory.newSimpleInstance(SogoDefaultRenderersFactory(application),
                mTrackSelector)
    ....
    

    这个方法有个缺点, 只支持5.0之后的版本, 因为这个参数rotation-degrees只在5.0之后支持

    代码示例

    马上就来

    相关文章

      网友评论

          本文标题:如何使用rotation-degrees手动旋转(rotate)

          本文链接:https://www.haomeiwen.com/subject/whiswftx.html