工作需要研究下市面上显示实时视频方案。这里介绍下RTMP协议。
一、 采集摄像头
这个使用opencvSharp来采集:
nuget:
var task = Task.Run(() => { var capture = new VideoCapture(0); VideoCaptureProperties captureProperties = new VideoCaptureProperties(); capture.Fps = 30; //苹果测试流 //var capture = new VideoCapture("http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear2/prog_index.m3u8", VideoCaptureAPIs.FFMPEG); if (!capture.IsOpened()) { ShowContent("Failed to open capture"); return; } //capture.Set(captureProperties, 80); var frame = new Mat(); var process = new Process(); while (true) { capture.Read(frame); if (frame.Size().Width > 0 && frame.Size().Height > 0) { HersheyFonts fontFace = new HersheyFonts(); frame.PutText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), new OpenCvSharp.Point(10, 30), fontFace, 1.0, Scalar.Red); //var buffer = frame.ToBytes(); //byte[] bytes = frame.ToBytes(".jpg"); #region 压缩尺寸变小 //Cv2.Resize(frame, frame, new OpenCvSharp.Size(frame.Width / 2, frame.Height / 2)); byte[] bytes = CompressImEncode(frame); //CompressImEncodeNew(frame); // //预览压缩 frame = Mat.FromImageData(bytes); #endregion MatToBitmapShow(frame); MemoryStream memory = new MemoryStream(); memory.Write(bytes, 0, bytes.Length); memory.Write(_delimiter, 0, _delimiter.Length); SendTCP(memory.ToArray()); //Cv2.ImShow("Video", frame); //Cv2.WaitKey(1); // 延时一段时间 Cv2.WaitKey(1); } } });
二、 准备RTMP 流服务器
这里使用 nginx-rtmp-http-flv
worker_processes 1; events { worker_connections 1024; } rtmp { server { listen 1935; application live { live on; ##打开 GOP 缓存,减少首屏等待时间 gop_cache on ; #打开GOP缓存,减少首屏等待时间 record_max_size 1K; #设置录制文件的最大值。 } } } #推流地址:rtmp://192.168.1.194:1935/live/video1 #FLV 播放地址:http://127.0.0.1:8088/flv?port=1935&app=live&stream=video1 http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 8088; server_name localhost; location / { add_header 'Access-Control-Allow-Origin' '*'; root html; index index.html index.htm; } location /live { flv_live on; } location /flv { add_header 'Access-Control-Allow-Origin' '*'; flv_live on; chunked_transfer_encoding on; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
写推流到流媒体服务器:
string rtmp1 = "rtmp://127.0.0.1:1935/live/video1"; string rtmp2 = "rtmp://127.0.0.1/live/test110"; task = Task.Run(() => { // 初始化 FFmpeg 库 var capture = new VideoCapture(0); //var capture = new VideoCapture("http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear2/prog_index.m3u8", VideoCaptureAPIs.FFMPEG); if (!capture.IsOpened()) { ShowContent("Failed to open capture"); return; } var frame = new Mat(); var process = new Process(); process.StartInfo.FileName = "ffmpeg"; //aac 音频 -r 25 帧率25 -acodec aac process.StartInfo.Arguments = "-re -i - -vcodec libx264 -f flv " + rtmp1; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardInput = true; //下面这设置使其后台运行 process.StartInfo.CreateNoWindow = true; process.Start(); while (true) { capture.Read(frame); if (frame.Size().Width > 0 && frame.Size().Height > 0) { HersheyFonts fontFace = new HersheyFonts(); frame.PutText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), new OpenCvSharp.Point(10, 30), fontFace, 1.0, Scalar.Red); var buffer = frame.ToBytes(); process.StandardInput.BaseStream.Write(buffer, 0, buffer.Length); MatToBitmapShow(frame); //Cv2.ImShow("Video", frame); //Cv2.WaitKey(1); } } process.WaitForExit(); });
三、网页播放:
效果:
flv.js demo .mainContainer { display: block; width: 1024px; margin-left: auto; margin-right: auto; } .urlInput { display: block; width: 100%; margin-left: auto; margin-right: auto; margin-top: 8px; margin-bottom: 8px; } .centeredVideo { display: block; width: 100%; height: 576px; margin-left: auto; margin-right: auto; margin-bottom: auto; } .controls { display: block; width: 100%; text-align: left; margin-left: auto; margin-right: auto; }FLV
Your browser is too old which doesn't support HTML5 video.
开始 暂停 停止 跳转 var player = document.getElementById('videoElement'); if (flvjs.isSupported()) { var flvPlayer = flvjs.createPlayer({ type: 'flv', "isLive": true,//= 0.5) {//如果差值大于等于0.5 手动跳帧 这里可根据自身需求来定 // this.player.currentTime = this.player.buffered.end(0);//手动跳帧 // } // } // }, 2000); //2000毫秒执行一次
未完待续。。。