Android TV使用gsyVideoPlayer快进操作视频会回退

1. 背景

    今天TV产品优化,发现一个难以修改的问题,使用gsyVideoPlayer的时候,切换的是系统内核播放视频,然后遥控器在控制快进快退的时候会有进度条回退的问题,这对用户就不友好了啊。

2. 原因探究

    调查了之后发现,是因为关键帧的问题,快进的时候是按照视频的关键帧来进行快进的,如果视频背压缩的过于严重会导致视频的关键帧比较少,那么就会出现以下这种情况:

现在播放到8秒,你要快进到18秒,但是视频的关键帧在第15秒,那么进度条就会从18退到15,因为进度条是按照真实的视频进度来进行走动的。

3. 解决方案

    知道了原因之后那么有两种方案:

    方案一:从系统内核切换到Exo内核,因为我发现三种内核都测试过之后,Exo内核对于关键帧的处理更好,基本上不会出现快进回退的问题。

    方案二:维持原有的系统内核,禁用gsyVideoPlayer原有的进度条展示,自己实现进度条,时间的展示。

4. 实现

4.1 方案一测试(失败)

    采用了之后播放.mp4视频一点问题没有,非常流畅,实现了我想要的效果,但是现网的视频后缀是.m3u8格式的,使用Exo内核播放之后,报了如下错误:

05-18 11:26:07.632: E/ExoPlayerImplInternal(10506): Source error.
05-18 11:26:07.632: E/ExoPlayerImplInternal(10506): com.google.android.exoplayer2.source.UnrecognizedInputFormatException: None of the available extractors (MatroskaExtractor, FragmentedMp4Extractor, Mp4Extractor, Mp3Extractor, AdtsExtractor, Ac3Extractor, TsExtractor, FlvExtractor, OggExtractor, PsExtractor, WavExtractor, AmrExtractor) could read the stream.
05-18 11:26:07.632: E/ExoPlayerImplInternal(10506): 	at com.google.android.exoplayer2.source.ExtractorMediaPeriod$ExtractorHolder.selectExtractor(ExtractorMediaPeriod.java:927)
05-18 11:26:07.632: E/ExoPlayerImplInternal(10506): 	at com.google.android.exoplayer2.source.ExtractorMediaPeriod$ExtractingLoadable.load(ExtractorMediaPeriod.java:849)
05-18 11:26:07.632: E/ExoPlayerImplInternal(10506): 	at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:320)
05-18 11:26:07.632: E/ExoPlayerImplInternal(10506): 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
05-18 11:26:07.632: E/ExoPlayerImplInternal(10506): 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
05-18 11:26:07.632: E/ExoPlayerImplInternal(10506): 	at java.lang.Thread.run(Thread.java:841)
05-18 11:26:07.632: E/EventLogger(10506): playerFailed [0.78]
05-18 11:26:07.632: E/EventLogger(10506): com.google.android.exoplayer2.ExoPlaybackException
05-18 11:26:07.632: E/EventLogger(10506): 	at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:349)
05-18 11:26:07.632: E/EventLogger(10506): 	at android.os.Handler.dispatchMessage(Handler.java:98)
05-18 11:26:07.632: E/EventLogger(10506): 	at android.os.Looper.loop(Looper.java:136)
05-18 11:26:07.632: E/EventLogger(10506): 	at android.os.HandlerThread.run(HandlerThread.java:61)
05-18 11:26:07.632: E/EventLogger(10506): Caused by: com.google.android.exoplayer2.source.UnrecognizedInputFormatException: None of the available extractors (MatroskaExtractor, FragmentedMp4Extractor, Mp4Extractor, Mp3Extractor, AdtsExtractor, Ac3Extractor, TsExtractor, FlvExtractor, OggExtractor, PsExtractor, WavExtractor, AmrExtractor) could read the stream.
05-18 11:26:07.632: E/EventLogger(10506): 	at com.google.android.exoplayer2.source.ExtractorMediaPeriod$ExtractorHolder.selectExtractor(ExtractorMediaPeriod.java:927)
05-18 11:26:07.632: E/EventLogger(10506): 	at com.google.android.exoplayer2.source.ExtractorMediaPeriod$ExtractingLoadable.load(ExtractorMediaPeriod.java:849)
05-18 11:26:07.632: E/EventLogger(10506): 	at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:320)
05-18 11:26:07.632: E/EventLogger(10506): 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
05-18 11:26:07.632: E/EventLogger(10506): 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
05-18 11:26:07.632: E/EventLogger(10506): 	at java.lang.Thread.run(Thread.java:841)
05-18 11:26:07.632: D/EventLogger(10506): loading [false]

    这个报错看了半天,主要意思是说Exoplayer中没有可用的解析器,然后我去找了解决办法,说是需要设置如下代码:

//EXOPlayer内核,支持格式更多
PlayerFactory.setPlayManager(Exo2PlayerManager.class);


//exo缓存模式,支持m3u8,只支持exo
CacheFactory.setCacheManager(ExoPlayerCacheManager.class);

    试了并不行,不知道是我的问题还是播放器的问题,最后也没找到解决办法,直接放弃。

4.2 方案二测试(可行)

    首选我继承StandardGSYVideoPlayer创建了一个新的Player,然后重写其中的 setTextAndProgress方法,将super.setTextAndProgress(secProgress);方法注释掉即可,运行发现进度条不走,当前时间跟总时间一直在00:00.,然后只需要自己写一个计时器,让进度条每隔1s刷新一次将当前时间跟进度更新掉就好。写到这我就在想另外一个问题,它本身已经写了一个计时器了在更新进度了,我在写一个控制岂不是多余了嘛?本着不重复造轮子的态度,我进行了如下改动:

 /**
     * 处理快进快退问题
     * @param isForward
     */
    public void step(boolean isForward) {
        if (!getGSYVideoManager().isPlaying()) {
            PLog.i("fastForward is not playing");
            getStartButton().callOnClick();
        }
        int videoLength = (int) getGSYVideoManager().getDuration();

        if (videoLength == -1) {
            return;
        }

        int size = videoLength / LENGTH;// LENGTH快进快退的步长

        final int[] postion = new int[size + 2];
        postion[size + 1] = videoLength;

        for (int i = 0; i <= size; i++) {
            postion[i] = LENGTH * i;
        }

        mBottomContainer.setVisibility(VISIBLE);

        if (isForward) { // 快进

            if (mCurrentPosition == videoLength) {
                setProgress(videoLength, videoLength);
                return;
            }

            for (int i = 0; i < postion.length; i++) {
                if (postion[i] - mCurrentPosition > 0) {
                    PLog.i("forwart postion=" + postion[i]);
                    setProgress(postion[i], videoLength);
                    getGSYVideoManager().seekTo(mCurrentPosition);
                    break;
                }
            }
        } else { // 快退

            if (mCurrentPosition == 0) {
                setProgress(0, videoLength);
                return;
            }

            for (int i = 0; i < postion.length; i++) {
                if (postion[i] - mCurrentPosition >= 0) {
                    setProgress(postion[i - 1], videoLength);
                    getGSYVideoManager().seekTo(mCurrentPosition);
                    break;
                }
            }
        }
    }

    /**
     * 快进快退 自己控制 进度条 避免快进 回退问题
     *
     * @param position
     * @param videoLength
     */
    public void setProgress(int position, int videoLength) {
        mCurrentPosition = position;
        int progress = (int) (mCurrentPosition / (videoLength / 100));
        mProgressBar.setProgress(progress);
        mTotalTimeTextView.setText(CommonUtil.stringForTime(videoLength));
        mCurrentTimeTextView.setText(CommonUtil.stringForTime(position));

        mHadler.postDelayed(new Runnable() {
            @Override
            public void run() {
                mBottomContainer.setVisibility(GONE);
            }
        }, 500);
    }

    @Override
    protected void setTextAndProgress(int secProgress) { // 避免关键帧 回退的问题
        if (!mProgressBar.isShown()) {
            super.setTextAndProgress(secProgress);
        }
    }

   我做了一个假象,在进度条展示的时候,我会按照自己分割的关键帧去快进快退,这样控制强行让进度条永远按照你想要的方向走,但是当500ms进度条消失之后,我让进度条按照gsyVideoPlayer原有的计时器进行更新,这样我不仅省了一个计时器并且实现了了想要的效果,进度条在显示的时候永远不会回退,消失之后可能会有稍微回退,但是用户看不到了,问题应该不大。

5. 总结

    最后还是希望不要将视频压缩的太过严重,关键帧太少,视频清晰度降低,对用户的体验更不好,在用户能看到的地方一定要将体验做好,可以在看不到的地方做优化,本次优化主要针对于遥控器控制的快进快退,手机开发的小伙伴可以借鉴下思路。

6. 参考

    1. https://blog.csdn.net/yhroppo/article/details/104494850

    2. github地址 :https://github.com/CarGuo/GSYVideoPlayer 

    3. https://github.com/CarGuo/GSYVideoPlayer/issues/1302

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值