效果展示
旋转前的显示:
旋转处理后的效果:
如何实现
方法一. 最直接的想法是进行横竖屏切换.
Activity变成横屏显示了, 视频播放自然也就全屏了. 没什么可细说的.
这个做法也有缺点: 有些情况下某些页面不允许进行横竖屏切换, 或者横竖屏切换后, 仍然要保持其他显示元素与竖屏时一样. 我们现在这个产品的需求就是这么要求的. 那就需要另想办法了.
方法二. 旋转view控件.
对于exoplayer2 来说支持surface view 和texture view两种显示. surface view基本就没办法旋转了.
官方的issue里有这方面的讨论, 及示例做法:
https://github.com/google/ExoPlayer/issues/3843
然后这个办法最后呈现出来的效果, 却不是我想要的. 简单的旋转view之后, 效果是这样的:
方法三. 定制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之后支持
代码示例
马上就来