我正在使用ExoPlayer在RecyclerView中流式传输视频。
我正在ViewHolder内的RecyclerView Adapter的bind方法内实现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)
我不确定我在做什么错,关于如何解决此问题的任何想法?
我不认为m3u8是视频格式,而是播放列表格式。我认为Exoplayer的级别比处理播放列表的级别低;可能您需要自己阅读m3u8文件,然后自己传递播放列表中的链接。
幸运的是,文件格式并不复杂,解析起来也不应该太困难。看来它已经被很好地证明了。维基百科上甚至有一些示例:https://en.wikipedia.org/wiki/M3U
对于流式.m3u8文件,在初始化Exoplayer时使用以下代码:-
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);
}
在Android 4.1+上,您可以使用此库https://github.com/brianwernick/ExoMedia/。自述页面上提到的示例应该足以使您入门。我已经复制了该代码段,并进行了一些补充/修改。
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();
}
您需要修改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))
}
DashMediaSource
for DASH。SsMediaSource
用于SmoothStreaming。HlsMediaSource
(这是您的格式=> .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))
}