Browse Source

重连问题不太好弄,暂时改为发现网络异常,停止媒体移除缓存

MisterZhang 4 năm trước cách đây
mục cha
commit
e50f1df8d7

+ 1 - 1
pom.xml

@@ -13,7 +13,7 @@
 	<artifactId>EasyMedia</artifactId>
 	<version>0.0.1-SNAPSHOT</version>
 	<name>EasyMedia</name>
-	<description>Demo project for Spring Boot</description>
+	<description>一款简单的流媒体服务</description>
 
 	<properties>
 		<java.version>1.8</java.version>

+ 3 - 3
src/main/java/com/zj/service/MediaService.java

@@ -59,7 +59,7 @@ public class MediaService {
 				MediaTransferFlvByFFmpeg mediaTransferFlvByFFmpeg = (MediaTransferFlvByFFmpeg) mediaConvert;
 				//如果当前已经用javacv,则关闭再重新拉流
 				if(!camera.isEnabledFFmpeg()) {
-					mediaTransferFlvByFFmpeg.stop();
+					mediaTransferFlvByFFmpeg.stopFFmpeg();
 					cameras.remove(camera.getMediaKey());
 					this.playForHttp(camera, ctx);
 				} else {
@@ -107,7 +107,7 @@ public class MediaService {
 				MediaTransferFlvByFFmpeg mediaTransferFlvByFFmpeg = (MediaTransferFlvByFFmpeg) mediaConvert;
 				//如果当前已经用javacv,则关闭再重新拉流
 				if(!camera.isEnabledFFmpeg()) {
-					mediaTransferFlvByFFmpeg.stop();
+					mediaTransferFlvByFFmpeg.stopFFmpeg();
 					cameras.remove(camera.getMediaKey());
 					this.playForWs(camera, ctx);
 				} else {
@@ -203,7 +203,7 @@ public class MediaService {
 				cameras.remove(camera.getMediaKey());
 			} else if (mediaConvert instanceof MediaTransferFlvByFFmpeg) {
 				MediaTransferFlvByFFmpeg mediaTransferFlvByFFmpeg = (MediaTransferFlvByFFmpeg) mediaConvert;
-				mediaTransferFlvByFFmpeg.stop();
+				mediaTransferFlvByFFmpeg.stopFFmpeg();
 				cameras.remove(camera.getMediaKey());
 			}
 		}

+ 38 - 6
src/main/java/com/zj/thread/MediaTransferFlvByFFmpeg.java

@@ -71,9 +71,12 @@ public class MediaTransferFlvByFFmpeg extends MediaTransfer {
 	private Thread outputThread;
 	private Thread listenThread;
 	private boolean running = false; // 启动
-	private boolean enableLog = false;
+	private boolean enableLog = true;
 	
 	private int hcSize, wcSize = 0;
+	
+	//记录当前
+	long currentTimeMillis = System.currentTimeMillis();
 
 	/**
 	 * 用于没有客户端时候的计时
@@ -132,16 +135,16 @@ public class MediaTransferFlvByFFmpeg extends MediaTransfer {
 		this
 		.addArgument("-rtsp_transport").addArgument("tcp")
 		.addArgument("-i").addArgument(camera.getUrl())
-		.addArgument("-max_delay").addArgument("100")
+		.addArgument("-max_delay").addArgument("1")
 //		.addArgument("-strict").addArgument("experimental")
 		.addArgument("-g").addArgument("25")
 		.addArgument("-r").addArgument("25")
 //		.addArgument("-b").addArgument("200000")
 //		.addArgument("-filter_complex").addArgument("setpts='(RTCTIME - RTCSTART) / (TB * 1000000)'")
 		.addArgument("-c:v").addArgument("libx264")
-//		.addArgument("-preset:v").addArgument("ultrafast")
-		.addArgument("-preset:v").addArgument("fast")
-//		.addArgument("-tune:v").addArgument("zerolatency")
+		.addArgument("-preset:v").addArgument("ultrafast")
+//		.addArgument("-preset:v").addArgument("fast")
+		.addArgument("-tune:v").addArgument("zerolatency")
 //		.addArgument("-crf").addArgument("26")
 		.addArgument("-c:a").addArgument("aac")
 //		.addArgument("-qmin").addArgument("28")
@@ -186,6 +189,7 @@ public class MediaTransferFlvByFFmpeg extends MediaTransfer {
 		try {
 			process = new ProcessBuilder(command).start();
 			running = true;
+			listenNetTimeout();
 			dealStream(process);
 			outputData();
 			listenClient();
@@ -293,6 +297,32 @@ public class MediaTransferFlvByFFmpeg extends MediaTransfer {
 		});
 		listenThread.start();
 	}
+	
+	/**
+	 * 监听网络异常超时
+	 */
+	public void listenNetTimeout() {
+		Thread listenNetTimeoutThread = new Thread(new Runnable() {
+			public void run() {
+				while (true) {
+					
+					if((System.currentTimeMillis()-currentTimeMillis) > 15000) {
+						log.info("网络异常超时");
+						MediaService.cameras.remove(camera.getMediaKey());
+						stopFFmpeg();
+						break;
+					}
+					
+					try {
+						Thread.sleep(5000);
+					} catch (InterruptedException e) {
+					}
+				}
+			}
+		});
+		listenNetTimeoutThread.setDaemon(true);
+		listenNetTimeoutThread.start();
+	}
 
 	public static MediaTransferFlvByFFmpeg atPath() {
 		return atPath(null);
@@ -327,6 +357,7 @@ public class MediaTransferFlvByFFmpeg extends MediaTransfer {
 				try {
 					while (running) {
 						line = in.readLine();
+						currentTimeMillis = System.currentTimeMillis();
 						if (line == null) {
 							break;
 						}
@@ -355,6 +386,7 @@ public class MediaTransferFlvByFFmpeg extends MediaTransfer {
 				try {
 					while (running) {
 						line = err.readLine();
+						currentTimeMillis = System.currentTimeMillis();
 						if (line == null) {
 							break;
 						}
@@ -404,7 +436,7 @@ public class MediaTransferFlvByFFmpeg extends MediaTransfer {
 	/**
 	 * 关闭
 	 */
-	public void stop() {
+	public void stopFFmpeg() {
 		this.running = false;
 		try {
 			this.process.destroy();

+ 67 - 48
src/main/java/com/zj/thread/MediaTransferFlvByJavacv.java

@@ -182,7 +182,7 @@ public class MediaTransferFlvByJavacv extends MediaTransfer implements Runnable
 		} catch (Exception e) {
 			MediaService.cameras.remove(camera.getMediaKey());
 			log.error("\r\n{}\r\n启动拉流器失败,网络超时或视频源不可用", camera.getUrl());
-			e.printStackTrace();
+//			e.printStackTrace();
 		}
 		return grabberStatus = false;
 	}
@@ -292,40 +292,26 @@ public class MediaTransferFlvByJavacv extends MediaTransfer implements Runnable
 		//时间戳计算
 		long startTime = 0;
 		long videoTS = 0;
-		long lastTime=0;
 		// 累积延迟计算
-		long latencyDifference = 0;// 累积延迟
-		long lastLatencyDifference = 0;// 当前最新一组gop的延迟
-		long maxLatencyThreshold = 30000000;// 最大延迟阈值,如果lastLatencyDifference-latencyDifference>maxLatencyThreshold,则重启拉流器
-
-		long processTime = 0;// 上一帧处理耗时,用于延迟时间补偿,处理耗时不算进累积延迟
+//		long latencyDifference = 0;// 累积延迟
+//		long lastLatencyDifference = 0;// 当前最新一组gop的延迟
+//		long maxLatencyThreshold = 30000000;// 最大延迟阈值,如果lastLatencyDifference-latencyDifference>maxLatencyThreshold,则重启拉流器
+//		long processTime = 0;// 上一帧处理耗时,用于延迟时间补偿,处理耗时不算进累积延迟
+		
 		for(;running && grabberStatus && recorderStatus;) {
 			
-			lastTime=System.currentTimeMillis();
-			//累积延迟过大,则重新建立连接
-			if (lastLatencyDifference-latencyDifference>maxLatencyThreshold) {
-				// 重置参数
-				recorderStatus = false;
-				try {
-					if (!transferFlag) {
-						grabber.restart(); // grabber.grabFrame() avformat
-					}
-					//装封装模式,延迟很小不需要重启,只需要清空缓存即可
-					grabber.flush();
-					recorderStatus = true;
-					log.warn("\r\n{}\r\n重连成功》》》", camera.getUrl());
-					continue;
-				} catch (IOException e) {
-					log.warn("\r\n{}\r\n重连失败!", camera.getUrl());
-					// 跳出循环,销毁拉流器和录制器
-					break;
-				}
-			}
-
 			try {
 				if(transferFlag) {
 					//转复用
+					long startGrab = System.currentTimeMillis();
 					AVPacket pkt = grabber.grabPacket();
+					if((System.currentTimeMillis() - startGrab) > 5000) {
+//						doReConnect();
+//						continue;
+						log.info("\r\n{}\r\n视频流网络异常>>>", camera.getUrl());
+						closeMedia();
+						break;
+					} 
 					if (null!=pkt&&!pkt.isNull()) {
 						if (startTime == 0) {
 							startTime = System.currentTimeMillis();
@@ -341,7 +327,16 @@ public class MediaTransferFlvByJavacv extends MediaTransfer implements Runnable
 					}
 				}else {
 					//转码
-					Frame frame = grabber.grabFrame();
+					long startGrab = System.currentTimeMillis();
+					Frame frame = grabber.grab();	//这边判断相机断网,正常50左右,断线15000
+					if((System.currentTimeMillis() - startGrab) > 5000) {
+//						doReConnect();
+//						continue;
+						log.info("\r\n{}\r\n视频流网络异常>>>", camera.getUrl());
+						closeMedia();
+						break;
+					} 
+					
 					if (frame != null) {
 						if (startTime == 0) {
 							startTime = System.currentTimeMillis();
@@ -357,32 +352,23 @@ public class MediaTransferFlvByJavacv extends MediaTransfer implements Runnable
 					}
 				}
 			} catch (Exception e) {
-				//log.info("\r\n{}\r\n尝试重连。。。", camera.getUrl());
-				try {
-					Thread.sleep(500);
-				} catch (InterruptedException e1) {
-				}
-				//e.printStackTrace();
+				grabberStatus = false;
+				MediaService.cameras.remove(camera.getMediaKey());
 			} catch (org.bytedeco.javacv.FrameRecorder.Exception e) {
-				//runing = false;
-				log.info("\r\n{}\r\n录制器出现异常。。。", camera.getUrl());
-				e.printStackTrace();
-			}
+				recorderStatus = false;
+				MediaService.cameras.remove(camera.getMediaKey());
+			} 
+			
 			if (bos.size() > 0) {
 				byte[] b = bos.toByteArray();
 				bos.reset();
 
 				// 发送视频到前端
 				sendFrameData(b);
-				
-				//流程耗时记录
-				if(lastTime>0) {
-					processTime=System.currentTimeMillis()-lastTime;
-				}
 			}
 		}
 
-		// close包含stop和release方法。录制文件必须保证最后执行stop()方法
+		//启动失败,直接关闭, close包含stop和release方法。录制文件必须保证最后执行stop()方法
 		try {
 			recorder.close();
 			grabber.close();
@@ -394,7 +380,7 @@ public class MediaTransferFlvByJavacv extends MediaTransfer implements Runnable
 		} catch (IOException e) {
 			e.printStackTrace();
 		} finally {
-			running = false;
+			closeMedia();
 		}
 		log.info("关闭媒体流-javacv,{} ", camera.getUrl());
 	}
@@ -460,8 +446,7 @@ public class MediaTransferFlvByJavacv extends MediaTransfer implements Runnable
 		if (httpClients.isEmpty() && wsClients.isEmpty()) {
 			// 等待20秒还没有客户端,则关闭推流
 			if (noClient > camera.getNoClientsDuration()) {
-				running = false;
-				MediaService.cameras.remove(camera.getMediaKey());
+				closeMedia();
 			} else {
 				noClient += 1000;
 //				log.info("\r\n{}\r\n {} 秒自动关闭推拉流 \r\n", camera.getUrl(), noClientsDuration-noClient);
@@ -489,6 +474,40 @@ public class MediaTransferFlvByJavacv extends MediaTransfer implements Runnable
 		});
 		listenThread.start();
 	}
+	
+	/**
+	 * 重连,目前重连有些问题,停止后时间戳也变化了,发现相机连不上先直接断开,清除缓存,后续再优化
+	 */
+//	private void doReConnect() {
+//		try {
+//			boolean createGrabber = createGrabber();
+//			while (!createGrabber) {
+//				try {
+//					Thread.sleep(5000);
+//				} catch (InterruptedException e) {
+//				}
+//				log.info("\r\n{}\r\n尝试重连>>>", camera.getUrl());
+//				createGrabber = createGrabber();
+//			}
+//			
+//		} finally {
+//			try {
+//				grabber.flush();
+//			} catch (Exception e) {
+//				running = false;
+//				MediaService.cameras.remove(camera.getMediaKey());
+//			}
+//		}
+//		log.info("\r\n{}\r\n重连成功", camera.getUrl());
+//	}
+	
+	/**
+	 * 关闭流媒体
+	 */
+	private void closeMedia() {
+		running = false;
+		MediaService.cameras.remove(camera.getMediaKey());
+	}
 
 	/**
 	 * 新增客户端

+ 1 - 1
src/main/resources/application.properties

@@ -1,5 +1,5 @@
 #版本号
-mediaserver.version = 1.0
+mediaserver.version = 1.1.0
 #web端口
 server.port = 8888
 #流媒体服务端口