因为业务需求,有个自己写推流的功能,所以需要通过大疆的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任务
}
}
注意事项
- 延迟: 这种方法会有一定延迟,因为数据先被写入文件再推流。若对延迟要求非常严格,需要考虑其他更底层的方案,如自定义的原生实现。
- 文件管理: 如果你不希望文件一直增大,可以定期清理或分段写入多个文件。
这个是实现推流的第一步,体验卡,延迟会随着文件的增大而越来越大,所以作为练手版,强烈不建议使用到项目里,这延迟高达几十秒,很阔怕。
第一波操作完美,收工!!!
发表回复