如何使用rotation-degrees手動(dòng)旋轉(zhuǎn)(rotate)exoplayer2播放器

效果展示

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


image.png

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


image.png

如何實(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之后, 效果是這樣的:

image.png

方法三. 定制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)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容