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

效果展示
旋转前的显示:

如何使用rotation-degrees手动旋转(rotate)exoplayer2播放器
文章图片
image.png 旋转处理后的效果:

如何使用rotation-degrees手动旋转(rotate)exoplayer2播放器
文章图片
image.png 如何实现
方法一. 最直接的想法是进行横竖屏切换. Activity变成横屏显示了, 视频播放自然也就全屏了. 没什么可细说的.
这个做法也有缺点: 有些情况下某些页面不允许进行横竖屏切换, 或者横竖屏切换后, 仍然要保持其他显示元素与竖屏时一样. 我们现在这个产品的需求就是这么要求的. 那就需要另想办法了.
方法二. 旋转view控件. 对于exoplayer2 来说支持surface view 和texture view两种显示. surface view基本就没办法旋转了.
官方的issue里有这方面的讨论, 及示例做法:
https://github.com/google/ExoPlayer/issues/3843
然后这个办法最后呈现出来的效果, 却不是我想要的. 简单的旋转view之后, 效果是这样的:

如何使用rotation-degrees手动旋转(rotate)exoplayer2播放器
文章图片
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) ....

【如何使用rotation-degrees手动旋转(rotate)exoplayer2播放器】这个方法有个缺点, 只支持5.0之后的版本, 因为这个参数rotation-degrees只在5.0之后支持
代码示例
马上就来

    推荐阅读