是否可以同时运行mp4和流m3u8视频的exoplayer?
我尝试过,但是找不到解决方法。
我找到了以下测试来源。
视频mp4:here
流m3u8:here
这是我在mp4视频中编写的代码,但在m3u8中却可以。
我做了几次尝试,但是没有成功,我在考虑使用HlsMediaSource,但是我无法使其工作。
错误,在SimpleVideoStream.java
中调用了以下函数:
public void onPlayerError(ExoPlaybackException error) {
代码:
AndroidManifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ui.exoplayer">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".SimpleVideoStream"
android:configChanges="orientation|screenSize"
android:screenOrientation="landscape" />
</application>
</manifest>
MainActivity:
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Intent intent = new Intent(this, SimpleVideoStream.class);
Bundle extras = new Bundle();
extras.putString("title", "Big Buck Bunny");
//extras.putString("url", "https://www.w3schools.com/html/mov_bbb.mp4");
extras.putString("url", "https://live3-mediaset-it.akamaized.net/content/hls_clr_xo/live/channel(ch09)/Stream(02)/index.m3u8");
extras.putString("sub", "https://pastebin.com/raw/A0fDHxgK");
extras.putBoolean("subShow", true);
intent.putExtras(extras);
startActivity(intent);
}
}
SimpleVideoStream:
package com.ui.exoplayer;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.WindowManager;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.LoadControl;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer2.extractor.ExtractorsFactory;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MergingMediaSource;
import com.google.android.exoplayer2.source.SingleSampleMediaSource;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.trackselection.TrackSelector;
import com.google.android.exoplayer2.ui.SimpleExoPlayerView;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
public class SimpleVideoStream extends AppCompatActivity implements ExoPlayer.EventListener {
public static final int PERMISSIONS_REQUEST_CODE = 0;
SimpleExoPlayerView playerView;
SimpleExoPlayer player;
DataSource.Factory dataSourceFactory;
MediaSource videoSource;
String url, sub;
Boolean showTitle = true, showSub = false;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Bundle b = getIntent().getExtras();
url = b.getString("url", "");
sub = b.getString("sub", "");
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
playerView = (SimpleExoPlayerView) findViewById(R.id.exo_player_view);
// 1. Create a default TrackSelector
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
// 2. Create a default LoadControl
LoadControl loadControl = new DefaultLoadControl();
// 3. Create the player
player = ExoPlayerFactory.newSimpleInstance(this, trackSelector, loadControl);
playerView.setPlayer(player);
playerView.setKeepScreenOn(true);
playerView.setRewindIncrementMs(5 * 1000);
playerView.setFastForwardIncrementMs(5 * 1000);
// Produces DataSource instances through which media data is loaded.
dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "ExoPlayer"));
// Produces Extractor instances for parsing the media data.
final ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
// This is the MediaSource representing the media to be played.
videoSource = new ExtractorMediaSource(Uri.parse(url), dataSourceFactory, extractorsFactory, null, null);
// Prepare the player with the source.
player.addListener(this);
player.prepare(videoSource);
playerView.requestFocus();
player.setPlayWhenReady(true);// to play video when ready. Use false to pause a video
if (!sub.equals("") && b.getBoolean("subShow")) addSub(sub);
}
@Override
protected void onPause() {
super.onPause();
if (player != null) {
player.setPlayWhenReady(false); //to pause a video because now our video player is not in focus
}
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
}
@Override
public void onLoadingChanged(boolean isLoading) {
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
switch (playbackState) {
case ExoPlayer.STATE_BUFFERING:
//You can use progress dialog to show user that video is preparing or buffering so please wait
break;
case ExoPlayer.STATE_IDLE:
//idle state
break;
case ExoPlayer.STATE_READY:
// dismiss your dialog here because our video is ready to play now
break;
case ExoPlayer.STATE_ENDED:
// do your processing after ending of video
break;
}
}
@Override
public void onPlayerError(ExoPlaybackException error) {
// show user that something went wrong. I am showing dialog but you can use your way
AlertDialog.Builder adb = new AlertDialog.Builder(this);
adb.setTitle("Could not able to stream video");
adb.setMessage("It seems that something is going wrong.\nPlease try again.");
adb.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
finish(); // take out user from this activity. you can skip this
}
});
AlertDialog ad = adb.create();
ad.show();
}
@Override
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
}
@Override
public void onRepeatModeChanged(int repeatMode) {
}
@Override
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
}
@Override
public void onPositionDiscontinuity(int reason) {
}
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
}
@Override
public void onSeekProcessed() {
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
private void removeSub() {
showSub = false;
final ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
videoSource = new ExtractorMediaSource(Uri.parse(url), dataSourceFactory, extractorsFactory, null, null);
player.prepare(videoSource, false, false);
}
private void addSub(String sub) {
removeSub();
showSub = true;
Format textFormat = Format.createTextSampleFormat(null, MimeTypes.APPLICATION_SUBRIP, null, Format.NO_VALUE, Format.NO_VALUE, "en", null, Format.OFFSET_SAMPLE_RELATIVE);
MediaSource textMediaSource = new SingleSampleMediaSource.Factory(dataSourceFactory).createMediaSource(Uri.parse(sub), textFormat, C.TIME_UNSET);
videoSource = new MergingMediaSource(videoSource, textMediaSource);
player.prepare(videoSource, false, false);
}
}
答案 0 :(得分:0)
我相信您确实需要使用HlsMediaSource来流式传输HLS(m3u8)。以下示例适用于DASH,HLS和mp4。
// 1. Create a default TrackSelector
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory = new
AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector = new
DefaultTrackSelector(videoTrackSelectionFactory);
playerView = rootView.findViewById(R.id.videoView);
player = ExoPlayerFactory.newSimpleInstance(<context>, trackSelector);
player.setPlayWhenReady(true);
playerView.setPlayer(player);
// DASH
// DefaultHttpDataSourceFactory dataSourceFactory = new DefaultHttpDataSourceFactory(
// Util.getUserAgent(<context>, "ExoPlayer"));
// DefaultDashChunkSource.Factory chunkSourceFactory = new
// DefaultDashChunkSource.Factory(dataSourceFactory);
//
// MediaSource mediaSource = new DashMediaSource(Uri.parse(<dash url>),
// dataSourceFactory, chunkSourceFactory, null, null);
// HLS
// DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(<context>,
// Util.getUserAgent(rootView.getContext(), "ExoPlayer"));
//
// // Produces Extractor instances for parsing the media data.
// ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
// Handler mainHandler = new Handler();
// MediaSource mediaSource = new HlsMediaSource(Uri.parse(
// "https://live3-mediaset-it.akamaized.net/content/hls_clr_xo/live/channel(ch09)/Stream(02)/index.m3u8"),
// dataSourceFactory, null, null);
// MP4
// Produces DataSource instances through which media data is loaded.
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(<context>,
Util.getUserAgent(rootView.getContext(), "ExoPlayer"));
// Produces Extractor instances for parsing the media data.
final ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
// This is the MediaSource representing the media to be played.
MediaSource mediaSource = new ExtractorMediaSource(Uri.parse(
"https://www.w3schools.com/html/mov_bbb.mp4"),
dataSourceFactory, extractorsFactory, null, null);
player.prepare(mediaSource);
player.setPlayWhenReady(true);
答案 1 :(得分:0)
这将是一个用 Kotlin 编写的更优雅的解决方案来处理 .mp4
和 .m3u8
流网址
示例layout.xml
<com.google.android.exoplayer2.ui.PlayerView
android:id="@+id/videoPlayerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
初始化你的播放器
var exoPlayer: ExoPlayer? = null
exoPlayer = SimpleExoPlayer.Builder(videoPlayerView.context).build()
exoPlayer?.repeatMode = Player.REPEAT_MODE_OFF
videoPlayerView.player = exoPlayer
val uri: Uri = Uri.parse(url)
val mediaSource = buildMediaSource(uri)
exoPlayer?.prepare(mediaSource, true, false)
exoPlayer?.playWhenReady = true
下面的方法处理 mp4
和 m3u8
流媒体的播放。
private fun buildMediaSource(uri: Uri): MediaSource {
val userAgent = Util.getUserAgent(videoPlayerView.context, getString(R.string.app_name))
val lastPathSegment = uri.lastPathSegment
return if (lastPathSegment?.contains("mp3") == true ||
lastPathSegment?.contains("mp4") == true
) {
ProgressiveMediaSource.Factory(DefaultHttpDataSourceFactory(userAgent))
.createMediaSource(uri)
} else if (lastPathSegment?.contains("m3u8") == true) {
HlsMediaSource.Factory(DefaultHttpDataSourceFactory(userAgent))
.createMediaSource(uri)
} else {
val dashChunkSourceFactory = DefaultDashChunkSource.Factory(
DefaultHttpDataSourceFactory("ua", null)
)
val manifestDataSourceFactory = DefaultHttpDataSourceFactory(userAgent)
DashMediaSource.Factory(dashChunkSourceFactory, manifestDataSourceFactory)
.createMediaSource(uri)
}
}