it-swarm.com.de

Cache in ExoPlayer verwenden

Ich suche nach einem Beispiel für die Implementierung von Cache in ExoPlayer. 

ExoPlayer hat in seiner Bibliothek verschiedene Klassen bezüglich Cache und Google erklärt in diesem video , dass wir es mit der CacheDataSource-Klasse implementieren können, aber Google stellt keine Demo bereit. Leider scheint dies ziemlich kompliziert zu sein, daher suche ich derzeit nach Beispielen (kein Erfolg bei Google).

Hat jemand Erfolg oder hat eine Info, die helfen würde? Vielen Dank.

28
ilansas

Hier ist die Lösung für ExoPlayer 2. +

Erstellen Sie eine benutzerdefinierte Cache-Datenquellenfactory

class CacheDataSourceFactory implements DataSource.Factory {
    private final Context context;
    private final DefaultDataSourceFactory defaultDatasourceFactory;
    private final long maxFileSize, maxCacheSize;

    CacheDataSourceFactory(Context context, long maxCacheSize, long maxFileSize) {
        super();
        this.context = context;
        this.maxCacheSize = maxCacheSize;
        this.maxFileSize = maxFileSize;
        String userAgent = Util.getUserAgent(context, context.getString(R.string.app_name));
        DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
        defaultDatasourceFactory = new DefaultDataSourceFactory(this.context,
                bandwidthMeter,
                new DefaultHttpDataSourceFactory(userAgent, bandwidthMeter));
    }

    @Override
    public DataSource createDataSource() {
        LeastRecentlyUsedCacheEvictor evictor = new LeastRecentlyUsedCacheEvictor(maxCacheSize);
        SimpleCache simpleCache = new SimpleCache(new File(context.getCacheDir(), "media"), evictor);
        return new CacheDataSource(simpleCache, defaultDatasourceFactory.createDataSource(),
                new FileDataSource(), new CacheDataSink(simpleCache, maxFileSize),
                CacheDataSource.FLAG_BLOCK_ON_CACHE | CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR, null);
    }
}

Und der Spieler

BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory =
        new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);

SimpleExoPlayer exoPlayer = ExoPlayerFactory.newSimpleInstance(this, trackSelector);
MediaSource audioSource = new ExtractorMediaSource(Uri.parse(url),
            new CacheDataSourceFactory(context, 100 * 1024 * 1024, 5 * 1024 * 1024), new DefaultExtractorsFactory(), null, null);
exoPlayer.setPlayWhenReady(true); 
exoPlayer.prepare(audioSource);

Es funktioniert ziemlich gut.

25
Bao Le

Hier ist ein Beispiel, das die Demodatenquelle durch OkHttp ersetzt. Der Standardwert ist kein Cache https://github.com/b95505017/ExoPlayer/commit/ebfdda8e7848a2e2e275f5c0525f614b56ef43a6https: //) github.com/b95505017/ExoPlayer/tree/okhttp_http_data_source .__ Sie müssen den OkHttp-Cache also nur richtig konfigurieren, und die Anforderungen sollten zwischengespeichert werden.

5
Jacek Tymicki

Ich habe es im Renderer-Builder so implementiert

private static final int BUFFER_SEGMENT_SIZE = 64 * 1024;
private static final int BUFFER_SEGMENT_COUNT = 160;

final String userAgent = Util.getUserAgent(mContext, appName);
final DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
final Allocator allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE);*

Cache cache = new SimpleCache(context.getCacheDir(), new LeastRecentlyUsedCacheEvictor(1024 * 1024 * 10));
DataSource dataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
CacheDataSource cacheDataSource = new CacheDataSource(cache, dataSource, false, false);
ExtractorSampleSource sampleSource = new ExtractorSampleSource(uri
                , cacheDataSource
                , allocator
                , BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE
                , new Mp4Extractor());
2
S.Prapagorn

Die Dokumentationsliste von Exoplayer ist der class DashDownloader und enthält einige Beispielcodes für diese Art von Quelle. (Klicken Sie auf [Frames], um zur Navigation der Dokumentation zurückzukehren. Ich musste sie entfernen, um den Deep-Link zu erhalten.)

0

Um das Problem zu lösen, dass mehrere Videos oder Prozesse versuchen, auf denselben Cache zuzugreifen, benötigen Sie einen echten Singleton. Ein zuverlässiger Weg wäre, es so zu machen:

object VideoCache {
    private var sDownloadCache: SimpleCache? = null
    private const val maxCacheSize: Long = 100 * 1024 * 1024

    fun getInstance(context: Context): SimpleCache {
        val evictor = LeastRecentlyUsedCacheEvictor(maxCacheSize)
        if (sDownloadCache == null) sDownloadCache = SimpleCache(File(context.cacheDir, "koko-media"), evictor)
        return sDownloadCache as SimpleCache
    }
}

was Sie jetzt verwenden können:

private val simpleCache: SimpleCache by lazy {
        VideoCache.getInstance(context)
    }
0
Rowland Mtetezi

Standardmäßig speichert der ExoPlayer keine Medien (Video, Audio usw.). Wenn Sie beispielsweise eine Online-Videodatei abspielen möchten, liest ExoPlayer jedes Mal eine Verbindung, liest Daten und spielt sie ab.

Glücklicherweise bietet es uns einige Schnittstellen und Implementierungsklassen, um das Zwischenspeichern von Medien in unserer App zu unterstützen.

Sie können Ihren eigenen Cache schreiben, der bestimmte Schnittstellen von ExoPlayer implementiert. Um es einfach zu machen, werde ich Ihnen zeigen, wie Sie den Cache mithilfe von Implementierungsklassen aktivieren.

Schritt 1: Geben Sie einen Ordner an, der Ihre Mediendateien enthält. In Android für kleinere Cache-Ordner (weniger als 1 MB) sollten Sie getCacheDir verwenden. Andernfalls können Sie Ihren bevorzugten Cache-Ordner angeben. getFileDir zum Beispiel.

Schritt 2: Geben Sie eine Größe für den Cache-Ordner und Richtlinien an, wenn die Größe erreicht ist. Es gibt 2 APIs

  • NoOpCacheEvictor das Cache-Dateien nicht entfernt oder entfernt. Je nach Speicherort des Cache-Ordners wird der Ordner entfernt, wenn er sich im internen Speicher befindet, wenn Benutzer App-Daten löschen oder die App deinstallieren.
  • LeastRecentlyUsedCacheEvictor das wird die zuletzt verwendeten Cache-Dateien zuerst entfernen/entfernen. Wenn Ihre Cache-Größe beispielsweise 10 MB beträgt, werden bei Erreichen der Größe automatisch Dateien gesucht und entfernt, die am wenigsten verwendet wurden.

Setze es zusammen

val renderersFactory = DefaultRenderersFactory(context.applicationContext)
val trackSelector = DefaultTrackSelector()
val loadControl = DefaultLoadControl()

val player = ExoPlayerFactory.newSimpleInstance(context, renderersFactory, trackSelector, loadControl)
player.addListener(this)

// Specify cache folder, my cache folder named media which is inside getCacheDir.
val cacheFolder = File(context.cacheDir, "media")

// Specify cache size and removing policies
val cacheEvictor = LeastRecentlyUsedCacheEvictor(1 * 1024 * 1024) // My cache size will be 1MB and it will automatically remove least recently used files if the size is reached out.

// Build cache
val cache = SimpleCache(cacheFolder, cacheEvictor)

// Build data source factory with cache enabled, if data is available in cache it will return immediately, otherwise it will open a new connection to get the data.
val cacheDataSourceFactory = CacheDataSourceFactory(cache, DefaultHttpDataSourceFactory("ExoplayerDemo"))

val uri = Uri.parse("Put your media url here")
val mediaSource = ExtractorMediaSource.Factory(cacheDataSourceFactory).createMediaSource(uri)

player.prepare(mediaSource)
0
Tommy

Neben der Antwort von Bao Le können Sie die Kotlin-Version von CacheDataSourceFactory verwenden, die eine Instanz von SimpleCache enthält, um das Problem zu lösen, dass mehrere Cache-Objekte in dasselbe Verzeichnis schreiben.

class CacheDataSourceFactory(private val context: Context,
                                      private val maxCacheSize: Long,
                                      private val maxFileSize: Long) : DataSource.Factory {

    private val defaultDatasourceFactory: DefaultDataSourceFactory
    private val simpleCache: SimpleCache by lazy {
        val evictor = LeastRecentlyUsedCacheEvictor(maxCacheSize)
        SimpleCache(File(context.cacheDir, "media"), evictor)
    }

    init {
        val userAgent = Util.getUserAgent(context, context.packageName)
        val bandwidthMeter = DefaultBandwidthMeter()
        defaultDatasourceFactory = DefaultDataSourceFactory(context,
                bandwidthMeter,
                DefaultHttpDataSourceFactory(userAgent, bandwidthMeter))
    }

    override fun createDataSource(): DataSource {
        return CacheDataSource(simpleCache,
                defaultDatasourceFactory.createDataSource(),
                FileDataSource(),
                CacheDataSink(simpleCache, maxFileSize),
                CacheDataSource.FLAG_BLOCK_ON_CACHE or CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR,
                null)
    }
}
0
Dmide

Hier ist mein Beispiel in Kotlin (Projekt verfügbar hier ):

class MainActivity : AppCompatActivity() {
    private var player: SimpleExoPlayer? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (cache == null) {
            cache = SimpleCache(File(cacheDir, "media"), LeastRecentlyUsedCacheEvictor(MAX_PREVIEW_CACHE_SIZE_IN_BYTES))
        }
        setContentView(R.layout.activity_main)
    }

    override fun onStart() {
        super.onStart()
        playVideo()
    }

    private fun playVideo() {
        player = ExoPlayerFactory.newSimpleInstance([email protected], DefaultTrackSelector())
        playerView.player = player
        player!!.volume = 1f
        player!!.playWhenReady = true
        player!!.repeatMode = Player.REPEAT_MODE_ALL
        player!!.playVideoFromUrl(this, "https://sample-videos.com/video123/mkv/240/big_buck_bunny_240p_20mb.mkv", cache!!)
//        player!!.playVideoFromUrl(this, "https://sample-videos.com/video123/mkv/720/big_buck_bunny_720p_1mb.mkv", cache!!)
//        player!!.playVideoFromUrl(this, "https://sample-videos.com/video123/mkv/720/big_buck_bunny_720p_1mb.mkv")
//        player!!.playRawVideo(this,R.raw.videoplayback)
    }

    override fun onStop() {
        super.onStop()
        playerView.player = null
        player!!.release()
        player = null
    }

    companion object {
        const val MAX_PREVIEW_CACHE_SIZE_IN_BYTES = 20L * 1024L * 1024L
        var cache: com.google.Android.exoplayer2.upstream.cache.Cache? = null

        @JvmStatic
        fun getUserAgent(context: Context): String {
            val packageManager = context.packageManager
            val info = packageManager.getPackageInfo(context.packageName, 0)
            val appName = info.applicationInfo.loadLabel(packageManager).toString()
            return Util.getUserAgent(context, appName)
        }
    }

    fun SimpleExoPlayer.playRawVideo(context: Context, @RawRes rawVideoRes: Int) {
        val dataSpec = DataSpec(RawResourceDataSource.buildRawResourceUri(rawVideoRes))
        val rawResourceDataSource = RawResourceDataSource(context)
        rawResourceDataSource.open(dataSpec)
        val factory: DataSource.Factory = DataSource.Factory { rawResourceDataSource }
        prepare(LoopingMediaSource(ExtractorMediaSource.Factory(factory).createMediaSource(rawResourceDataSource.uri)))
    }

    fun SimpleExoPlayer.playVideoFromUrl(context: Context, url: String, cache: Cache? = null) = playVideoFromUri(context, Uri.parse(url), cache)

    fun SimpleExoPlayer.playVideoFile(context: Context, file: File) = playVideoFromUri(context, Uri.fromFile(file))

    fun SimpleExoPlayer.playVideoFromUri(context: Context, uri: Uri, cache: Cache? = null) {
        val factory = if (cache != null)
            CacheDataSourceFactory(cache, DefaultHttpDataSourceFactory(getUserAgent(context)))
        else
            DefaultDataSourceFactory(context, MainActivity.getUserAgent(context))
        val mediaSource = ExtractorMediaSource.Factory(factory).createMediaSource(uri)
        prepare(mediaSource)
    }
}
0