|
|
|
@ -12,6 +12,12 @@ import com.sun.jna.Pointer;
|
|
|
|
import com.sun.jna.ptr.IntByReference;
|
|
|
|
import com.sun.jna.ptr.IntByReference;
|
|
|
|
import jakarta.annotation.Resource;
|
|
|
|
import jakarta.annotation.Resource;
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
|
|
|
import org.bytedeco.ffmpeg.global.avcodec;
|
|
|
|
|
|
|
|
import org.bytedeco.ffmpeg.global.avutil;
|
|
|
|
|
|
|
|
import org.bytedeco.javacv.FFmpegFrameGrabber;
|
|
|
|
|
|
|
|
import org.bytedeco.javacv.FFmpegFrameRecorder;
|
|
|
|
|
|
|
|
import org.bytedeco.javacv.FFmpegLogCallback;
|
|
|
|
|
|
|
|
import org.bytedeco.javacv.Frame;
|
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
|
|
|
|
|
|
import java.io.*;
|
|
|
|
import java.io.*;
|
|
|
|
@ -621,7 +627,7 @@ public class HikControlModuleImpl implements CameraModule {
|
|
|
|
// 通过获取设备时间来判断连接是否有效
|
|
|
|
// 通过获取设备时间来判断连接是否有效
|
|
|
|
HCNetSDK.NET_DVR_TIME deviceTime = new HCNetSDK.NET_DVR_TIME();
|
|
|
|
HCNetSDK.NET_DVR_TIME deviceTime = new HCNetSDK.NET_DVR_TIME();
|
|
|
|
return hcNetsdk.NET_DVR_GetDVRConfig(lUserId, HCNetSDK.NET_DVR_GET_TIMECFG, 0,
|
|
|
|
return hcNetsdk.NET_DVR_GetDVRConfig(lUserId, HCNetSDK.NET_DVR_GET_TIMECFG, 0,
|
|
|
|
deviceTime.getPointer(), deviceTime.size(), new com.sun.jna.ptr.IntByReference());
|
|
|
|
deviceTime.getPointer(), deviceTime.size(), new IntByReference());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
@ -961,10 +967,10 @@ public class HikControlModuleImpl implements CameraModule {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void runGrabberRecorder(PipedInputStream pipedIn) {
|
|
|
|
private void runGrabberRecorder(PipedInputStream pipedIn) {
|
|
|
|
org.bytedeco.ffmpeg.global.avutil.av_log_set_level(org.bytedeco.ffmpeg.global.avutil.AV_LOG_ERROR);
|
|
|
|
avutil.av_log_set_level(avutil.AV_LOG_ERROR);
|
|
|
|
org.bytedeco.javacv.FFmpegLogCallback.set();
|
|
|
|
FFmpegLogCallback.set();
|
|
|
|
org.bytedeco.javacv.FFmpegFrameGrabber grabber = null;
|
|
|
|
FFmpegFrameGrabber grabber = null;
|
|
|
|
org.bytedeco.javacv.FFmpegFrameRecorder recorder = null;
|
|
|
|
FFmpegFrameRecorder recorder = null;
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
// 等待管道有数据(最多等30秒)
|
|
|
|
// 等待管道有数据(最多等30秒)
|
|
|
|
long deadline = System.currentTimeMillis() + 30_000;
|
|
|
|
long deadline = System.currentTimeMillis() + 30_000;
|
|
|
|
@ -976,15 +982,14 @@ public class HikControlModuleImpl implements CameraModule {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
log.info("[Grabber] cameraId={} 首批数据 {} bytes", cameraId, pipedIn.available());
|
|
|
|
log.info("[Grabber] cameraId={} 首批数据 {} bytes", cameraId, pipedIn.available());
|
|
|
|
|
|
|
|
|
|
|
|
grabber = new org.bytedeco.javacv.FFmpegFrameGrabber(pipedIn);
|
|
|
|
grabber = new FFmpegFrameGrabber(pipedIn);
|
|
|
|
grabber.setFormat("mpeg");
|
|
|
|
grabber.setFormat("mpeg");
|
|
|
|
// 减小 probe 参数,避免消费过多数据导致跳帧
|
|
|
|
// probe 参数:给足数据量和时长,避免 probe 阶段读到管道暂时无数据就误判 EOF 导致 grab() 提前返回 null
|
|
|
|
grabber.setOption("probesize", "131072"); // 128KB
|
|
|
|
grabber.setOption("probesize", "5000000"); // 5MB
|
|
|
|
grabber.setOption("analyzeduration", "1000000"); // 1秒
|
|
|
|
grabber.setOption("analyzeduration", "5000000"); // 5秒
|
|
|
|
grabber.setOption("max_analyze_duration", "1000000");
|
|
|
|
grabber.setOption("max_analyze_duration", "5000000");
|
|
|
|
grabber.setOption("err_detect", "ignore_err");
|
|
|
|
grabber.setOption("err_detect", "ignore_err");
|
|
|
|
grabber.setOption("fflags", "nobuffer");
|
|
|
|
// 注意:不能设 fflags=nobuffer / flags=low_delay,否则管道流 probe 时会提前判 EOF
|
|
|
|
grabber.setOption("flags", "low_delay");
|
|
|
|
|
|
|
|
grabber.start();
|
|
|
|
grabber.start();
|
|
|
|
|
|
|
|
|
|
|
|
int w = grabber.getImageWidth(), h = grabber.getImageHeight();
|
|
|
|
int w = grabber.getImageWidth(), h = grabber.getImageHeight();
|
|
|
|
@ -993,9 +998,9 @@ public class HikControlModuleImpl implements CameraModule {
|
|
|
|
int br = grabber.getVideoBitrate() > 0 ? grabber.getVideoBitrate() : 2000000;
|
|
|
|
int br = grabber.getVideoBitrate() > 0 ? grabber.getVideoBitrate() : 2000000;
|
|
|
|
log.info("[Grabber] cameraId={} {}x{} fps={}", cameraId, w, h, fps);
|
|
|
|
log.info("[Grabber] cameraId={} {}x{} fps={}", cameraId, w, h, fps);
|
|
|
|
|
|
|
|
|
|
|
|
recorder = new org.bytedeco.javacv.FFmpegFrameRecorder(rtmpUrl, w, h, ch);
|
|
|
|
recorder = new FFmpegFrameRecorder(rtmpUrl, w, h, ch);
|
|
|
|
recorder.setFormat("flv");
|
|
|
|
recorder.setFormat("flv");
|
|
|
|
recorder.setVideoCodec(org.bytedeco.ffmpeg.global.avcodec.AV_CODEC_ID_H264);
|
|
|
|
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
|
|
|
|
recorder.setVideoBitrate(br);
|
|
|
|
recorder.setVideoBitrate(br);
|
|
|
|
recorder.setFrameRate(fps);
|
|
|
|
recorder.setFrameRate(fps);
|
|
|
|
recorder.setGopSize(Math.max(25, (int) fps));
|
|
|
|
recorder.setGopSize(Math.max(25, (int) fps));
|
|
|
|
@ -1006,7 +1011,7 @@ public class HikControlModuleImpl implements CameraModule {
|
|
|
|
recorder.setVideoOption("ec", "favor_inter");
|
|
|
|
recorder.setVideoOption("ec", "favor_inter");
|
|
|
|
recorder.setVideoOption("err_detect", "ignore_err");
|
|
|
|
recorder.setVideoOption("err_detect", "ignore_err");
|
|
|
|
if (ch > 0) {
|
|
|
|
if (ch > 0) {
|
|
|
|
recorder.setAudioCodec(org.bytedeco.ffmpeg.global.avcodec.AV_CODEC_ID_AAC);
|
|
|
|
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
|
|
|
|
recorder.setSampleRate(grabber.getSampleRate() > 0 ? grabber.getSampleRate() : 8000);
|
|
|
|
recorder.setSampleRate(grabber.getSampleRate() > 0 ? grabber.getSampleRate() : 8000);
|
|
|
|
recorder.setAudioChannels(ch);
|
|
|
|
recorder.setAudioChannels(ch);
|
|
|
|
recorder.setAudioBitrate(grabber.getAudioBitrate() > 0 ? grabber.getAudioBitrate() : 64000);
|
|
|
|
recorder.setAudioBitrate(grabber.getAudioBitrate() > 0 ? grabber.getAudioBitrate() : 64000);
|
|
|
|
@ -1016,7 +1021,7 @@ public class HikControlModuleImpl implements CameraModule {
|
|
|
|
|
|
|
|
|
|
|
|
long fc = 0;
|
|
|
|
long fc = 0;
|
|
|
|
long startMs = System.currentTimeMillis();
|
|
|
|
long startMs = System.currentTimeMillis();
|
|
|
|
org.bytedeco.javacv.Frame frame;
|
|
|
|
Frame frame = null;
|
|
|
|
int errorFrameCount = 0;
|
|
|
|
int errorFrameCount = 0;
|
|
|
|
while (running && (frame = grabber.grab()) != null) {
|
|
|
|
while (running && (frame = grabber.grab()) != null) {
|
|
|
|
if (frame.image != null) {
|
|
|
|
if (frame.image != null) {
|
|
|
|
@ -1101,12 +1106,12 @@ public class HikControlModuleImpl implements CameraModule {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 关闭 FFmpegFrameGrabber */
|
|
|
|
/** 关闭 FFmpegFrameGrabber */
|
|
|
|
private static void closeQuietly(org.bytedeco.javacv.FFmpegFrameGrabber g) {
|
|
|
|
private static void closeQuietly(FFmpegFrameGrabber g) {
|
|
|
|
if (g != null) { try { g.close(); } catch (Exception ignored) {} }
|
|
|
|
if (g != null) { try { g.close(); } catch (Exception ignored) {} }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 关闭 FFmpegFrameRecorder */
|
|
|
|
/** 关闭 FFmpegFrameRecorder */
|
|
|
|
private static void closeQuietly(org.bytedeco.javacv.FFmpegFrameRecorder r) {
|
|
|
|
private static void closeQuietly(FFmpegFrameRecorder r) {
|
|
|
|
if (r != null) { try { r.close(); } catch (Exception ignored) {} }
|
|
|
|
if (r != null) { try { r.close(); } catch (Exception ignored) {} }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|