如何在 ExoPlayer 的 RecyclerView 中播放视频之前预加载视频列表?

huangapple go评论89阅读模式
英文:

How to precache a list of videos before playing them in a recyclerview of exoplayer?

问题

我在RecyclerView中使用ExoPlayer来渲染视频列表。这个RecyclerView是在一个Activity中渲染的,我在打开这个Activity之前就知道了视频URL列表。

我希望能够在进入该Activity之前预加载或缓存这些视频。这些视频通常都不到1分钟。因此,我不是在寻找流畅播放视频的解决方案。我只是希望在打开Activity之前将视频缓存在缓存中,这样一旦RecyclerView打开,视频就可以像在抖音上一样无缓冲地播放。

我找到了一种使用LocalCacheDataSourceFactory来缓存已播放视频的方法,代码如下:

MediaSource videoSource =
 new ExtractorMediaSource(Uri.parse(mediaUrl),
                            new LocalCacheDataSourceFactory(context, 100 * 1024 * 1024, 5 * 1024 * 1024), new DefaultExtractorsFactory(), null, null);

这种方法只允许我缓存已播放的视频,而不能预加载或预缓存它们。

我在ExoPlayer团队的这篇Medium文章中找到了关于预缓存的内容,但没有其他适用于我特定需求的集成示例。文章链接

英文:

I am using exoplayer in recyclerview to render a list of videos. This recyclerview is rendered in an activity and I know the list of video urls before opening the activity.

I want to be able to preload or cache the videos before going to that activity. The videos are usually less than 1 minute. So I am not looking for a solution to smooth stream videos. I just want the videos to be in the cache before opening the activity so that once the recyclerview opens the videos start playing without any buffering just like in tiktok.

I found a way to cache already played videos using LocalCacheDataSourceFactory in

MediaSource videoSource =
 new ExtractorMediaSource(Uri.parse(mediaUrl),
                            new LocalCacheDataSourceFactory(context, 100 * 1024 * 1024, 5 * 1024 * 1024), new DefaultExtractorsFactory(), null, null);

This only allows me to cache the videos that are already played but not preloading or precaching them.

Found this medium article from exoplayer team but no other example integration for my specific requirement. article

答案1

得分: 1

请查看这篇文章。我编写了一个逐步指南,教你如何使用Exoplayer2预加载/预缓存视频。

在你的情况下,你必须在后台线程内创建一个递归或循环的缓存方法。

在Android中使用Exoplayer 2进行视频预加载/预缓存

英文:

Checkout this article. I have written a step by step guide to preload/precache videos using Exoplayer2.

In your case you must create a recursion or looping of caching method inside a background thread.

Video preloading/ precaching using Exoplayer 2 in Android

答案2

得分: 0

我在自己的应用中实现了这个功能。按照以下步骤操作:

  1. 添加视频缓存依赖:

    implementation 'com.danikula:videocache:2.7.1'
    
  2. 设置依赖项,推荐在应用程序类中完成此操作:

    private HttpProxyCacheServer proxy;
    
    public static HttpProxyCacheServer getProxy(Context context) {
        AppController app = (AppController) context.getApplicationContext();
        return app.proxy == null ? (app.proxy = app.newProxy()) : app.proxy;
    }
    
    private HttpProxyCacheServer newProxy() {
        return new HttpProxyCacheServer(this);
    }
    

    需要注意的是,需要保持一个单一的 HttpProxyCacheServer 实例。该库通常用于使您可以缓存视频,以便在滚动到回收视图项时,ExoPlayer 不会每次都重新缓冲它。

  3. 然后按照以下方式设置您的 ExoPlayer:

    a. 在方法中初始化 proxyServer:

    HttpProxyCacheServer proxyServer;
    
    public ViewRecommendedShortVideosAdapter(Context context) {
        proxyServer = AppController.getProxy(context);
    }
    

    b. 在播放 ExoPlayer 文件的方法中:

    String streamingURL = shortVideo.getStreamingURL();
    String proxyURL = proxyServer.getProxyUrl(streamingURL); 
    
    MediaItem mediaItem = MediaItem.fromUri(proxyURL);
    exoPlayer.setMediaItem(mediaItem);
    exoPlayer.prepare();
    exoPlayer.setPlayWhenReady(true);
    

注意:上述步骤仅在视频播放后对视频进行缓存,而不会对尚未播放的视频进行缓存。

  1. 要缓存尚未播放的视频,请执行以下操作:

    a. 您可以仅缓存回收数据 ArrayList 中的下一个视频(这有助于节省用户的互联网费用),或者您可以缓存全部视频(不建议,因为会增加用户的数据费用)。

    b. 为了缓存下一个视频,创建一个名为 prepareNextVideo() 的方法,其中包含缓存下一个视频的逻辑。在原始播放 ExoPlayer 媒体项的方法中调用此方法(可能在设置第一个媒体项并设置 exoPlayer.play() 之后)。

    c. prepareNextVideo() 中的代码:

    private void prepareNextVideo(int currentPosition) {
        URL url = null;
        try {
            ShortVideo shortVideo = videosArrayList.get(currentPosition + 1);
    
            url = new URL(proxyServer.getProxyUrl(shortVideo.getStreamingURL()));
    
            InputStream inputStream = url.openStream();
            int bufferSize = 1024; 
            byte[] buffer = new byte[bufferSize];
            int length = 0;
            while ((length = inputStream.read(buffer)) != -1) {
                // 这里不需要执行任何操作,只是读取流数据。
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

最后,只需调用此方法来缓冲下一个视频。如果希望缓冲所有视频,也可以将其放入循环中,并异步运行。

英文:

I have achieved this in my own app. Follow these steps:

  1. add this video caching dependency:

      implementation 'com.danikula:videocache:2.7.1'
    
  2. Setup dependency like this:
    It is advised that you do this in the application class:

    private HttpProxyCacheServer proxy;

    public static HttpProxyCacheServer getProxy(Context context) {
        AppController app = (AppController) context.getApplicationContext();
        return app.proxy == null ? (app.proxy = app.newProxy()) : app.proxy;
    }
    private HttpProxyCacheServer newProxy() {
        return new HttpProxyCacheServer(this);
    }

//Note that you need to have a single instance of HttpProxyCacheServer. 
//Note the library is tradinally meant to allow you to cache a video so exoplayer does not re-buffer it every single time you scroll to recycler item. 
  1. Then setup your exoplayer like this:

    a.

    HttpProxyCacheServer proxyServer; // maintain a single instance of this. you can init this in oncreate method: 
    public ViewRecommendedShortVideosAdapter(Context context) {
    
        proxyServer = AppController.getProxy(context);
       }
    

    b. In your method to play exoplayer file:

    String streamingURL = shortVideo.getStreamingURL();
        String proxyURL = proxyServer.getProxyUrl(streamingURL); 
    
        MediaItem mediaItem = MediaItem.fromUri(proxyURL); // you are now crating the media item from the proxy url you get by calling getProxyUrl on your proxyServer instance. 
        exoPlayer.setMediaItem(mediaItem);
        exoPlayer.prepare();
        exoPlayer.setPlayWhenReady(true);
    

Note: the above still only gives you caching of the video once it has been played, and not caching of yet to play videos.

  1. To cache yet to play videos, do this:

    a. you can cache only the next video in the recycler data arraylist (this helps save user internet costs) or you can cache the whole (I don't recommend, cos of data costs on users).

    b. To cache the next video, create a method such as prepareNextVideo(), this will contain the logic to cache the next video. you will call this method in the original method to play an exoplayer media item. (maybe after setting up the first media item and set exoplayer.play()).

    c. the code in the prepareNextVideo():

     private void prepareNextVideo(int currentPosition){
        URL url = null;
        try {
            ShortVideo shortVideo = videosArrayList.get(currentPosition+1); //you can put some if conditions here to check if the element exists. but a try cache should handle it to. 
    
            url = new URL(proxyServer.getProxyUrl(shortVideo.getStreamingURL())); // we are using our proxy url again. 
    
            InputStream inputStream = url.openStream();
            int bufferSize = 1024; 
            byte[] buffer = new byte[bufferSize];
            int length = 0;
            while ((length = inputStream.read(buffer)) != -1) {
                //nothing to do here. you are just reading the stream. 
            }
    
    
        } catch (Exception e) {
            e.printStackTrace();
    
            //can fetch
        }
    }
    

Finally, simply call this method to buffer the next video. you can also put it in a loop, run asynchronously if you want to buffer all the videos.

huangapple
  • 本文由 发表于 2020年4月4日 19:18:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/61027278.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定