如何使用rotation-degrees手动旋转(rotate)exoplayer2播放器

效果展示

旋转前的显示:


如何使用rotation-degrees手动旋转(rotate)exoplayer2播放器_第1张图片
image.png

旋转处理后的效果:


如何使用rotation-degrees手动旋转(rotate)exoplayer2播放器_第2张图片
image.png

如何实现

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

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

方法二. 旋转view控件.

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

如何使用rotation-degrees手动旋转(rotate)exoplayer2播放器_第3张图片
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 drmSessionManager) {
        super(context, drmSessionManager);
    }

    public SogoDefaultRenderersFactory(Context context, @Nullable DrmSessionManager drmSessionManager, int extensionRendererMode) {
        super(context, drmSessionManager, extensionRendererMode);
    }

    public SogoDefaultRenderersFactory(Context context, @Nullable DrmSessionManager drmSessionManager, int extensionRendererMode, long allowedVideoJoiningTimeMs) {
        super(context, drmSessionManager, extensionRendererMode, allowedVideoJoiningTimeMs);
    }


    @Override
    protected void buildVideoRenderers(Context context, @Nullable DrmSessionManager drmSessionManager, long allowedVideoJoiningTimeMs, Handler eventHandler, VideoRendererEventListener eventListener, int extensionRendererMode, ArrayList 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 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)exoplayer2播放器)