视频拉流优化

yt_mpremote
liuguijing 2 months ago
parent 26f12089a2
commit 7c51f7894d

@ -14,34 +14,27 @@ import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.exoplayer.source.ProgressiveMediaSource;
import androidx.media3.ui.PlayerView;
import android.app.AlertDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Toast;
import com.xypower.mpremote.databinding.ActivityStreamBinding;
import com.xypower.mpremote.utils.AdbUtils;
import com.xypower.mpremote.utils.AlertDialogUtils;
import org.videolan.libvlc.LibVLC;
import org.videolan.libvlc.Media;
import org.videolan.libvlc.MediaPlayer;
import java.util.ArrayList;
import dadb.AdbShellResponse;
import dadb.Dadb;
public class StreamActivity extends AppCompatActivity implements View.OnClickListener {
// private PlayerView playerView;
private static final String TAG = "STRM";
private static final int MAX_RETRIES = 5;
@ -65,9 +58,8 @@ public class StreamActivity extends AppCompatActivity implements View.OnClickLis
private long bufferingStartTime = 0;
private static final long BUFFERING_TIMEOUT_MS = 10000; // 10秒缓冲超时
private String RTMP_URL;
private SurfaceView playerView;
private MediaPlayer mediaPlayer;
private LibVLC libVLC;
private PlayerView playerView;
private AlertDialog alertDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -82,37 +74,19 @@ public class StreamActivity extends AppCompatActivity implements View.OnClickLis
private void initEvent() {
RTMP_URL = "rtmp://" + mDeviceIp + "/live/0";
String cmd = "am start -n com.xypower.mplive/com.xypower.mplive.MainActivity"
+ " --ei cameraId " + Integer.toString(cameraId)
+ " --ei rotation " + Integer.toString(rotation)
+ " --ei netCamera " + Integer.toString(netCamera)
+ " --ei vendor " + Integer.toString(vendor)
+ " --ei autoStart 1"
+ " --es url \"" + RTMP_URL + "\"";
String cmd = "am start -n com.xypower.mplive/com.xypower.mplive.MainActivity" + " --ei cameraId " + Integer.toString(cameraId) + " --ei rotation " + Integer.toString(rotation) + " --ei netCamera " + Integer.toString(netCamera) + " --ei vendor " + Integer.toString(vendor) + " --ei autoStart 1" + " --es url \"" + RTMP_URL + "\"";
Runnable runnable = new Runnable() {
@Override
public void run() {
initializePlayer();
}
};
alertDialog = AlertDialogUtils.show(this, "视频加载中");
startStreaming(cmd, runnable);
}
private void initHandler() {
// mHandler = new Handler();
// 配置 VLC 参数
ArrayList<String> options = new ArrayList<>();
options.add("--aout=opensles"); // 优化音频延迟‌:ml-citation{ref="6" data="citationList"}
options.add("--audio-time-stretch");
libVLC = new LibVLC(this, options);
mediaPlayer = new MediaPlayer(libVLC);
}
private void initIntent() {
@ -131,29 +105,9 @@ public class StreamActivity extends AppCompatActivity implements View.OnClickLis
binding.toolbar.back.setOnClickListener(this);
binding.toolbar.refresh.setOnClickListener(this);
playerView = binding.playerView;
SurfaceHolder holder = playerView.getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
Surface surface = holder.getSurface();
mediaPlayer.getVLCVout().setVideoSurface(surface,holder);
mediaPlayer.getVLCVout().attachViews(); // 绑定视图‌:ml-citation{ref="8" data="citationList"}
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
}
});
}
private void startStreaming(final String cmd, final Runnable runnable) {
Log.d(TAG, cmd);
Thread th = new Thread(new Runnable() {
@Override
public void run() {
@ -197,12 +151,10 @@ public class StreamActivity extends AppCompatActivity implements View.OnClickLis
}
}
});
th.start();
}
private void stopStreaming() {
// String cmd = "am start -n com.xypower.mplive/com.xypower.mplive.MainActivity --ei autoClose 1";
String cmd = "am force-stop com.xypower.mplive";
Thread th = new Thread(new Runnable() {
@Override
@ -240,107 +192,42 @@ public class StreamActivity extends AppCompatActivity implements View.OnClickLis
th.start();
}
private void initializePlayer2() {
// // 创建重试策略
// DefaultLoadControl loadControl = new DefaultLoadControl.Builder()
// .setBufferDurationsMs(
// 5000, // minBufferMs
// 10000, // maxBufferMs
// 500, // bufferForPlaybackMs
// 500 // bufferForPlaybackAfterRebufferMs
// ).build();
// player = new ExoPlayer.Builder(this).build();
// playerView.setPlayer(player);
// player.addListener(new Player.Listener() {
// @Override
// public void onPlayerError(PlaybackException error) {
// Log.e(TAG, "播放错误: " + error.getMessage());
// handlePlaybackError();
// }
//
// @Override
// public void onPlaybackStateChanged(int state) {
// if (state == Player.STATE_READY) {
// // 重置重试计数器当成功连接时
// retryCount = 0;
// }
// }
// });
// startPlayback();
}
// private void handlePlaybackError2() {
// if (retryCount < MAX_RETRIES) {
// retryCount++;
// Log.d(TAG, "准备重试 (" + retryCount + "/" + MAX_RETRIES + ")...");
// mHandler.postDelayed(() -> {
// if (player != null) {
// startPlayback();
// }
// }, 3000);
// } else {
// Log.e(TAG, "达到最大重试次数,停止尝试");
// // 这里可以添加UI提示或执行其他错误处理
// }
// }
private void startPlayback2() {
if (player == null) return;
Log.d(TAG, "开始播放,重试次数: " + retryCount);
MediaItem mediaItem = MediaItem.fromUri("rtmp://" + mDeviceIp + "/live/0");
ProgressiveMediaSource videoSource = new ProgressiveMediaSource.Factory(new RtmpDataSource.Factory())
.createMediaSource(mediaItem);
player.setMediaSource(videoSource);
player.prepare();
player.setPlayWhenReady(true);
}
private void initializePlayer() {
// if (player == null) {
// player = new ExoPlayer.Builder(this)
// .setLoadControl(new DefaultLoadControl.Builder()
// .setBufferDurationsMs(
// 5000, // minBufferMs
// 10000, // maxBufferMs
// 500, // bufferForPlaybackMs
// 500 // bufferForPlaybackAfterRebufferMs
// ).setPrioritizeTimeOverSizeThresholds(true)
// .build())
// .build();
//
//// playerView.setPlayer(player);
//
// player.addListener(new Player.Listener() {
// @Override
// public void onPlayerError(PlaybackException error) {
// Log.e(TAG, "播放错误: " + error.getMessage());
// handlePlaybackError();
// }
//
// @Override
// public void onPlaybackStateChanged(int state) {
// if (state == Player.STATE_BUFFERING) {
// if (!isBuffering) {
// isBuffering = true;
// bufferingStartTime = System.currentTimeMillis();
// // 启动缓冲超时检查
// retryHandler.postDelayed(bufferingTimeoutRunnable, BUFFERING_TIMEOUT_MS);
// }
// } else if (state == Player.STATE_READY) {
// isBuffering = false;
// retryHandler.removeCallbacks(bufferingTimeoutRunnable);
// retryCount = 0;
// currentRetryDelay = INITIAL_RETRY_DELAY_MS;
// Log.d(TAG, "播放器准备就绪");
// }
// }
// });
// }
// startPlayback();
Media media = new Media(libVLC, Uri.parse(RTMP_URL));
mediaPlayer.setMedia(media);
mediaPlayer.play();
if (player == null) {
player = new ExoPlayer.Builder(this).setLoadControl(new DefaultLoadControl.Builder().setBufferDurationsMs(5000, // minBufferMs
10000, // maxBufferMs
500, // bufferForPlaybackMs
500 // bufferForPlaybackAfterRebufferMs
).setPrioritizeTimeOverSizeThresholds(true).build()).build();
playerView.setPlayer(player);
player.addListener(new Player.Listener() {
@Override
public void onPlayerError(PlaybackException error) {
Log.e(TAG, "播放错误: " + error.getMessage());
handlePlaybackError();
}
@Override
public void onPlaybackStateChanged(int state) {
if (state == Player.STATE_BUFFERING) {
if (!isBuffering) {
isBuffering = true;
bufferingStartTime = System.currentTimeMillis();
// 启动缓冲超时检查
retryHandler.postDelayed(bufferingTimeoutRunnable, BUFFERING_TIMEOUT_MS);
}
} else if (state == Player.STATE_READY) {
AlertDialogUtils.dismiss(alertDialog);
isBuffering = false;
retryHandler.removeCallbacks(bufferingTimeoutRunnable);
retryCount = 0;
currentRetryDelay = INITIAL_RETRY_DELAY_MS;
Log.d(TAG, "播放器准备就绪");
}
}
});
}
startPlayback();
}
@ -356,13 +243,9 @@ public class StreamActivity extends AppCompatActivity implements View.OnClickLis
private void startPlayback() {
if (player == null) return;
Log.d(TAG, "开始播放,重试次数: " + retryCount);
// MediaItem mediaItem = MediaItem.fromUri(Uri.parse(RTMP_URL));
MediaItem mediaItem = MediaItem.fromUri(RTMP_URL);
ProgressiveMediaSource videoSource = new ProgressiveMediaSource.Factory(new RtmpDataSource.Factory())
.createMediaSource(mediaItem);
ProgressiveMediaSource videoSource = new ProgressiveMediaSource.Factory(new RtmpDataSource.Factory()).createMediaSource(mediaItem);
player.setMediaSource(videoSource);
// player.setMediaItem(mediaItem);
player.prepare();
@ -371,15 +254,13 @@ public class StreamActivity extends AppCompatActivity implements View.OnClickLis
private void handlePlaybackError() {
releasePlayerInternal();
if (retryCount < MAX_RETRIES) {
retryCount++;
Log.d(TAG, "准备重试 (" + retryCount + "), 延迟: " + currentRetryDelay + "ms");
retryHandler.postDelayed(() -> {
initializePlayer();
// 增加下次重试的延迟时间(使用退避算法)
currentRetryDelay = Math.min((long)(currentRetryDelay * RETRY_BACKOFF_MULTIPLIER), MAX_RETRY_DELAY_MS);
currentRetryDelay = Math.min((long) (currentRetryDelay * RETRY_BACKOFF_MULTIPLIER), MAX_RETRY_DELAY_MS);
}, currentRetryDelay);
}
}
@ -394,12 +275,11 @@ public class StreamActivity extends AppCompatActivity implements View.OnClickLis
}
@Override
protected void onDestroy() {
super.onDestroy();
AlertDialogUtils.dismiss(alertDialog);
releasePlayerInternal();
stopStreaming();
}
@ -408,7 +288,7 @@ public class StreamActivity extends AppCompatActivity implements View.OnClickLis
protected void onPause() {
super.onPause();
if (Util.SDK_INT < 24) {
releasePlayer();
releasePlayerInternal();
}
}
@ -417,16 +297,10 @@ public class StreamActivity extends AppCompatActivity implements View.OnClickLis
protected void onStop() {
super.onStop();
if (Util.SDK_INT >= 24) {
releasePlayer();
releasePlayerInternal();
}
}
private void releasePlayer() {
if (player != null) {
player.release();
player = null;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {

@ -11,24 +11,24 @@
android:id="@+id/toolbar"
layout="@layout/toolbar" />
<SurfaceView
android:id="@+id/playerView"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
<!-- <SurfaceView-->
<!-- android:id="@+id/playerView"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="0dp"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@+id/toolbar" />-->
<!-- <androidx.media3.ui.PlayerView-->
<!-- android:id="@+id/playerView"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="0dip"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@+id/toolbar"-->
<!-- app:resize_mode="fit"-->
<!-- app:show_buffering="always"-->
<!-- app:show_timeout="5000"-->
<!-- app:use_controller="false"-->
<!-- tools:ignore="MissingConstraints" />-->
<androidx.media3.ui.PlayerView
android:id="@+id/playerView"
android:layout_width="match_parent"
android:layout_height="0dip"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar"
app:resize_mode="fit"
app:show_buffering="always"
app:show_timeout="5000"
app:use_controller="false"
tools:ignore="MissingConstraints" />
<!-- <ImageButton-->

Loading…
Cancel
Save