效果展示
旋轉(zhuǎn)前的顯示:

旋轉(zhuǎn)處理后的效果:

如何實(shí)現(xiàn)
方法一. 最直接的想法是進(jìn)行橫豎屏切換.
Activity變成橫屏顯示了, 視頻播放自然也就全屏了. 沒(méi)什么可細(xì)說(shuō)的.
這個(gè)做法也有缺點(diǎn): 有些情況下某些頁(yè)面不允許進(jìn)行橫豎屏切換, 或者橫豎屏切換后, 仍然要保持其他顯示元素與豎屏?xí)r一樣. 我們現(xiàn)在這個(gè)產(chǎn)品的需求就是這么要求的. 那就需要另想辦法了.
方法二. 旋轉(zhuǎn)view控件.
對(duì)于exoplayer2 來(lái)說(shuō)支持surface view 和texture view兩種顯示. surface view基本就沒(méi)辦法旋轉(zhuǎn)了.
官方的issue里有這方面的討論, 及示例做法:
https://github.com/google/ExoPlayer/issues/3843
然后這個(gè)辦法最后呈現(xiàn)出來(lái)的效果, 卻不是我想要的. 簡(jiǎn)單的旋轉(zhuǎn)view之后, 效果是這樣的:

方法三. 定制MediaCodecVideoRenderer, 設(shè)置rotation-degrees參數(shù)
目前我們產(chǎn)品用的exoplayer2的版本是2.6.1 對(duì)于最新版本的2.8.3, 做法稍有不同, 但是同樣的思路都能實(shí)現(xiàn).
具體來(lái)說(shuō)就是擴(kuò)展默認(rèn)的MediaCodecVideoRenderer和DefaultRenderersFactory
先是自定義SogoDefaultRenderersFactory 擴(kuò)展DefaultRenderersFactory , 從而能夠返回我們自定義的MediaCodecVideoRenderer類實(shí)例
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));
}
}
}
}
下面是自定義擴(kuò)展MediaCodecVideoRenderer類: 在getMediaFormat中對(duì)生成的MediaFormat 設(shè)置旋轉(zhuǎn)角度. 這里是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;
}
}
對(duì)于豎屏比例視頻和橫屏比例視頻混雜的情況下, 怎么才能判斷當(dāng)前是橫屏視頻呢?
-- 可以通過(guò)為exoplayer設(shè)置VideoListener, 來(lái)監(jiān)聽(tīng)視頻流的寬高比. 具體接口實(shí)現(xiàn):
public interface VideoListener {
.............
void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
float pixelWidthHeightRatio);
....
}
通過(guò)width和heigh參數(shù)可知視頻流的寬高.
當(dāng)發(fā)現(xiàn)是橫屏視頻流之后, 我的做法是馬上重建了一個(gè)exoplayer播放器, 并在創(chuàng)建這個(gè)新的播放器時(shí),使用上面定義的兩個(gè)擴(kuò)展類.
.....
var player = ExoPlayerFactory.newSimpleInstance(SogoDefaultRenderersFactory(application),
mTrackSelector)
....
這個(gè)方法有個(gè)缺點(diǎn), 只支持5.0之后的版本, 因?yàn)檫@個(gè)參數(shù)rotation-degrees只在5.0之后支持
代碼示例
馬上就來(lái)