当前位置:   article > 正文

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

gsyvideoplayer tv版

1. 背景

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

2. 原因探究

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

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

3. 解决方案

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

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

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

4. 实现

4.1 方案一测试(失败)

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

  1. 05-18 11:26:07.632: E/ExoPlayerImplInternal(10506): Source error.
  2. 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.
  3. 05-18 11:26:07.632: E/ExoPlayerImplInternal(10506): at com.google.android.exoplayer2.source.ExtractorMediaPeriod$ExtractorHolder.selectExtractor(ExtractorMediaPeriod.java:927)
  4. 05-18 11:26:07.632: E/ExoPlayerImplInternal(10506): at com.google.android.exoplayer2.source.ExtractorMediaPeriod$ExtractingLoadable.load(ExtractorMediaPeriod.java:849)
  5. 05-18 11:26:07.632: E/ExoPlayerImplInternal(10506): at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:320)
  6. 05-18 11:26:07.632: E/ExoPlayerImplInternal(10506): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
  7. 05-18 11:26:07.632: E/ExoPlayerImplInternal(10506): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
  8. 05-18 11:26:07.632: E/ExoPlayerImplInternal(10506): at java.lang.Thread.run(Thread.java:841)
  9. 05-18 11:26:07.632: E/EventLogger(10506): playerFailed [0.78]
  10. 05-18 11:26:07.632: E/EventLogger(10506): com.google.android.exoplayer2.ExoPlaybackException
  11. 05-18 11:26:07.632: E/EventLogger(10506): at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:349)
  12. 05-18 11:26:07.632: E/EventLogger(10506): at android.os.Handler.dispatchMessage(Handler.java:98)
  13. 05-18 11:26:07.632: E/EventLogger(10506): at android.os.Looper.loop(Looper.java:136)
  14. 05-18 11:26:07.632: E/EventLogger(10506): at android.os.HandlerThread.run(HandlerThread.java:61)
  15. 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.
  16. 05-18 11:26:07.632: E/EventLogger(10506): at com.google.android.exoplayer2.source.ExtractorMediaPeriod$ExtractorHolder.selectExtractor(ExtractorMediaPeriod.java:927)
  17. 05-18 11:26:07.632: E/EventLogger(10506): at com.google.android.exoplayer2.source.ExtractorMediaPeriod$ExtractingLoadable.load(ExtractorMediaPeriod.java:849)
  18. 05-18 11:26:07.632: E/EventLogger(10506): at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:320)
  19. 05-18 11:26:07.632: E/EventLogger(10506): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
  20. 05-18 11:26:07.632: E/EventLogger(10506): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
  21. 05-18 11:26:07.632: E/EventLogger(10506): at java.lang.Thread.run(Thread.java:841)
  22. 05-18 11:26:07.632: D/EventLogger(10506): loading [false]

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

  1. //EXOPlayer内核,支持格式更多
  2. PlayerFactory.setPlayManager(Exo2PlayerManager.class);
  3. //exo缓存模式,支持m3u8,只支持exo
  4. CacheFactory.setCacheManager(ExoPlayerCacheManager.class);

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

4.2 方案二测试(可行)

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

  1. /**
  2. * 处理快进快退问题
  3. * @param isForward
  4. */
  5. public void step(boolean isForward) {
  6. if (!getGSYVideoManager().isPlaying()) {
  7. PLog.i("fastForward is not playing");
  8. getStartButton().callOnClick();
  9. }
  10. int videoLength = (int) getGSYVideoManager().getDuration();
  11. if (videoLength == -1) {
  12. return;
  13. }
  14. int size = videoLength / LENGTH;// LENGTH快进快退的步长
  15. final int[] postion = new int[size + 2];
  16. postion[size + 1] = videoLength;
  17. for (int i = 0; i <= size; i++) {
  18. postion[i] = LENGTH * i;
  19. }
  20. mBottomContainer.setVisibility(VISIBLE);
  21. if (isForward) { // 快进
  22. if (mCurrentPosition == videoLength) {
  23. setProgress(videoLength, videoLength);
  24. return;
  25. }
  26. for (int i = 0; i < postion.length; i++) {
  27. if (postion[i] - mCurrentPosition > 0) {
  28. PLog.i("forwart postion=" + postion[i]);
  29. setProgress(postion[i], videoLength);
  30. getGSYVideoManager().seekTo(mCurrentPosition);
  31. break;
  32. }
  33. }
  34. } else { // 快退
  35. if (mCurrentPosition == 0) {
  36. setProgress(0, videoLength);
  37. return;
  38. }
  39. for (int i = 0; i < postion.length; i++) {
  40. if (postion[i] - mCurrentPosition >= 0) {
  41. setProgress(postion[i - 1], videoLength);
  42. getGSYVideoManager().seekTo(mCurrentPosition);
  43. break;
  44. }
  45. }
  46. }
  47. }
  48. /**
  49. * 快进快退 自己控制 进度条 避免快进 回退问题
  50. *
  51. * @param position
  52. * @param videoLength
  53. */
  54. public void setProgress(int position, int videoLength) {
  55. mCurrentPosition = position;
  56. int progress = (int) (mCurrentPosition / (videoLength / 100));
  57. mProgressBar.setProgress(progress);
  58. mTotalTimeTextView.setText(CommonUtil.stringForTime(videoLength));
  59. mCurrentTimeTextView.setText(CommonUtil.stringForTime(position));
  60. mHadler.postDelayed(new Runnable() {
  61. @Override
  62. public void run() {
  63. mBottomContainer.setVisibility(GONE);
  64. }
  65. }, 500);
  66. }
  67. @Override
  68. protected void setTextAndProgress(int secProgress) { // 避免关键帧 回退的问题
  69. if (!mProgressBar.isShown()) {
  70. super.setTextAndProgress(secProgress);
  71. }
  72. }

   我做了一个假象,在进度条展示的时候,我会按照自己分割的关键帧去快进快退,这样控制强行让进度条永远按照你想要的方向走,但是当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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/295815?site
推荐阅读
相关标签
  

闽ICP备14008679号