C# 客户端接收解析mjpg-streamer视频流
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了C# 客户端接收解析mjpg-streamer视频流,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含5453字,纯文字阅读大概需要8分钟。
内容图文
![C# 客户端接收解析mjpg-streamer视频流](/upload/InfoBanner/zyjiaocheng/854/31bd4252417249cf9997c1d4f879906e.jpg)
最近用wpf做一个树莓派机器人的综合控制端,需要解析机器人摄像头的视频流,树莓派是用mjpg-streamer调用并搭建了视频流服务。
客户端解析mjpg-streamer视频帧的原理是:建立Http长连接,每次接收1024长度的数据,数据流中包含数据头信息和紧跟在数据头信息后的图像帧数据,所以需要先定位数据头信息,头信息中包含图像帧数据的长度,然后从头信息的结尾开始解析图像帧数据,第一次读取的数据中不一定包含完整的图像帧数据,需要从第二次读取的数据中继续解析未完整的数据。
原理参考:https://blog.csdn.net/qingkongyeyue/article/details/52824165
以下为具体代码:
private static readonly string DefaultUserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
public void GetLivingVedio(string requestUrl, Action<byte[]> setFrame)
{
Task.Run(delegate
{
if (string.IsNullOrEmpty(requestUrl))
{
MessageBox.Show("GetLivingVedio url 为空!");
return;
}
try
{
HttpWebRequest request = WebRequest.Create(requestUrl) as HttpWebRequest; ;
//在使用curl做POST的时候, 当要POST的数据大于1024字节的时候, curl并不会直接就发起POST请求, 而是会分为俩步,
//1.发送一个请求, 包含一个Expect: 100 -continue, 询问Server使用愿意接受数据
//2.接收到Server返回的100 - continue应答以后, 才把数据POST给Server
//并不是所有的Server都会正确应答100 -continue, 比如lighttpd, 就会返回417 “Expectation Failed”, 则会造成逻辑出错,,
request.ServicePoint.Expect100Continue = false;
//默认代理
request.UserAgent = DefaultUserAgent;
//ContentType
//request.ContentType = "application/json;charset=utf-8";
request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8";
request.KeepAlive = true;
request.Method = "Get";
request.Timeout = (int)(30 * 1000f); // to ensure no timeout
using (Stream stream = request.GetResponse().GetResponseStream())
{
BinaryReader reader = new BinaryReader(new BufferedStream(stream), new System.Text.ASCIIEncoding());
int headerStart = 0;
int frameStart = 0;
int frameLength = 0;
byte[] frameBuffer = null;
int remainDataInNext = 0;
while (!StopLivingVedio)
{
try
{
byte[] buffer = reader.ReadBytes(1024);
if (remainDataInNext > 0)
{
int locationBuffStart = frameBuffer.Length - remainDataInNext;
if (buffer.Length > remainDataInNext)
{
Array.Copy(buffer, 0, frameBuffer, locationBuffStart, remainDataInNext);
}
else
{
Array.Copy(buffer, 0, frameBuffer, locationBuffStart, buffer.Length);
}
remainDataInNext = remainDataInNext - buffer.Length < 0 ? 0 : remainDataInNext - buffer.Length;
if (remainDataInNext == 0)
{
//Console.WriteLine("frame is ok! {0}", DateTime.Now.ToString("HH:mm:ss.fff"));
if (setFrame != null)
setFrame(frameBuffer);
}
}
else if (LocateHeader(buffer, ref headerStart, ref frameStart, ref frameLength))
{
frameBuffer = new byte[frameLength];
Array.Copy(buffer, frameStart, frameBuffer, 0, buffer.Length - frameStart);
remainDataInNext = frameLength - (buffer.Length - frameStart);
}
}
catch (Exception ex)
{
Console.WriteLine("GetLivingVedio's error:{0}", ex);
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("GetLivingVedio's error:{0}", ex.ToString());
}
Console.WriteLine("exit real time preview");
});
}
/// <summary>
/// 定位buffer中的头信息
/// </summary>
/// <param name="buffer"></param>
/// <param name="headerstart"></param>
/// <param name="framestart"></param>
/// <param name="framelength"></param>
/// <returns></returns>
public bool LocateHeader(byte[] buffer, ref int headerstart, ref int framestart, ref int framelength)
{
bool searchHeaderStartResult = false;
bool searchHeaderEndResult = false;
if (buffer != null && buffer.Length > 0)
{
for (int i = 0; i < buffer.Length; i++)
{
//比较消息头
for (int j = 0; j < this.HeaderStartBuffer.Length; j++)
{
//相等时继续比较,不跳出循环
if ((i + j) < buffer.Length && buffer[i + j] == this.HeaderStartBuffer[j])
{
if (j == 19)
{
headerstart = i;
searchHeaderStartResult = true;
i += 20;
}
}
else
{
break;
}
}
//比较消息结尾
for (int j = 0; j < this.HeaderEndBuffer.Length; j++)
{
//相等时继续比较,不跳出循环
if ((i + j) < buffer.Length && buffer[i + j] == this.HeaderEndBuffer[j])
{
if (j == 3)
{
framestart = i + 4;
searchHeaderEndResult = true;
}
}
else
{
break;
}
}
if (searchHeaderStartResult && searchHeaderEndResult)
{
if (headerstart < framestart)
{
byte[] headerBuffer = new byte[framestart - headerstart];
Array.Copy(buffer, headerstart, headerBuffer, 0, headerBuffer.Length);
string headerString = Encoding.UTF8.GetString(headerBuffer);
int lengthStartIndex = headerString.IndexOf("Content-Length:") + 15;
int lengthEndIndex = headerString.IndexOf("X-Timestamp");
string lengthString = headerString.Substring(lengthStartIndex, lengthEndIndex - lengthStartIndex);
framelength = int.Parse(lengthString.Trim());
}
break;
}
}
}
return searchHeaderStartResult && searchHeaderEndResult;
}
wpf调用:
? private void Window_Loaded(object sender, RoutedEventArgs e)
? ? ? ? {
? ? ? ? ? ? string videoUrl = "http://192.168.1.1:8080/?action=stream";
? ? ? ? ? ? this.ViewModel.GetLivingVedio(videoUrl, displayVedioFrame);
? ? ? ? }
? ? ? ? private void displayVedioFrame(byte[] frameBuffer)
? ? ? ? {
? ? ? ? ? ? this.Dispatcher.Invoke(delegate
? ? ? ? ? ? {
? ? ? ? ? ? ? ? BitmapImage bmp = null;
? ? ? ? ? ? ? ? try
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? bmp = new BitmapImage();
? ? ? ? ? ? ? ? ? ? bmp.BeginInit();
? ? ? ? ? ? ? ? ? ? bmp.StreamSource = new MemoryStream(frameBuffer);
? ? ? ? ? ? ? ? ? ? bmp.EndInit();
? ? ? ? ? ? ? ? ? ? imgLiving.Source = bmp;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? catch (Exception ex)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? Console.WriteLine("displayVedioFrame's error:{0}", ex);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? }
内容总结
以上是互联网集市为您收集整理的C# 客户端接收解析mjpg-streamer视频流全部内容,希望文章能够帮你解决C# 客户端接收解析mjpg-streamer视频流所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。