打赏

记录推流java代码

package com.aipeople.by;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.aipeople.by.databinding.ActivityMainBinding;
import com.pedro.rtplibrary.rtsp.RtspCamera2;
import com.pedro.rtplibrary.view.OpenGlView;
import com.pedro.rtsp.utils.ConnectCheckerRtsp;

public class MainActivity extends AppCompatActivity implements ConnectCheckerRtsp {

    private ActivityMainBinding binding;
    private RtspCamera2 rtspCamera2;
    private TextView tvStatus;

    // 目标 RTSP 推流地址
    private final String RTSP_URL = "rtsp://192.168.2.180:8554/zhxt";

    // 状态标志位:解耦权限异步回调与 Surface 异步创建
    private boolean isPermissionGranted = false;
    private boolean isSurfaceReady = false;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        tvStatus = binding.tvStatus;

        // 【关键】先注册 Surface 回调,再申请权限
        setupSurfaceCallback();
        checkAndRequestPermissions();
    }

    /**
     * 监听 OpenGlView 底层 Surface 生命周期
     * 防止在 Surface 未就绪时初始化 EGL 导致 glThread 崩溃
     */
    private void setupSurfaceCallback() {
        binding.openGlView.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(@NonNull SurfaceHolder holder) {
                isSurfaceReady = true;
                tryStartPushIfReady();
            }

            @Override
            public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
                // Surface 尺寸变化时可在此处理,当前无需操作
            }

            @Override
            public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
                isSurfaceReady = false;
                releaseStreamer();
            }
        });
    }

    /**
     * 检查并请求相机和麦克风权限
     */
    private void checkAndRequestPermissions() {
        String[] perms = {Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO};
        boolean allGranted = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
                && ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED;

        if (allGranted) {
            isPermissionGranted = true;
            tryStartPushIfReady();
        } else {
            ActivityCompat.requestPermissions(this, perms, 100);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 100 && grantResults.length >= 2
                && grantResults[0] == PackageManager.PERMISSION_GRANTED
                && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
            isPermissionGranted = true;
            tryStartPushIfReady();
        } else {
            Toast.makeText(this, "需要相机和麦克风权限才能推流", Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 双重校验:权限已授予 + Surface 已创建且有效
     */
    private void tryStartPushIfReady() {
        if (!isPermissionGranted || !isSurfaceReady) return;
        if (!binding.openGlView.getHolder().getSurface().isValid()) return;

        startPush();
    }

    /**
     * 初始化 RtspCamera2 并开始推流
     */
    private void startPush() {
        // 防止重复初始化
        if (rtspCamera2 != null && rtspCamera2.isOnPreview()) return;

        if (rtspCamera2 == null) {
            // ✅ 使用 RtspCamera2,回调接口为 ConnectCheckerRtsp
            rtspCamera2 = new RtspCamera2(binding.openGlView, this);
        }

        if (!rtspCamera2.isStreaming()) {
            // prepareVideo(width, height, fps, bitrate, iFrameInterval, rotation)
//            boolean videoReady = rtspCamera2.prepareVideo(640, 480, 30, 800 * 1024, 2, 0);
            // prepareAudio(bitrate, sampleRate, isStereo, echoCanceler, noiseSuppressor)
            boolean audioReady = rtspCamera2.prepareAudio(64 * 1024, 44100, true, false, false);
//            boolean videoReady = rtspCamera2.prepareVideo(1280, 720, 30, 2000 * 1024, 2, 0);
            // 参数依次为:width, height, fps, bitrate, iFrameInterval, rotation
            boolean videoReady = rtspCamera2.prepareVideo(
                    1920,       // 1. 宽度:1080P
                    1080,       // 2. 高度:1080P
                    30,         // 3. 帧率:30fps(保证流畅度)
                    4000 * 1024,// 4. 码率:4Mbps(1080P 30fps 的推荐高画质码率)
                    1,          // 5. 关键帧间隔:设为 1秒(提升动态清晰度)
                    90           // 6. 旋转角度:0
            );
            if (!videoReady || !audioReady) {
                updateStatus("编码器初始化失败,请检查设备");
                return;
            }

            // ✅ startPreview() 无参版本,View 已在构造函数中绑定
            rtspCamera2.startPreview();
            // ✅ RtspCamera2 支持 rtsp:// 协议
            rtspCamera2.startStream(RTSP_URL);
            updateStatus("正在连接 RTSP 服务器...");
        }
    }

    /**
     * 安全释放推流资源
     */
    private void releaseStreamer() {
        if (rtspCamera2 != null) {
            if (rtspCamera2.isStreaming()) rtspCamera2.stopStream();
            if (rtspCamera2.isOnPreview()) rtspCamera2.stopPreview();
            rtspCamera2 = null;
        }
    }

    private void updateStatus(String status) {
        runOnUiThread(() -> tvStatus.setText("当前状态:" + status));
    }

    // ==================== ConnectCheckerRtsp 回调实现 ====================

    @Override
    public void onConnectionSuccessRtsp() {
        updateStatus("RTSP 推流中");
    }

    @Override
    public void onConnectionFailedRtsp(@NonNull String reason) {
        updateStatus("连接失败: " + reason);
    }

    @Override
    public void onNewBitrateRtsp(long bitrate) {
        // 可在此更新实时码率显示
    }

    @Override
    public void onDisconnectRtsp() {
        updateStatus("已断开连接");
    }

    @Override
    public void onAuthErrorRtsp() {
        updateStatus("RTSP 认证失败");
    }

    @Override
    public void onAuthSuccessRtsp() {
        updateStatus("认证成功,连接中...");
    }

    // ==================== Activity 生命周期 ====================

    @Override
    protected void onDestroy() {
        super.onDestroy();
        releaseStreamer();
    }
}

  

posted @ 2026-07-06 15:35  吃瓜大湿熊  阅读(4)  评论(0)    收藏  举报