获取视频 RTMP 推流web播放
工作需要研究下市面上显示实时视频方案。这里介绍下RTMP协议。
需求获取USB摄像头,手机谁摄像头。显示到web网页上。
一、 采集摄像头
这个使用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
<!---->
未完待续。。。