package com.ard.work.sdk.hb.service; import java.util.Map; import java.util.Optional; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; /** * 相机推流队列管理器(静态版本) * 全局唯一的队列管理器,无需创建实例,直接通过类名调用 * 每个相机(设备ID/通道号)对应独立的阻塞队列,存储待推流的H264数据 */ public class CameraStreamQueueManager { /** * 静态队列容器:Key=相机唯一标识,Value=该相机的H264数据队列 * ConcurrentHashMap保证高并发下的线程安全 */ private static final ConcurrentHashMap> CAMERA_QUEUE_MAP = new ConcurrentHashMap<>(); /** * 每个相机队列的默认容量 */ private static final int DEFAULT_QUEUE_CAPACITY = 10; // 私有化构造方法,禁止创建实例(核心:确保静态单例) private CameraStreamQueueManager() { throw new UnsupportedOperationException("该类为静态工具类,禁止实例化!"); } // ===================== 静态核心操作 ===================== /** * 创建指定相机的独立队列(不存在则创建,已存在则返回现有队列) * @param cameraId 相机唯一标识(不可为空) * @return 该相机的阻塞队列 */ public static BlockingQueue createCameraQueue(String cameraId) { if (cameraId == null || cameraId.trim().isEmpty()) { throw new IllegalArgumentException("相机唯一标识不能为空!"); } // ConcurrentHashMap的原子操作,保证线程安全 return CAMERA_QUEUE_MAP.computeIfAbsent(cameraId.trim(), k -> new LinkedBlockingQueue<>(DEFAULT_QUEUE_CAPACITY)); } /** * 向指定相机的队列中添加H264数据(非阻塞,队列满则返回false) * @param cameraId 相机唯一标识 * @param h264Data H264裸流数据(完整NALU单元) * @return true=入队成功,false=队列满/队列不存在 */ public static boolean offerDataToQueue(String cameraId, byte[] h264Data) { if (h264Data == null || h264Data.length == 0) { return false; } BlockingQueue queue = CAMERA_QUEUE_MAP.get(cameraId); return queue != null && queue.offer(h264Data); } /** * 向指定相机的队列中添加H264数据(阻塞式,队列满则等待超时) * @param cameraId 相机唯一标识 * @param h264Data H264裸流数据 * @param timeout 超时时间(单位:毫秒) * @return true=入队成功,false=超时/队列不存在 * @throws InterruptedException 线程中断异常 */ public static boolean putDataToQueueWithTimeout(String cameraId, byte[] h264Data, long timeout) throws InterruptedException { if (h264Data == null || h264Data.length == 0) { return false; } BlockingQueue queue = CAMERA_QUEUE_MAP.get(cameraId); if (queue == null) { return false; } return queue.offer(h264Data, timeout, TimeUnit.MILLISECONDS); } /** * 从指定相机的队列中获取H264数据(阻塞式,队列为空则等待) * @param cameraId 相机唯一标识 * @return H264数据,队列为空则阻塞直到有数据/线程中断 * @throws InterruptedException 线程中断异常 */ public static byte[] takeDataFromQueue(String cameraId) throws InterruptedException { BlockingQueue queue = CAMERA_QUEUE_MAP.get(cameraId); return queue != null ? queue.take() : null; } /** * 从指定相机的队列中获取H264数据(非阻塞,队列为空则返回null) * @param cameraId 相机唯一标识 * @return H264数据,队列为空/队列不存在则返回null */ public static byte[] pollDataFromQueue(String cameraId) { BlockingQueue queue = CAMERA_QUEUE_MAP.get(cameraId); return queue != null ? queue.poll() : null; } /** * 销毁指定相机的队列(清空数据并从容器中移除) * @param cameraId 相机唯一标识 * @return true=销毁成功,false=队列不存在 */ public static boolean destroyCameraQueue(String cameraId) { if (cameraId == null || cameraId.trim().isEmpty()) { return false; } BlockingQueue queue = CAMERA_QUEUE_MAP.remove(cameraId.trim()); if (queue != null) { queue.clear(); return true; } return false; } // ===================== 静态监控/辅助方法 ===================== /** * 获取指定相机队列的当前数据量 * @param cameraId 相机唯一标识 * @return 队列大小,队列不存在则返回0 */ public static int getQueueSize(String cameraId) { return Optional.ofNullable(CAMERA_QUEUE_MAP.get(cameraId)).map(BlockingQueue::size).orElse(0); } /** * 检查指定相机的队列是否存在 * @param cameraId 相机唯一标识 * @return true=存在,false=不存在 */ public static boolean isQueueExists(String cameraId) { return CAMERA_QUEUE_MAP.containsKey(cameraId); } /** * 获取所有相机队列的信息(用于监控/日志) * @return 队列信息Map:Key=相机ID,Value=队列大小 */ public static Map getAllCameraQueueInfo() { ConcurrentHashMap queueInfoMap = new ConcurrentHashMap<>(); CAMERA_QUEUE_MAP.forEach((cameraId, queue) -> queueInfoMap.put(cameraId, queue.size())); return queueInfoMap; } /** * 清空所有相机队列(慎用,一般用于系统关闭/重置) */ public static void clearAllQueues() { CAMERA_QUEUE_MAP.forEach((cameraId, queue) -> queue.clear()); } }