大疆图传rtmp推流进化1

因为业务需求,有个自己写推流的功能,所以需要通过大疆的MSDK里拿到h264后再推到自己的服务器上,本来大疆自带rtmp推流功能的,但是我就要自己再传一下(万一我想在里面加上水印呢),所以我就先用一个库手搓了第一个版本。

1、先安装导入引用

//ffmpeg rtmp推流
implementation 'com.arthenica:mobile-ffmpeg-full-gpl:4.4.LTS'

2、首先大疆的h264视频帧开启调用

MediaDataCenter.getInstance().getCameraStreamManager().addReceiveStreamListener(ComponentIndexType.LEFT_OR_MAIN, reciveh264data);

3、然后回调内容如下

 private ICameraStreamManager.ReceiveStreamListener reciveh264data = new ICameraStreamManager.ReceiveStreamListener() {

        private String tempFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "tempfile.h264";
        private RTMPStreamer rtmpStreamer = new RTMPStreamer(tempFilePath);
        private boolean isStreamingStarted = false;
        @Override
        public void onReceiveStream(@NonNull byte[] data, int offset, int length, @NonNull StreamInfo info) {
            LogUtils.d("h264data", "data长度:" + data.length + "data offset度:" + offset + ",StreamInfo:" + info.toString());
            LogUtils.e("H264FileWriter", "写入数据失败: " + tempFilePath);
            // 写入每一帧数据到临时文件
            rtmpStreamer.sendFrame(Arrays.copyOfRange(data, offset, offset + length));
            // 启动推流(只需启动一次)
            if (!isStreamingStarted) {
                rtmpStreamer.startStreaming("rtmp://192.168.1.10/live/test");
                isStreamingStarted = true;  // 确保只启动一次
            } 
        }
    };

4、然后是ffmpeg推流类RTMPStreamer

public class RTMPStreamer {

    private FileOutputStream fileOutputStream;
    private String tempFilePath;

    public RTMPStreamer(String tempFilePath) {
        this.tempFilePath = tempFilePath;
    }

    public void startStreaming(String rtmpUrl) {
        String command = "-re -i " + tempFilePath + " -c:v copy -f flv " + rtmpUrl;

        FFmpeg.executeAsync(command, (executionId, returnCode) -> {
            if (returnCode == Config.RETURN_CODE_SUCCESS) {
                LogUtils.d("FFmpeg", "推流成功,任务ID: " + executionId);
            } else {
                LogUtils.e("FFmpeg", "推流失败,任务ID: " + executionId + ",错误码: " + returnCode);
            }
        });
    }

    public void sendFrame(byte[] data) {
        try {
            if (fileOutputStream == null) {
                fileOutputStream = new FileOutputStream(tempFilePath, true);  // 追加模式
            }
            fileOutputStream.write(data);
            fileOutputStream.flush();
        } catch (IOException e) {
            LogUtils.e("RTMPStreamer", "写入帧数据失败: " + e.getMessage());
        }
    }

    public void stopStreaming() {
        try {
            if (fileOutputStream != null) {
                fileOutputStream.close();
            }
        } catch (IOException e) {
            LogUtils.e("RTMPStreamer", "关闭文件流失败: " + e.getMessage());
        }
        FFmpeg.cancel(); // 取消FFmpeg任务
    }
}

注意事项

  • 延迟: 这种方法会有一定延迟,因为数据先被写入文件再推流。若对延迟要求非常严格,需要考虑其他更底层的方案,如自定义的原生实现。
  • 文件管理: 如果你不希望文件一直增大,可以定期清理或分段写入多个文件。

这个是实现推流的第一步,体验卡,延迟会随着文件的增大而越来越大,所以作为练手版,强烈不建议使用到项目里,这延迟高达几十秒,很阔怕。

第一波操作完美,收工!!!


已发布

分类

,

来自

标签:

评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注