开发环境:

操作系统:Win10 x64专业版2004

开发工具:VS2019 16.7.2

目标平台:x86

首先去下载IPC SDK(点击下载,需要华为授权账户。)

新建一个WPF的项目,Framework版本为4.7

把下载的sdk压缩包中的windows\output32目录中的HWPuSDK.dll和lib目录中的所有文件,都复制到项目的bin/debug目录中(和生成的exe同级),华为的这个SDK对64位支持不好,使用64位遇到不少问题,最终还是先采用32位的DLL。

项目中对图像的手动处理,经过对比,在Emgu CV和OpenCVSharp4中采用了OpenCVSharp4,个人感觉OpenCVSharp4使用起来更简洁方便。

项目中对视频流的回调手动处理展示,采用WriteableBitmap(参考吕毅大神的《WPF 高性能位图渲染 WriteableBitmap 及其高性能用法示例》),本来想采用D3D这种显卡加速的方法,无奈没有找到相关文章和资料,如果哪位大神有资料,还望告知一下。谢谢!

项目中引用了以下组件

在本次开发中,我们先实现自动预览摄像头视频和手动对摄像头视频流进行处理。

因为SDK自动播放需要传入一个控件的句柄,而WPF中窗体上所有控件的句柄都是窗体本身,所以我们还需要使用WindowsFromHost来使用Winform的一些控件来实现播放句柄的传入。

项目中引用WindowsFromsIntegeration

在项目的MainWindow.xaml中添加三个按钮、两个RadioButton、一个Winform的PictureBox和一个WPF的Image控件。大致布局如下:

详细的xaml代码:

<Window x:Class="HuaWeiCamera.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen"
Loaded="MainWindow_OnLoaded"
Title="MainWindow" Height="800" Width="1200" Closed="MainWindow_OnClosed">
<Grid Margin="0,0,2,0">
<Grid.RowDefinitions>
<RowDefinition Height="60"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<WrapPanel VerticalAlignment="Center">
<StackPanel Margin="30,5,0,0" VerticalAlignment="Center">
<Button Content="预览摄像头" HorizontalAlignment="Center" VerticalAlignment="Center" Width="75" Height="30" Click="ButtonView_OnClick" />
<WrapPanel Margin="0,5,0,0">
<RadioButton Content="自动处理" VerticalAlignment="Center" IsChecked="True" GroupName="PlayMode" x:Name="RadioButtonAuto" />
<RadioButton Content="手动处理" VerticalAlignment="Center" GroupName="PlayMode" x:Name="RadioButtonManual" Margin="10,0,0,0" />
</WrapPanel>
</StackPanel>
<Button x:Name="ButtonSaveOne" Content="抓拍一张" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="30,0,0,0" Width="75" Height="30" IsEnabled="False" Click="ButtonSave_OnClick" />
<Button Content="人脸抓拍" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="30,0,0,0" Width="75" Height="30" />
</WrapPanel>
<WrapPanel Grid.Row="1">
<WindowsFormsHost HorizontalAlignment="Center" Width="1200" Height="700" VerticalAlignment="Center" x:Name="FormsHostVideo">
<wf:PictureBox x:Name="ImagePlay"></wf:PictureBox>
</WindowsFormsHost>
<Image VerticalAlignment="Center" HorizontalAlignment="Center" x:Name="CanvaVideo" Stretch="Fill" Source="{Binding Path=VideoWriteableBitmap}" /> </WrapPanel>
</Grid>
</Window>

在App.cs中定义下日志记录类

    public partial class App : Application
{
public static NLog.Logger NewNLog;
private void App_OnStartup(object sender, StartupEventArgs e)
{
DispatcherUnhandledException += App_DispatcherUnhandledException;
NewNLog = NLog.LogManager.GetLogger("HuaWeiCameraLoger");
}
}

根据华为的《SDC 8.0.1 SDK开发指南》,我们要实现摄像头预览,需要先定义以下几个struct和enum:

sturct:PU_REAL_PLAY_INFO_S(视频实时预览结构体)、PU_TIME_S(时间结构体)

enum:PU_PROTOCOL_TYPE(传输协议类型)、PU_STREAM_TYPE(码流类型)、PU_VIDEO_TYPE(数据流类型)、PU_MEDIA_CRYPTO_TYPE(加密类型)、PU_MEDIA_CALLBACK_TYPE(回调类型)

using System;
using System.Runtime.InteropServices;
using HuaWeiCamera.Enums;
using HuaWeiCamera.Enums.Media;
using HuaWeiCamera.Enums.Video; namespace HuaWeiCamera.Struct
{
/// <summary>
/// 视频实时预览结构体,http://www.cnblogs.com/wdw984
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = )]
public struct PU_REAL_PLAY_INFO_S
{
/// <summary>
/// 设备通道号,一般为101。
/// </summary>
public uint ulChannelId;
/// <summary>
/// 播放窗口句柄,为IntPtr.Zero表示用户自己处理视频数据流,不自动播放视频流
/// </summary>
public IntPtr hPlayWnd;
/// <summary>
/// 码流类型,主码流、子码
/// </summary>
public PU_STREAM_TYPE enStreamType;
/// <summary>
/// 流类型:视频流、音频流、复合流、录 像流、元数据
/// </summary>
public PU_VIDEO_TYPE enVideoType;
/// <summary>
/// 传输协议类型,UDP,TCP
/// </summary>
public PU_PROTOCOL_TYPE enProtocolType;
/// <summary>
/// 回调类型:0:RTP解密1:RTP不解密 2:Frame 3:YUV
/// </summary>
public PU_MEDIA_CALLBACK_TYPE enMediaCallbackType;
/// <summary>
/// 请求端IP,第三方平台可以不填,SDK会 自动获取
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = )]
public string szLocalIp;
/// <summary>
/// 是否保活
/// </summary>
public bool bKeepLive;
/// <summary>
/// 请求预录、录像开始时间(本地时 间)。
/// </summary>
public PU_TIME_S stStartTime;
/// <summary>
/// 请求预录、录像结束时间(本地时 间)。
/// </summary>
public PU_TIME_S stEndTime;
/// <summary>
/// 加密类型,只支持AES加密。
/// </summary>
public PU_MEDIA_CRYPTO_TYPE enMediaCryptoType;
/// <summary>
/// 加密密钥
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = )]
public string szMediaCrypto;
/// <summary>
/// szReserved[0-15]表示组播IP地址
/// szReserved[16-19]表示组播端口
/// szReserved[22]表示智能分析数据打包 格式 0:XML,1:元数据
/// szReserved[23]表示元数据请求类型,取值参考枚举 PU_METADATA_REQUEST_TYPE_E定义
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = )]
public byte[] szReserved;
}
}
namespace HuaWeiCamera.Enums
{
/// <summary>
/// 视频流类型,http://www.cnblogs.com/wdw984
/// </summary>
public enum PU_STREAM_TYPE
{
/// <summary>
/// 视频主码流
/// </summary>
PU_VIDEO_MAIN_STREAM=,
/// <summary>
/// 视频子码流
/// </summary>
PU_VIDEO_SUB_STREAM1,
/// <summary>
/// 视频子码流2(VWareC01 不支持)
/// </summary>
PU_VIDEO_SUB_STREAM2,
/// <summary>
/// 视频子码流3(VWareC01 不支持)
/// </summary>
PU_VIDEO_SUB_STREAM3,
/// <summary>
/// 视频子码流4
/// </summary>
PU_VIDEO_SUB_STREAM4,
/// <summary>
/// 视频子码流5
/// </summary>
PU_VIDEO_SUB_STREAM5,
/// <summary>
/// 预留值
/// </summary>
PU_VIDEO_STREAM_MAX
}
}
namespace HuaWeiCamera.Enums.Video
{
/// <summary>
/// 码流类型,http://www.cnblogs.com/wdw984
/// </summary>
public enum PU_VIDEO_TYPE
{
/// <summary>
/// 视频流
/// </summary>
PU_VIDEO_TYPE_VIDEO = ,
/// <summary>
/// 音频流
/// </summary>
PU_VIDEO_TYPE_AUDIO,
/// <summary>
/// 复合流
/// </summary>
PU_VIDEO_TYPE_MUX,
/// <summary>
/// 录像流
/// </summary>
PU_VIDEO_TYPE_RECORD,
/// <summary>
/// 元数据流
/// </summary>
PU_VIDEO_TYPE_META,
/// <summary>
/// 视频+元数据流
/// </summary>
PU_VIDEO_TYPE_VIDEO_META,
/// <summary>
/// 预留值
/// </summary>
PU_VIDEO_TYPE_MAX
}
}
namespace HuaWeiCamera.Enums
{
/// <summary>
/// 数据传输类型,http://www.cnblogs.com/wdw984
/// </summary>
public enum PU_PROTOCOL_TYPE
{
/// <summary>
/// UDP
/// </summary>
PU_PROTOCOL_TYPE_UDP = ,
/// <summary>
/// TCP
/// </summary>
PU_PROTOCOL_TYPE_TCP,
/// <summary>
/// 组播方式
/// </summary>
PU_PROTOCOL_TYPE_MULTICAST,
/// <summary>
/// 预留值
/// </summary>
PU_PROTOCOL_TYPE_MAX
}
}
namespace HuaWeiCamera.Enums.Media
{
/// <summary>
/// 媒体回调类型,http://www.cnblogs.com/wdw984
/// </summary>
public enum PU_MEDIA_CALLBACK_TYPE
{
/// <summary>
/// RTP包方式
/// </summary>
PU_MEDIA_CALLBACK_TYPE_RTP = ,
/// <summary>
/// RTP包形式,不解密
/// </summary>
PU_MEDIA_CALLBACK_TYPE_RTP_CRYPTO,
/// <summary>
/// 帧回调方式
/// </summary>
PU_MEDIA_CALLBACK_TYPE_FRAME,
/// <summary>
/// YUV方式,Linux不支持
/// </summary>
PU_MEDIA_CALLBACK_TYPE_YUV,
/// <summary>
/// 把RTP包回调给控件方处理方式,Linux不支持
/// </summary>
PU_MEDIA_CALLBACK_TYPE_FOR_STORAGE,
/// <summary>
/// 智能元数据方式
/// </summary>
PU_MEDIA_CALLBACK_TYPE_META_FRAME,
/// <summary>
/// 预留值
/// </summary>
PU_MEDIA_CALLBACK_TYPE_MAX
}
}
using System.Runtime.InteropServices;

namespace HuaWeiCamera.Struct
{
/// <summary>
/// 时间结构体,http://www.cnblogs.com/wdw984
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = )]
public struct PU_TIME_S
{
/// <summary>
/// 年
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = )]
public string szYear;
/// <summary>
/// 月
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = )]
public string szMonth;
/// <summary>
/// 日
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = )]
public string szDay;
/// <summary>
/// 时
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = )]
public string szHour;
/// <summary>
/// 分
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = )]
public string szMinute;
/// <summary>
/// 秒
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = )]
public string szSecond;
}
}

定义一个静态类,用来实现调用SDK和摄像头交互(HuaWeiSDKHelper)

using System;
using System.Runtime.InteropServices;
using HuaWeiCamera.Enums;
using HuaWeiCamera.Enums.SnapShot;
using HuaWeiCamera.Struct; namespace HuaWeiCamera.Class
{
/// <summary>
/// 华为HoloSens SDC二次开发使用,http://www.cnblogs.com/wdw984
/// </summary>
public static class HuaWeiSdkHelper
{
private const string SdkPath= "HWPuSDK.dll";
#region 初始化和登录 /// <summary>
/// 初始化设备
/// </summary>
/// <param name="ulLinkMode">0自动 1手动 3混合模式</param>
/// <param name="szLocalIp">本地IP</param>
/// <param name="ulLocalPort">本地端口</param>
/// <returns></returns>
[DllImport(SdkPath, EntryPoint = "IVS_PU_Init", CharSet = CharSet.Ansi, SetLastError = true, PreserveSig = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool IVS_Pu_Init(uint ulLinkMode, string szLocalIp, uint ulLocalPort);
/// <summary>
/// 远程登录设备
/// </summary>
/// <param name="szLoginIp">设备IP</param>
/// <param name="ulLoginPort">设备端口 6060</param>
/// <param name="szUserName">登录名 ApiAdmin</param>
/// <param name="szPasswd">登录密码 HuaWei123</param>
/// <returns></returns>
[DllImport(SdkPath, EntryPoint = "IVS_PU_Login", CharSet = CharSet.Ansi, SetLastError = true, PreserveSig = true, CallingConvention = CallingConvention.StdCall)]
public static extern uint IVS_PU_Login(string szLoginIp, uint ulLoginPort, string szUserName, string szPasswd); /// <summary>
/// 初始化和登录设备
/// </summary>
/// <param name="sdcIp">SDC设备IP</param>
/// <param name="sdcPort">SDC设备端口</param>
/// <param name="sdcUser">SDC登录用户名</param>
/// <param name="sdcPwd">SDC登录密码</param>
/// <param name="errMsg">失败时的错误信息</param>
/// <param name="ulIdentifyId">登录成功后返回登录句柄</param>
public static void InitAndLogin(string sdcIp,uint sdcPort,string sdcUser,string sdcPwd,out uint ulIdentifyId,out string errMsg)
{
ulIdentifyId = ;
errMsg = "";
//要开启TLS的情况时:初始化调用IVS_PU_InitEx接口,登录调用IVS_PU_Login 接口时端口号设置为6061
if (!IVS_Pu_Init(, "192.168.2.144", ))
{
errMsg=($"设备初始化失败,{GetLastErrorInfo()}");
return;
}
ulIdentifyId = IVS_PU_Login(sdcIp, sdcPort, sdcUser, sdcPwd);
if (ulIdentifyId == )
{
errMsg=$"设备登录失败,{GetLastErrorInfo()}";
}
} #endregion #region 预览相关
/// <summary>
/// 实时预览
/// </summary>
/// <param name="ulIdentifyId">登录成功后返回的用户编号</param>
/// <param name="pstRealPlayInfo">播放结构体</param>
/// <param name="fRealDataCallBack">回调实现播放</param>
/// <param name="pUsrData">传入码流数据 回调函数作为参数</param>
/// <returns></returns>
[DllImport(SdkPath, EntryPoint = "IVS_PU_RealPlay")]
public static extern uint IVS_PU_RealPlay(uint ulIdentifyID, PU_REAL_PLAY_INFO_S[] pstRealPlayInfo, PfRealDataCallBack fRealDataCallBack, ref IntPtr pUsrData); public delegate void PfRealDataCallBack(IntPtr szBuffer, int lSize, IntPtr pUsrData);
/// <summary>
/// 停止实时预览
/// </summary>
/// <param name="ulIdentifyId">登录成功后返回的用户编号</param>
/// <param name="ulRealHandle">实时播放句柄</param>
/// <returns></returns>
[DllImport(SdkPath, EntryPoint = "IVS_PU_StopRealPlay", CharSet = CharSet.Ansi, SetLastError = true, PreserveSig = true, CallingConvention = CallingConvention.StdCall)]
public static extern uint IVS_PU_StopRealPlay(uint ulIdentifyId, uint ulRealHandle);
#endregion #region 错误信息相关 /// <summary>
/// 获取最后一次错误代码
/// </summary>
/// <returns></returns>
[DllImport(SdkPath, EntryPoint = "IVS_PU_GetLastError", CharSet = CharSet.Ansi, SetLastError = true, PreserveSig = true, CallingConvention = CallingConvention.StdCall)]
private static extern int IVS_PU_GetLastError(); /// <summary>
/// 根据错误代码返回错误信息
/// </summary>
/// <param name="ulErrorNo">错误编号</param>
/// <returns></returns>
[DllImport(SdkPath, EntryPoint = "IVS_PU_GetErrorMsg", CharSet = CharSet.Ansi, SetLastError = true, PreserveSig = true, CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr IVS_PU_GetErrorMsg(int ulErrorNo); /// <summary>
/// 返回最后一次错误码和错误信息
/// </summary>
/// <returns></returns>
public static string GetLastErrorInfo()
{
var lastErrorCode = IVS_PU_GetLastError();
var lastErrorMsg = Marshal.PtrToStringAnsi(IVS_PU_GetErrorMsg(lastErrorCode)); return $"错误码:{IVS_PU_GetLastError()},错误信息:{lastErrorMsg}";
} #endregion #region 退出登录 /// <summary>
/// 退出登录
/// </summary>
/// <param name="ulIdentifyId">登录成功后返回的句柄编号</param>
/// <returns></returns>
[DllImport(SdkPath, EntryPoint = "IVS_PU_Logout", CharSet = CharSet.Ansi, SetLastError = true, PreserveSig = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool IVS_PU_Logout(uint ulIdentifyId);
/// <summary>
/// 反注册设备,退出时进行设备释放
/// </summary>
/// <returns></returns>
[DllImport(SdkPath, EntryPoint = "IVS_PU_Cleanup", CharSet = CharSet.Ansi, SetLastError = true, PreserveSig = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool IVS_PU_Cleanup(); #endregion }
}

在MainWindow.cs中我们需要定义一些变量:

        private uint _ulIdentifyId;//登录摄像头后返回的编号
private uint _ulRealHandleId;//调用预览SDK返回的结果值
private static bool _isSave;//是否保存当前帧为图片
private static bool _isExit;//是否退出
private static HuaWeiSdkHelper.PfRealDataCallBack _fedRealPlayCallbackWithYUV;//手动处理摄像头回调时的委托事件
private const uint ByteLength = * * ;//位图的大小
private static readonly VideoYuvModelView VideoYuvModelView = new VideoYuvModelView();//Image的数据源,用来手动处理视频时候展示图像
private IntPtr _videoPlayHandle = IntPtr.Zero;//自动预览时的控件句柄 [DllImport("kernel32.dll")]
private static extern void CopyMemory(IntPtr destination, IntPtr source, uint length);//用来复制内存中的数据

在窗体初始化和加载事件中,我们来初始化一些数据的绑定

public MainWindow()
{
InitializeComponent();
VideoYuvModelView.VideoWriteableBitmap = new WriteableBitmap(, , 96.0, 96.0, PixelFormats.Bgr32, null);//因为摄像头返回的图片大小时1920*1080,所以这里定义的大小要和返回的图片大小一致
} private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
CanvaVideo.DataContext = VideoYuvModelView;//手动处理时,Image控件数据源
_videoPlayHandle = ImagePlay.Handle;//自动处理时,使用Winform的控件句柄
}

预览摄像头按钮事件,中间根据选中的自动处理和手动处理来分别做出不同的相应

#region 视频预览(自动和手动处理视频流)

        private void ButtonView_OnClick(object sender, RoutedEventArgs e)
{
if ( == _ulIdentifyId)
{
//这里通过网络登录到摄像头,具体端口、用户名、密码请参考开发手册
HuaWeiSdkHelper.InitAndLogin("192.168.2.250", , "ApiAdmin", "HuaWei123", out _ulIdentifyId, out string errMsg); if ( == _ulIdentifyId)
{
MessageBox.Show(errMsg);
return;
}
}
var prpInfos = new PU_REAL_PLAY_INFO_S[];
var clientInfo = new PU_REAL_PLAY_INFO_S
{
ulChannelId = ,
hPlayWnd = _videoPlayHandle,
enProtocolType = PU_PROTOCOL_TYPE.PU_PROTOCOL_TYPE_TCP,
enStreamType = PU_STREAM_TYPE.PU_VIDEO_MAIN_STREAM,
enVideoType = PU_VIDEO_TYPE.PU_VIDEO_TYPE_VIDEO,
enMediaCryptoType = PU_MEDIA_CRYPTO_TYPE.PU_MEDIA_CRYPTO_NONE,
enMediaCallbackType = PU_MEDIA_CALLBACK_TYPE.PU_MEDIA_CALLBACK_TYPE_RTP,
szReserved = new byte[],
bKeepLive = true
}; IntPtr pUsrData = (IntPtr)_ulIdentifyId;
if (RadioButtonManual.IsChecked == true)
{
//手动处理视频预览
FormsHostVideo.Visibility = Visibility.Collapsed;
CanvaVideo.Visibility = Visibility.Visible;
clientInfo.hPlayWnd = IntPtr.Zero;
clientInfo.enMediaCallbackType = PU_MEDIA_CALLBACK_TYPE.PU_MEDIA_CALLBACK_TYPE_YUV;
prpInfos[] = clientInfo;
_fedRealPlayCallbackWithYUV = FedRealPlayCallbackWithYUV; //手动处理回调
_ulRealHandleId = HuaWeiSdkHelper.IVS_PU_RealPlay(_ulIdentifyId, prpInfos, _fedRealPlayCallbackWithYUV, ref pUsrData);
if ( == _ulRealHandleId)
{
MessageBox.Show(HuaWeiSdkHelper.GetLastErrorInfo());
} ButtonSaveOne.IsEnabled = true;//点击 抓拍一张 按钮,会把_isSave变量设置为true,从而在回调事件中可以保存当前帧为图片
}
else
{
ButtonSaveOne.IsEnabled = false;
CanvaVideo.Visibility = Visibility.Collapsed;
FormsHostVideo.Visibility = Visibility.Visible;
prpInfos[] = clientInfo;
//传入句柄,自动预览
_ulRealHandleId = HuaWeiSdkHelper.IVS_PU_RealPlay(_ulIdentifyId, prpInfos, null, ref pUsrData);
if ( == _ulRealHandleId)
{
MessageBox.Show(HuaWeiSdkHelper.GetLastErrorInfo());
}
}
} #region 手动解析YUV数据并展示在界面上
private static void FedRealPlayCallbackWithYUV(IntPtr szBuffer, int lSize, IntPtr pUsrData)
{
if (_isExit) return;
try
{ Span<byte> nativeSpan;
unsafe
{
nativeSpan = new Span<byte>(szBuffer.ToPointer(), lSize);
} if (nativeSpan.Length > )
{
#region 处理视频流YUV图像 Mat yuvImg = new Mat( * / , , MatType.CV_8UC1);
Mat rgbImg = new Mat(, , MatType.CV_8UC4); Marshal.Copy(nativeSpan.ToArray(), , yuvImg.Data, nativeSpan.Length);
Cv2.CvtColor(yuvImg, rgbImg, ColorConversionCodes.YUV2RGBA_I420);
Application.Current.Dispatcher?.InvokeAsync(() =>
{
VideoYuvModelView.VideoWriteableBitmap.Lock();
unsafe
{
CopyMemory(VideoYuvModelView.VideoWriteableBitmap.BackBuffer, new IntPtr(rgbImg.DataPointer), ByteLength);
}
VideoYuvModelView.VideoWriteableBitmap.AddDirtyRect(new Int32Rect(, , , ));
VideoYuvModelView.VideoWriteableBitmap.Unlock();
}); if (_isSave)
{
Cv2.ImWrite(Path.Combine($"{AppDomain.CurrentDomain.BaseDirectory}", "jpg",$"{Guid.NewGuid()}.jpg"), rgbImg);
_isSave = false;
} #endregion
}
}
catch (Exception e)
{
App.NewNLog.Error($"解析视频流出错:{e}");
}
}
#endregion #endregion

在程序关闭的时候进行资源释放。

        private void MainWindow_OnClosed(object sender, EventArgs e)
{
_isExit = true;if (_ulRealHandleId > )
{
HuaWeiSdkHelper.IVS_PU_StopRealPlay(_ulIdentifyId, _ulRealHandleId);//停止预览
}
if (_ulIdentifyId > )
{
HuaWeiSdkHelper.IVS_PU_Logout(_ulIdentifyId);//退出登录
}
HuaWeiSdkHelper.IVS_PU_Cleanup();//SDK资源释放
}

具体效果如下:

1、自动预览

2、手动处理

但是这里的YUV回调填充到WriteableBitmap遇到个问题,就是无法填满WriteableBitmap(把WriteableBitmap中的数据保存下来也是和预览的效果一样,估计是填充的算法不对),只能填充一部分,这里涉及到本人的知识盲区,暂时没法解决掉。

3、一帧图像保存为本地图片

至此我们使用C#初步实现了华为IPC摄像头的预览和数据流处理(也可以把处理类型换成视频流,然后存本地视频文件,因为默认时h265编码格式,播放时使用PotPlayer播放器来播放),算是入门了。

下一章我们将实现调用SDK来实现人脸自动抓拍效果。

使用C#对华为IPC摄像头二次开发(一)的更多相关文章

  1. Linux下onvif客户端关于ipc摄像头的搜索

    设备搜索:要访问一个IPC摄像头,或者说要调用IPC摄像头提供的WEB服务接口,就要先知道其IP地址,这就是设备发现的过程,或者叫设备搜索的过程.IPC摄像头用的是239.255.255.250(端口 ...

  2. 基于EasyNVR二次开发实现自己的摄像机IPC/NVR无插件化直播解决方案

    在之前的博客中<基于EasyNVR实现RTSP/Onvif监控摄像头Web无插件化直播监控>,我们已经比较多的描述EasyNVR所实现的功能,这些也在方案地址:http://www.eas ...

  3. 基于EasyNVR摄像机网页无插件直播服务二次开发实现H5播放页面的简单集成方案

    我们通常在构架一套视频SaaS应用的过程中,将平台设计为3层:视频硬件层(视频源).视频能力平台(vPaaS).视频应用平台(vSaaS),视频硬件包括各种IPC.NVR.编码器等视频生成设备,vPa ...

  4. PDA手持终端集成一体打印 二次开发

    PDA手持终端集成一体打印 二次开发支持 VS2008或VS2005开发工具 c#或C++开发语言 Mobile6.5,支持GSM通话,GPRS,EDGE网络;内置wifi,蓝牙,gps商场单品管理小 ...

  5. 基于华为物联网IOT的应用开发 --- 基于.net 的SDK封装

    最近,物联网的概念比较热门,一大批厂商抢着占领物联网的高低,包括有华为物联网.阿里云物联网.腾讯物联网.AWS物联网等等,无法一一列举,一般物联网包含设备侧开发.平台侧开发.应用侧开发,三个部分构成了 ...

  6. 基于EasyNVR摄像机无插件直播方案二次开发实现自己的摄像机IPC-NVR无插件化直播解决方案

    背景介绍 在之前的博客中<基于EasyNVR实现RTSP/Onvif监控摄像头Web无插件化直播监控>,对EasyNVR所实现的功能我们已经有较多描述,这些也在方案地址:http://ww ...

  7. EasyNVR摄像机网页H5全平台无插件直播流媒体播放服务二次开发之接口鉴权示例讲解

    背景需求 EasyNVR的使用者应该都清楚的了解到,EasyNVR一个强大的功能就是可以进行全平台的无插件直播.主要原因在于rtsp协议的视频流(默认是需要插件才可以播放的)经由EasyNVR处理可以 ...

  8. EasyNVR网页H5无插件播放摄像机视频功能二次开发之直播通道接口保活示例代码

    背景需求 随着雪亮工程.明厨亮灶.手机看店.智慧幼儿园监控等行业开始将传统的安防摄像头进行互联网.微信直播,我们知道摄像头直播的春天了.将安防摄像头或NVR上的视频流转成互联网直播常用的RTMP.HT ...

  9. EasyNVR网页Chrome无插件播放摄像机视频功能二次开发之云台控制接口示例代码

    随着多媒体技术和网络通信技术的迅速发展,视频监控技术在电力系统.电信行业.工业监控.工地.城市交通.水利系统.社区安防等领域得到越来越广泛的应用.摄像头直播视频监控通过网络直接连接,可达到的世界任何角 ...

随机推荐

  1. 5.22 noip模拟赛

    本来我是不想写的,无奈不会写.蒟蒻 考场就是想不出来 今天得到了100分额外水过了100分我是真的失败.还有一个根本不会check 感觉自己非常之菜. 这道题是这样的 还行吧比较有意思 首先确立一个真 ...

  2. ORACLE表与表联接的几种方式

    三大表与表联接方式 1.NESTED LOOPS 嵌套循环 2.HASH JOIN 哈希联接 3.SORT MERGE 排序合并联接 1.NESTED LOOPS  嵌套循环 嵌套循环的本质是将外部数 ...

  3. Golang SQL连接池梳理

    目录 一.如何理解数据库连接 二.连接池的工作原理 三.database/sql包结构 四.三个重要的结构体 4.1.DB 4.2.driverConn 4.3.Conn 五.流程梳理 5.1.先获取 ...

  4. JavaScript动画实例:运动的字母特效

    已知圆的坐标方程为: X=R*SIN(θ) Y=R*COS(θ)     (0≤θ≤2π) 给定初始坐标位置(X,Y),按照圆的坐标方程,从角度angle = 0开始,每间隔angleSpeed = ...

  5. 精讲RestTemplate第3篇-GET请求使用方法详解

    本文是精讲RestTemplate第3篇,前篇的blog访问地址如下: 精讲RestTemplate第1篇-在Spring或非Spring环境下如何使用 精讲RestTemplate第2篇-多种底层H ...

  6. 14、Java文件操作stream、File、IO

    1.文件操作涉及到的基本概念 File File类 是文件操作的主要对象中文意义就是 文件 顾名思意 万物皆文件,在计算上看到的所有东西都是文件保存,不管是你的图片.视频.数据库数据等等都是按照基本的 ...

  7. ROS 八叉树地图构建 - 安装 octomap 和 octomap_server 建图包!

    项目要用到八叉树库 Octomap 来构建地图,这里记录下安装.可视化,并启用带颜色的 Octomap 的过程. 一.Apt 安装 Octomap 库 如果你不需要修改源码,可以直接安装编译好的 oc ...

  8. 【Docker】 Error running deviceCreate (CreateSnapDeviceRaw)

    问题详细信息: [root@passport docker]# docker-compose -f docker-compose.yml up -ddocker_db_1_1651de706222 i ...

  9. Java程序员面试必备:Volatile全方位解析

    前言 volatile是Java程序员必备的基础,也是面试官非常喜欢问的一个话题,本文跟大家一起开启vlatile学习之旅,如果有不正确的地方,也麻烦大家指出哈,一起相互学习~ 1.volatile的 ...

  10. notepad++ 设置支持golang语法高亮

    see https://stackoverflow.com/questions/27747457/golang-plugin-on-notepad