Recyclerview 中的 Exoplayer 错误,源错误没有可用的提取器

Posted

技术标签:

【中文标题】Recyclerview 中的 Exoplayer 错误,源错误没有可用的提取器【英文标题】:Exoplayer error in Recyclerview, Source error None of the available extractors 【发布时间】:2020-06-20 07:37:21 【问题描述】:

我正在使用 ExoPlayer 在 RecyclerView 中流式传输视频。

我正在 ViewHolder 中的 RecyclerView Adapter 的绑定方法中实现 ExoPlayer。

我使用的视频格式是 m3u8,我使用的 URL 在浏览器中有效。 所以我知道视频链接是有效的。我还在那里测试了一个 youtube 链接。

这是来自 Recyclerview 适配器的 ViewHolder 的代码 ->

class ViewHolder private constructor(val binding: FeedRowBinding) :
    RecyclerView.ViewHolder(binding.root) 

    fun bind(context: Activity)
        if (entity.content.videolink != null) 
            setupVideoPlayer(entity.content.videolink, context)
        
    


private fun setupVideoPlayer(url: String, context: Activity) 
    val videoExoPlayer = SimpleExoPlayer.Builder(binding.videoView.context).build()
    videoExoPlayer.prepare(createUrlMediaSource(url, context))

    binding.play.setOnClickListener 
        videoExoPlayer.playWhenReady = true
    

    binding.pause.setOnClickListener 
        videoExoPlayer.playWhenReady = false
    


private fun createUrlMediaSource(url: String, context: Activity): MediaSource 
    val userAgent = Util.getUserAgent(context, context.getString(R.string.about))
    return ProgressiveMediaSource
           .Factory(DefaultDataSourceFactory(context, userAgent), DefaultExtractorsFactory())
           .createMediaSource(Uri.parse(url))

当加载我的 recyclerview 并到达包含视频的行时,我收到以下错误:

ExoPlayerImplInternal:源错误。 com.google.android.exoplayer2.source.UnrecognizedInputFormatException: 没有可用的提取器(MatroskaExtractor, FragmentedMp4Extractor, Mp4Extractor, Mp3Extractor, AdtsExtractor, Ac3Extractor, TsExtractor, FlvExtractor, OggExtractor, PsExtractor, WavExtractor、AmrExtractor、Ac4Extractor、FlacExtractor)可以读取 流。 在 com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractorHolder.selectExtractor(ProgressiveMediaPeriod.java:1090) 在 com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractingLoadable.load(ProgressiveMediaPeriod.java:969) 在 com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:391) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 在 java.lang.Thread.run(Thread.java:764)

我不确定我做错了什么,关于如何解决这个问题的任何想法?

【问题讨论】:

【参考方案1】:

你需要修改你的createUrlMediaSource

private fun createUrlMediaSource(url: String, context: Activity): MediaSource 
    val userAgent = Util.getUserAgent(context, context.getString(R.string.about))
    return ProgressiveMediaSource
           .Factory(DefaultDataSourceFactory(context, userAgent), DefaultExtractorsFactory())
           .createMediaSource(Uri.parse(url))

如https://exoplayer.dev中所述

DashMediaSource 代表 DASH。 SsMediaSource 用于 SmoothStreaming。 HlsMediaSource 用于 HLS(这是您的格式 => .m3u8)。 ProgressiveMediaSource 用于常规媒体文件。

所以你需要将你的函数替换为:

private fun createUrlMediaSource(url: String, context: Activity): MediaSource 
    val userAgent = Util.getUserAgent(context, context.getString(R.string.about))
    return HlsMediaSource
           .Factory(DefaultDataSourceFactory(context, userAgent), DefaultExtractorsFactory())
           .createMediaSource(Uri.parse(url))

【讨论】:

【参考方案2】:

我不认为 m3u8 是一种视频格式,而是一种播放列表格式。我认为 Exoplayer 比处理播放列表级别低;可能你需要自己阅读m3u8文件,然后自己传入播放列表中的链接。

幸运的是,文件格式并不复杂,解析起来也不难。它似乎有很好的记录。***上甚至还有一些例子:https://en.wikipedia.org/wiki/M3U

【讨论】:

【参考方案3】:

在 Android 4.1+ 上,您可以使用这个库 https://github.com/brianwernick/ExoMedia/ 。自述页面上提到的示例应该足以让您入门。我已经复制了该代码 sn-p 并进行了一些添加/修改。

private void setupVideoView() 
            EMVideoView emVideoView = (EMVideoView)findViewById(R.id.video_play_activity_video_view);
            emVideoView.setOnPreparedListener(this);

            //Enter your m3u8 URL below
            emVideoView.setVideoURI(Uri.parse("http://SOMESERVER/playlist.m3u8"));
        

        @Override
        public void onPrepared(MediaPlayer mp) 
            //Starts the video playback as soon as it is ready
            emVideoView.start();
        

        @Override
        public void onPause() 
            super.onPause();
            //Pause Video Playback
            emVideoView.pause();
        

【讨论】:

【参考方案4】:

对于流式传输 .m3u8 文件,在初始化 Exoplayer 时使用以下代码:-

BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();

TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);

TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);

videoPlayer = ExoPlayerFactory.newSimpleInstance(context,trackSelector);

Handler mHandler = new Handler();

String userAgent = Util.getUserAgent(context, "Exo Player");

DataSource.Factory dataSourceFactory = new DefaultHttpDataSourceFactory(
                userAgent, null,
                DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
                1800000,
                true);

HlsMediaSource mediaSource = new HlsMediaSource(Uri.parse(mediaUrl),dataSourceFactory, 1800000,mHandler, null);

if (mediaUrl != null) 
    videoPlayer.prepare(mediaSource);
    videoPlayer.setPlayWhenReady(true);

【讨论】:

以上是关于Recyclerview 中的 Exoplayer 错误,源错误没有可用的提取器的主要内容,如果未能解决你的问题,请参考以下文章

如何用recyclerview和viewpager2实现exoplayer?

在RecyclerView中发布ExoPlayer

使用 exoplayer android 在 recyclerview 中显示视频

Exoplayer Recyclerview 第二次播放错误的视频

水平 RecyclerView 中的 VideoView 在滑动时显示墙纸

启用 Exoplayer Cache 后滑动缓慢加载