1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
String zlmHost = "10.64.5.85"; String zlmApiPort = "180"; String zlmRtmpPort = "11935"; String zlmSecret = "abcd123456qwerty"; String appName = "live";
String streamId = "device_" + deviceCode + "_" + recordTask.getStartTime();
String rtmpPushUrl = String.format("rtmp://%s:%s/%s/%s", zlmHost, zlmRtmpPort, appName, streamId);
private void startRtmpPushTask(String flvUrl, String rtmpPushUrl, String deviceCode, RecordTask recordTask) { new Thread(() -> { FFmpegFrameGrabber grabber = null; FFmpegFrameRecorder recorder = null; try { log.info("开始RTMP推流: {} -> {}", flvUrl, rtmpPushUrl); grabber = createConfiguredGrabber(flvUrl); log.info("FFmpegFrameGrabber配置完成,开始启动..."); grabber.start(); log.info("FFmpegFrameGrabber启动成功"); int width = grabber.getImageWidth(); int height = grabber.getImageHeight(); double frameRate = grabber.getVideoFrameRate(); if (frameRate <= 0) frameRate = 25; log.info("流属性: 宽度={}, 高度={}, 帧率={}", width, height, frameRate); recorder = new FFmpegFrameRecorder(rtmpPushUrl, width, height); recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); recorder.setFormat("flv"); recorder.setFrameRate(frameRate); recorder.setVideoBitrate(2000000); recorder.setPixelFormat(org.bytedeco.ffmpeg.global.avutil.AV_PIX_FMT_YUV420P); recorder.setOption("preset", "fast"); recorder.setOption("profile", "baseline"); recorder.setOption("level", "3.1"); recorder.setOption("rtmp_live", "live"); recorder.setOption("rtmp_buffer", "1000"); if (grabber.getAudioChannels() > 0) { recorder.setAudioChannels(1); recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC); recorder.setSampleRate(44100); recorder.setAudioBitrate(64000); log.info("音频配置: 通道=1, 采样率=44100, 比特率=64000"); } recorder.start(); recordTask.setPushRecorder(recorder); recordTask.setPushGrabber(grabber); Frame firstFrame = grabber.grabFrame(); if (firstFrame != null) { firstFrame.timestamp = 0; recorder.record(firstFrame); recordTask.setFirstFrameSent(true); log.info("第一帧已发送,推流建立"); } long startTime = System.currentTimeMillis(); int frameCount = 1; long frameIntervalMs = (long) (1000.0 / frameRate); long expectedNextFrameTime = startTime + frameIntervalMs; long lastLogTime = startTime; while ("RECORDING".equals(recordTask.getStatus())) { Frame frame = grabber.grabFrame(); if (frame == null) { log.warn("抓取到空帧,可能输入流结束"); break; } long currentTime = System.currentTimeMillis(); if (currentTime >= expectedNextFrameTime) { frame.timestamp = frameCount * 1000000L / (long) frameRate; recorder.record(frame); frameCount++; expectedNextFrameTime = startTime + (frameCount * frameIntervalMs); if (currentTime - lastLogTime > 30000) { long duration = (currentTime - startTime) / 1000; double actualFps = frameCount / (duration + 0.001); log.info("推流进行中: 设备={}, 时长={}秒, 帧数={}, 实际帧率={:.2f}fps", deviceCode, duration, frameCount, actualFps); lastLogTime = currentTime; } } else { long sleepTime = Math.min(expectedNextFrameTime - currentTime, 10); if (sleepTime > 0) { Thread.sleep(sleepTime); } } } long totalDuration = (System.currentTimeMillis() - startTime) / 1000; log.info("推流完成: 设备={}, 总时长={}秒, 总帧数={}, 平均帧率={:.2f}fps", deviceCode, totalDuration, frameCount, frameCount / (totalDuration + 0.001)); } catch (Exception e) { log.error("RTMP推流异常: 设备={}, 错误={}", deviceCode, e.getMessage(), e); } finally { if (recorder != null) { try { recorder.recordSamples(null); recorder.stop(); recorder.release(); } catch (Exception e) { log.error("释放录制器失败", e); } } if (grabber != null) { try { grabber.stop(); grabber.release(); } catch (Exception e) { log.error("释放抓取器失败", e); } } recordTask.setPushRecorder(null); recordTask.setPushGrabber(null); } }, "rtmp-push-" + deviceCode).start(); log.info("RTMP推流任务已启动: 设备={}", deviceCode); }
|