我正在使用Android中的Exoplayer媒体播放器从RTMP媒体源URL直播。我是这种开发的新手,所以我关注official Tutorial。所有Android设备上的直播流都正常!我获取实时流的类是:
import android.annotation.SuppressLint;
import android.databinding.DataBindingUtil;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import com.example.juni1289.exoplayertest2.databinding.ActivityMainBinding;
import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.DefaultRenderersFactory;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.ext.rtmp.RtmpDataSourceFactory;
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.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.trackselection.TrackSelector;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.util.Util;
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
private ExoPlayer player;
private boolean playWhenReady;
private static final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter();
private ComponentListener componentListener;
private final String TAG = "MainActivity";
private MediaSource videoSource;
private AdaptiveTrackSelection.Factory adaptiveTrackSelectionFactory;
private TrackSelector trackSelector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
componentListener = new ComponentListener();
initializePlayer();
}
private void initializePlayer() {
if (player == null) {
// a factory to create an AdaptiveVideoTrackSelection
adaptiveTrackSelectionFactory = new AdaptiveTrackSelection.Factory(BANDWIDTH_METER);
trackSelector = new DefaultTrackSelector(adaptiveTrackSelectionFactory);
player = ExoPlayerFactory.newSimpleInstance(
new DefaultRenderersFactory(this),
trackSelector,
new DefaultLoadControl());
binding.videoView.setPlayer(player);
RtmpDataSourceFactory rtmpDataSourceFactory = new RtmpDataSourceFactory();
// Produces Extractor instances for parsing the media data.
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
// This is the MediaSource representing the media to be played.
videoSource = new ExtractorMediaSource(Uri.parse(""),
rtmpDataSourceFactory, extractorsFactory, null, null);
playWhenReady = true;
player.prepare(videoSource);
player.setPlayWhenReady(playWhenReady);
player.addListener(componentListener);
}
}
private void releasePlayer() {
if (player != null) {
player.removeListener(componentListener);
playWhenReady = player.getPlayWhenReady();
player.release();
player = null;
}
}
@Override
public void onPause() {
super.onPause();
if (Util.SDK_INT <= 23) {
releasePlayer();
}
}
@Override
public void onStop() {
super.onStop();
if (Util.SDK_INT > 23) {
releasePlayer();
}
}
@Override
public void onResume() {
super.onResume();
hideSystemUi();
if ((Util.SDK_INT <= 23 || player == null)) {
initializePlayer();
}
}
@SuppressLint("InlinedApi")
private void hideSystemUi() {
binding.videoView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
private class ComponentListener extends Player.DefaultEventListener {
@Override
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
super.onTimelineChanged(timeline, manifest, reason);
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
super.onTracksChanged(trackGroups, trackSelections);
}
@Override
public void onLoadingChanged(boolean isLoading) {
super.onLoadingChanged(isLoading);
}
@Override
public void onRepeatModeChanged(int repeatMode) {
super.onRepeatModeChanged(repeatMode);
}
@Override
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
super.onShuffleModeEnabledChanged(shuffleModeEnabled);
}
@Override
public void onPlayerError(ExoPlaybackException error) {
super.onPlayerError(error);
}
@Override
public void onPositionDiscontinuity(int reason) {
super.onPositionDiscontinuity(reason);
}
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
super.onPlaybackParametersChanged(playbackParameters);
}
@Override
public void onSeekProcessed() {
super.onSeekProcessed();
}
@Override
public void onTimelineChanged(Timeline timeline, Object manifest) {
super.onTimelineChanged(timeline, manifest);
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
String stateString;
switch (playbackState) {
case ExoPlayer.STATE_IDLE:
stateString = "ExoPlayer.STATE_IDLE -";
break;
case ExoPlayer.STATE_BUFFERING:
stateString = "ExoPlayer.STATE_BUFFERING -";
break;
case ExoPlayer.STATE_READY:
stateString = "ExoPlayer.STATE_READY -";
break;
case ExoPlayer.STATE_ENDED:
stateString = "ExoPlayer.STATE_ENDED -";
break;
default:
stateString = "UNKNOWN_STATE -";
break;
}
Log.e(TAG, "changed state to " + stateString
+ " playWhenReady: " + playWhenReady);
}
}
}
Gradle Dependencies
implementation 'com.google.android.exoplayer:exoplayer-core:2.7.3'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.7.3'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.7.3'
implementation 'com.google.android.exoplayer:extension-rtmp:2.7.3'
网址来自 Nginx 服务器在后台实施,后端直播流媒体软件使用MacBook进行 Wirecast 。
我面临的问题是,当我丢失Wifi连接(正常工作)时,直播流根本不会恢复。同样是3G / 4G移动网络连接,一旦它关闭,直播就不会恢复。
我已经按照给定的教程搜索了许多论坛以解决问题!但我无法找到任何资源信息以纠正问题!
我为我提供了一个解决方案,广播接收器在MainActivity中注册,将检查Internet连接,一旦它改变状态,Exoplayer将被重新初始化。但这有限制,只有当Wifi或移动数据连接打开或关闭时它才有效!
我希望Exoplayer在Wifi或移动数据连接停止时恢复实时流,然后它有一些生命,Exoplayer恢复实时流再次观看!
任何帮助或指导都将受到高度赞赏!由于我是这个开发的新手,我的代码中可能会出现任何错误。
我也在尝试使用以下代码:
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Surface;
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.decoder.DecoderCounters;
import com.google.android.exoplayer2.ext.rtmp.RtmpDataSourceFactory;
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.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.DefaultAllocator;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.video.VideoRendererEventListener;
public class MainActivity extends AppCompatActivity implements VideoRendererEventListener {
private SimpleExoPlayerView exoPlayerView;
private final String logKEY = "MainActivity";
private SimpleExoPlayer player;
private MediaSource videoSource;
private final String url = "myurl";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initExoPlayer();
}
private void initExoPlayer() {
try {
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
AdaptiveTrackSelection.Factory videoSelectionFactory=new AdaptiveTrackSelection.Factory(bandwidthMeter);
//TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector = new DefaultTrackSelector(videoSelectionFactory);
/////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//Create the player
DefaultAllocator defaultAllocator = new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE);
DefaultLoadControl defaultLoadControl = new DefaultLoadControl(defaultAllocator, 30,
30, 10, DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS,
DefaultLoadControl.DEFAULT_TARGET_BUFFER_BYTES, DefaultLoadControl.DEFAULT_PRIORITIZE_TIME_OVER_SIZE_THRESHOLDS);
player = ExoPlayerFactory.newSimpleInstance(this, trackSelector, defaultLoadControl);
exoPlayerView.setPlayer(player);
exoPlayerView.setUseController(false);
RtmpDataSourceFactory rtmpDataSourceFactory = new RtmpDataSourceFactory();
// Produces Extractor instances for parsing the media data.
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
// This is the MediaSource representing the media to be played.
videoSource = new ExtractorMediaSource(Uri.parse(url),
rtmpDataSourceFactory, extractorsFactory, null, null);
// Prepare the player with the source.
player.prepare(videoSource);
//auto start playing
player.setPlayWhenReady(true);
//adding listeners
player.addListener(new ExoPlayer.EventListener() {
@Override
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
}
@Override
public void onLoadingChanged(boolean isLoading) {
if (isLoading) {
Log.e(logKEY, "loadingChanged:::true");
} else {
Log.e(logKEY, "loadingChanged:::false");
}
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
}
@Override
public void onRepeatModeChanged(int repeatMode) {
}
@Override
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
}
@Override
public void onPlayerError(ExoPlaybackException error) {
Log.e(logKEY, "Listener-onPlayerError...");
player.stop();
player.prepare(videoSource);
player.setPlayWhenReady(true);
}
@Override
public void onPositionDiscontinuity(int reason) {
}
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
}
@Override
public void onSeekProcessed() {
}
});
} catch (Exception e) {
Log.e(logKEY, "error:::" + e.toString());
e.printStackTrace();
}
}
private void initView() {
exoPlayerView = findViewById(R.id.exoPlayerView);
}
@Override
public void onVideoEnabled(DecoderCounters counters) {
}
@Override
public void onVideoDecoderInitialized(String decoderName, long initializedTimestampMs, long initializationDurationMs) {
}
@Override
public void onVideoInputFormatChanged(Format format) {
}
@Override
public void onDroppedFrames(int count, long elapsedMs) {
}
@Override
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
Log.e(logKEY, "onVideoSizeChanged [" + " width: " + width + " height: " + height + "]");
Log.e(logKEY, "RES:(WxH):" + width + "X" + height + "\n " + height + "p");
}
@Override
public void onRenderedFirstFrame(Surface surface) {
}
@Override
public void onVideoDisabled(DecoderCounters counters) {
}
@Override
protected void onStop() {
super.onStop();
Log.e(logKEY, "onStop()...");
}
@Override
protected void onStart() {
super.onStart();
Log.e(logKEY, "onStart()...");
}
@Override
protected void onResume() {
super.onResume();
Log.e(logKEY, "onResume()...");
}
@Override
protected void onPause() {
super.onPause();
Log.e(logKEY, "onPause()...");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.e(logKEY, "onDestroy()...");
player.release();
}
}
以上也有上述问题!