1 项目特点
本项目最具亮点之处——简单:
- 学习简单
- 开发简单
- 部署简单
2 实现步骤
- 请参阅本人的这篇文章“JAIN SIP API详解与GB28181服务器实现【保姆级源码教程】http://t.csdnimg.cn/O2Rxi”先实现一个支持GB28181协议的视频预览平台,然后接入真实或虚拟(安卓手机可以通过安装模拟器实现)的网络摄像头,保证平台能通过http-flv地址正常取流预览。
- Java服务开启定时任务,每隔1秒采用ffmpeg抓取一帧图片,图片抓取成功后调用人脸识别算法,成功识别人脸后进行标记并保存标记后的图片。
如果有需求,也可以进行对接消息中间件实现告警推送的扩展。
3 代码实现
-
定时抓图
@Override public BaseResult faceDetection(String streamId) { ScheduledFuture scheduledFuture = ThreadPoolTaskConfig.getScheduledFuture(streamId); if(Objects.nonNull(scheduledFuture)){ log.warn("[FaceServiceImpl] Face detection: {} is running.", streamId); return BaseResult.success("success"); } List<String> playingStreams = redisUtil.getPlayingStreams(); if(!playingStreams.contains(streamId)){ log.error("[FaceDetection] Stream ID: {} inexistence.", streamId); return BaseResult.success("success"); } MediaServerDTO mediaServerDTO = redisUtil.getMediaServerDTO(); String fileName = streamId + ".jpg"; schedulerManager.startPeriod(streamId, () -> { List<String> streams = redisUtil.getPlayingStreams(); if(!streams.contains(streamId)){ schedulerManager.stopSchedule(streamId); TaskContainer.remove(captureFaceSavePath, fileName); } // 抓图 // rtsp://10.192.33.34:554/rtp/34020000001320000001_34020000001320000001 // String streamUrl = String.format("rtsp://%s:%s/%s/%s/", mediaServerDTO.getIp(), "554", "rtp", streamId); // http://10.192.33.34:80/rtp/34020000001320000001_34020000001320000001.live.flv String streamUrl = String.format("http://%s:%s/%s/%s.live.flv", mediaServerDTO.getIp(), mediaServerDTO.getHttpPort(), "rtp", streamId); // 请求截图 log.info("[CaptureTask]: " + fileName); // zlmRestfulUtils.getSnap(mediaServerDTO, streamUrl, 15, 1, captureFaceSavePath, fileName); FaceUtil.capture(ffmpegBinPath, streamUrl, captureFaceSavePath + fileName); // try { // FaceUtil.capture(streamUrl, captureFaceSavePath + fileName); // } catch (IOException e) { // e.printStackTrace(); // } // FaceUtil.capture(); }, 8); Optional<TaskPO> taskDaoById = taskDao.findById(streamId); if(taskDaoById.isPresent()){ TaskPO taskPO = taskDaoById.get(); taskPO.setFaceDetection(true); taskDao.save(taskPO); } TaskContainer.addStream(captureFaceSavePath, fileName); return BaseResult.success("success"); }
-
人脸识别
package com.example.mediasiphttpserver.config; import com.example.mediasiphttpserver.server.face.task.CaptureTask; import org.quartz.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import javax.annotation.PostConstruct; /** * @author yrz * @create 2023/12/20 */ @Configuration public class SchedulerConfig { @Autowired private Scheduler scheduler; @PostConstruct public void scheduleJobs() throws SchedulerException { // 创建第一个JobDetail和Trigger JobDetail jobDetail1 = JobBuilder.newJob(CaptureTask.class) .withIdentity("job1", "group1") .build(); CronTrigger trigger1 = TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1") .withSchedule(CronScheduleBuilder.cronSchedule("0/10 * * * * ?")) .build(); // 将JobDetail和Trigger关联到Scheduler scheduler.scheduleJob(jobDetail1, trigger1); } }
package com.example.mediasiphttpserver.server.face.task; import com.example.mediasiphttpserver.server.face.utils.FaceUtil; import com.example.mediasiphttpserver.server.face.utils.TaskContainer; import lombok.extern.slf4j.Slf4j; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import java.util.HashSet; import java.util.Map; import java.util.Set; /** * @author yrz * @create 2023/12/19 */ @Slf4j public class CaptureTask implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { Set<Map.Entry<String, HashSet<String>>> entries = TaskContainer.getEntries(); for(Map.Entry<String, HashSet<String>> entry : entries){ String captureFaceSavePath = entry.getKey(); HashSet<String> fileNames = entry.getValue(); for(String fileName : fileNames){ FaceUtil.faceDetection(captureFaceSavePath, fileName); } } } }
4 效果展示
-
flv预览后点击人脸任务
-
开启/停止任务
-
查看结果(无人脸被识别到展示默认图片)
有想了解该项目或想要源码的私信我(づ。◕ᴗᴗ◕。)づ