当前位置: 首页 > 编程日记 > 正文

C# 视频监控系列(9):服务器端——数据捕获(抓图 + 录像)

前言

录像功能是监控系统中最重要的功能之一,除了本文的功能实现外,还需要你自己考虑合适的存储策略:存储大小、时间段、存储盘符等。

注意

本系列文章限于学习交流,注重过程,由于涉及公司,所以不提供源代码下载,非常抱歉!!但是请大家放心,核心、实现以及其他能够贴出来的代码我都会贴出来,并且争取尽所能的回答留言里的每一个问题,感谢大家关注,欢迎交流 :)

系列

1.     C# 视频监控系列(1):准备

2.     C# 视频监控系列(2):客户端——封装API

3.     C# 视频监控系列(3):客户端——连接服务器

4.     C# 视频监控系列(4):客户端——音频接收和抓图

5.     C# 视频监控系列(5):客户端——给服务器端发送字符串和录像(数据捕获)

6.     C# 视频监控系列(6):服务器端——封装API(上) [HikServer.dll]

7.     C# 视频监控系列(7):服务器端——封装API(下) [DS40xxSDK.dll]

8.     C# 视频监控系列(8):服务器端——预览和可被客户端连接

9.     C# 视频监控系列(9):服务器端——数据捕获(抓图 + 录像)

推荐文章

1.     《控工安防监控知识论坛》提供海康DS4000M/DS4000H卡在安装驱动时常见问题解答等安防专业知识

正文

一、抓图

这个功能没有在VC++服务器端找到对应的代码,但是GOOGLE到了一段CSDN求助的代码:

int   ret=GetJpegImage(aa,bb,cc,dd);   
  
if(ret==0)   
  {   
  CString   str;   
  str.Format(
"ch%02d_%s.jpg",iLastSelect,csStartTime);   
  FILE   
*pFile=fopen(str.GetBuffer(0),"wb");//Buffer应该是个缓冲区   
  if(pFile)   
  {   
  fwrite(bb,cc,
1,pFile);           //存储图像   
  fclose(pFile);   

另外一段代码:http://topic.csdn.net/t/20060721/09/4894821.html

C#:

            byte[] imageBuf = new byte[704*576*2];

            
int size = 704*576*2;

            HikVisionSDK.GetJpegImage(ChannelHandle, imageBuf, 
out size, 100);

            
using (MemoryStream ms = new MemoryStream(imageBuf))
            {
                Image image 
= Image.FromStream(ms, true);
                image.Save(
"C:\\1.jpg");
            }

注意GetJpegImage的参数说明!!并且请注意,由于这个示例,发现前面的(GetJpegImage/GetOriginalImage)API错误了,请你及时更新!!

public static extern int GetOriginalImage(IntPtr hChannelHandle, byte[] ImageBuf, out int Size);

public static extern int GetJpegImage(IntPtr hChannelHandle, byte[] ImageBuf, out int Size, uint nQuality);

保存为bmp的方法请自行尝试,应该是差不多的: )

二、录像

关于录像的文件总共有三个部分,分别是文件头、数据流和文件尾,这里先给出代码,然后再进行说明。

VC++:

CHKVisionDlg::OnStart()

        for(int i = 0; i < GetTotalDSPs(); i++){
            m_bDspPreset[i]
=TRUE;
            
if(m_bDspPreset[i]){
                
char fileName[256];

                sprintf(fileName, 
"d:\\stream%d_%d.264", i, gFileNum++/GetTotalDSPs());

                gFileHandle[i] 
= _open(fileName, _O_CREAT | _O_BINARY | _O_WRONLY| _O_TRUNC, _S_IREAD | _S_IWRITE);
                
if(gFileHandle[i] == -1){
                    TRACE(
"channel %d file open error\n,i");
                    
return;
                }

                gChannelFrames[i] 
= 0;
                gChannelTotalLength[i] 
= 0;
                gChannelFramesLost[i] 
= 0;
                gChannelOverflow[i] 
= 0;
                gCurrentFileLen[i] 
= 0;

                _write(gFileHandle[i], FileHeader[i], FileHeaderLen);



                
// could not be start again untill stopped first
                
//m_bDspPreset[i] = FALSE;
                gCaptureStartedNum++;
                
// let the threads have chance to run
                
//Sleep(500);
            }else
                gFileHandle[i] 
= -1;
        }

StreamDirectReadCallback

int __cdecl StreamDirectReadCallback(ULONG channelNum,void *DataBuf,DWORD Length,int frameType,void *context)
{
    
//CHKVisionDlg * lpDlg = (CHKVisionDlg*)context;
    
//return lpDlg->ProcCallBack(channelNum, DataBuf, Length, frameType);


    
int i,status=0;
    CString ctip;
    
int nframetype =0;

    
// if cap images we need clean the queue here
//    if (!bCapture)
//        return 0;

     
// no errors
     if(frameType > 0) {
         
if(frameType == PktSysHeader){     
             
// store the file header             
             memcpy(FileHeader[channelNum], DataBuf, Length);
             FileHeaderLen 
= Length;
             TRACE(
"channel %d get the file header !\n",channelNum);
            
         }

         
if(frameType == PktIFrames || frameType ==PktSubIFrames){
             status 
= 1;
         }
         
else{
             status 
= 0;
         }
            
         
if(frameType == PktMotionDetection){
//             m_VideoWin.DrawVect(channelNum, (char *)DataBuf, Length);
             return 0;
         }
         
if(frameType == PktOrigImage){
             
return 0;
         }


     }

     
if(Length == 0){
         TRACE(
"no data ?\n");
         
return 0;
     }

//     if(frameType == PktIFrames){
//         int iii=1;
//     }

    ULONG currentTime 
= timeGetTime();

    gChannelTotalLength[channelNum] 
+= Length;
    gCurrentFileLen[channelNum] 
+= Length;

    
if(currentTime > StartTime+1000){

        CString str,str2;
        str.Format(
"%d", (gChannelTotalLength[dcurrentwin] *8/(currentTime - StartTime)));
        
for(i=0;i<g_nChannelTotal;i++)
            gChannelTotalLength[i] 
= 0;
         StartTime
= currentTime; 
        CHKVisionDlg 
*pMain = (CHKVisionDlg *)AfxGetMainWnd();
         pMain
->GetDlgItem(IDC_BPS)->SetWindowText((LPCTSTR)str);
    }

//    if (m_sframe && channelNum ==0)
//    {
 
//          if((frameType == PktSFrames && nframetype ==4 )||(frameType == PktSysHeader))
//         {
//            MP4_ServerWriteData(channelNum,(unsigned char *)DataBuf, Length,frameType,status);    
//         }
//    }
    
//    MP4_ServerWriteData(channelNum,(unsigned char *)DataBuf, Length,frameType,status);    
    
    
if(frameType ==PktAudioFrames)
    {
        _write(gFileHandleQcif[channelNum],DataBuf,Length);
        MP4_ServerWriteDataEx(channelNum,(unsigned 
char *)DataBuf, Length,frameType,status,1);
        _write(gFileHandle[channelNum], DataBuf, Length);
        MP4_ServerWriteDataEx(channelNum,(unsigned 
char *)DataBuf, Length,frameType,status,0);
        
    }
else if (frameType ==PktSubIFrames || frameType ==PktSubPFrames || frameType == PktSubBBPFrames || frameType == PktSubSysHeader)
    {
        
        _write(gFileHandleQcif[channelNum],DataBuf,Length);
        MP4_ServerWriteDataEx(channelNum,(unsigned 
char *)DataBuf, Length,frameType,status,1);    
    }
else 
    {
        
//_write(gFileHandle[channelNum], DataBuf, Length);
        MP4_ServerWriteDataEx(channelNum,(unsigned char *)DataBuf, Length,frameType,status,0);
    }

    
return 0;
}

CHKVisionDlg::OnStop()

        for(int i = 0; i < GetTotalDSPs(); i++){
            
if(m_bDspPreset[i]){
                ASSERT(gFileHandle[i] 
!= -1);
//                StopVideoCapture(ChannelHandle[i]);
                
//lseek(gFileHandle[i], 0, SEEK_SET);
                
//FRAMES_STATISTICS fs;
                
//GetFramesStatistics(ChannelHandle[i], &fs);
                
//ULONG frames = fs.AudioFrames + fs.VideoFrames;
                
//TRACE("channel %i has %x frames written\n", i, frames);
#define END_CODE 0x00000002
                ULONG endCode 
= END_CODE;
                _write(gFileHandle[i], 
&endCode, sizeof(ULONG));
                _close(gFileHandle[i]);
///add v34
                if (bEncodeCifAndQcif[i])
                    _close(gFileHandleQcif[i]);
                gCaptureStartedNum
--;
            }
        }

代码说明:

1.     从StartCap和StopCap的按钮事件可以看得出主要实现写文件头和文件尾的功能,注意_write函数。

2.     而上一章我们讲到了回调函数StreamDirectReadCallback,主要是将数据写到内存中,从代码能看出回调中是边写内存边写文件的代码,而且输出就是.264文件。由于回调从启动开始(允许被客户端访问),就一直不停的在调用这个回调,根据断点调试可以看得出当frameType == PktSysHeader时表示的就是文件头,并且只执行一次,这样在点击StartCap按钮时就直接将这个保存的文件头的数据写入文件了,用UE打开.264的文件可以发现前几个字符总是以4HKH开头的文件。

3.     注意gFileHandle是一个文件指针数组,文件被打开后回调中就一直往这个文件指针写数据!!

C#:

        //用于存放头文件
        byte[] FileHeader;
        
//文件头长度
        int FileHeaderLen;
        
//是否开始捕获文件 0 未启用 1 启用
        volatile int CaptureState;

        
/// <summary>
        
/// 开始录像
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void btnStart_Click(object sender, EventArgs e)
        {
            
//写入头文件
            using (FileStream fs = new FileStream("C:\\hik.264", FileMode.Create))
            {
                BinaryWriter bw 
= new BinaryWriter(fs);
                bw.Write(FileHeader);
                bw.Flush();
                bw.Close();
            }

            CaptureState 
= 1;
        }

        
uint endCode = 0x00000002;

        
/// <summary>
        
/// 停止录像
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void btnStop_Click(object sender, EventArgs e)
        {
            CaptureState 
= 0;
            
using (FileStream fs = new FileStream("C:\\hik.264", FileMode.Append))
            {
                BinaryWriter bw 
= new BinaryWriter(fs);
                bw.Write(endCode);
                bw.Close();
            }
        }

        
public int STREAM_DIRECT_READ_CALLBACK1(int channelNum, IntPtr DataBuf, int Length, FrameType_t frameType, IntPtr context)
        {
            
//int status = 0;
            
//HikServer.MP4_ServerWriteDataEx(channelNum, DataBuf, Length, (int)frameType, status, 0);
            
//return 0;

            
int status = 0;

            
if (frameType > 0)
            {
                
if (frameType == FrameType_t.PktSysHeader)
                {
                    FileHeader 
= new byte[Length];
                    Marshal.Copy(DataBuf, FileHeader, 
0, Length);
                    FileHeaderLen 
= Length;
                }

                
if (frameType == FrameType_t.PktIFrames || frameType == FrameType_t.PktSubIFrames)
                    status 
= 1;
                
else
                    status 
= 0;

                
if (frameType == FrameType_t.PktMotionDetection || frameType == FrameType_t.PktOrigImage)
                    
return 0;
            }

            
if (Length == 0)
            {
                
//TRACE("no data ?\n");
                return 0;
            }

            
if (frameType == FrameType_t.PktAudioFrames)
            {
                WriterVideoCapture(Length, DataBuf);
                
//写文件
                
//    _write(gFileHandleQcif[channelNum],DataBuf,Length);
                
//HikServer.MP4_ServerWriteDataEx(channelNum, DataBuf, Length, (int)frameType, status, 1);
                
//    _write(gFileHandle[channelNum], DataBuf, Length);
                HikServer.MP4_ServerWriteDataEx(channelNum, DataBuf, Length, (int)frameType, status, 0);
            }
            
else if (frameType == FrameType_t.PktSubIFrames || frameType == FrameType_t.PktSubPFrames || frameType == FrameType_t.PktSubBBPFrames || frameType == FrameType_t.PktSubSysHeader)
            {
                
//    _write(gFileHandleQcif[channelNum],DataBuf,Length);
                HikServer.MP4_ServerWriteDataEx(channelNum, DataBuf, Length, (int)frameType, status, 1);
            }
            
else
            {
                WriterVideoCapture(Length, DataBuf);
                HikServer.MP4_ServerWriteDataEx(channelNum, DataBuf, Length, (
int)frameType, status, 0);
            }

            
return 0;

        }

        
/// <summary>
        
/// 将数据流写入视频文件
        
/// </summary>
        
/// <param name="length"></param>
        
/// <param name="dataBuf"></param>
        private void WriterVideoCapture(int length, IntPtr dataBuf)
        {
            
if (CaptureState == 1)
            {
                
using (FileStream fs = new FileStream("C:\\hik.264", FileMode.Append))
                {
                    BinaryWriter bw 
= new BinaryWriter(fs);

                    
byte[] byteBuf = new byte[length];
                    Marshal.Copy(dataBuf, byteBuf, 
0, length);
                    bw.Write(byteBuf);
                    bw.Flush();
                    bw.Close();
                }
            }
        }

代码说明:

1.     回调函数STREAM_DIRECT_READ_CALLBACK1是在上篇文章的基础上修改的,也主要是参照的VC++的源代码改写的。

2.     CaptureState变量主要用于STREAM_DIRECT_READ_CALLBACK1中控制是否写文件。

3.     btnStart_ClickbtnStop_Click分别代表界面上的开始录像和停止录像按钮。

4.     注意写文件的方式,开始录像用FileMode.Create,持续写入用FileMode.Append。

补充

1.     录像的时候务必考虑单录像文件的大小以及磁盘空间不够的问题,最好还能考虑下分时段监控等。

2.     注意保存文件头的变量FileHeader,如果分文件连续保存的话有可能出现第一个文件能播放,后面的都不能播放了,可能是文件头变量的数据类型问题,你可以换byte[] -> IntPtr保存试试看。

3.     自带的示例里面有播放器极其源码,打开播放器,直接将.264文件拖拽到里面就可以播放了;如果报错那么说明你的录像有问题!!

结束

虽然代码都给出来了,但是里面整个过程还是需要理解的,一定要配合VC++自带的例子进行调试编写。

相关文章:

疫情当下,你是在家里躺着刷抖音?还是在做这些?

2020年本来可以是很开心的一年没想到一开头就给了我们一个重重的一击疫情的出现让我们非常的恐慌新型病毒肺炎让我们无处可躲原来热闹的新年因为疫情让我们逼不得已只能待在家里走亲访友更是不可能的就连原来约好的相亲也泡汤了因为封城、封村、封小区、封路了而这些也只是为了…

代码打补丁的利器——diff和patch

一般来说&#xff0c;如果我们在研发过程中需要对代码进行修改&#xff0c;是不需要通过打补丁的方式的&#xff0c;因为我们可以直接改动文件即可。但是如果针对一款要上线的产品&#xff0c;我们总不能在研发的电脑上编译通过后直接发布到线上的。&#xff08;转载请指明出于…

React Namespaced Components

2019独角兽企业重金招聘Python工程师标准>>> var MyForm React.createClass({...}); var MyForm.Row React.createClass({...}); var MyForm.Label React.createClass({...}); var MyForm.Input React.createClass({...}); This feature is available in v0.11 …

Linux下HOOK动态链接库中API的方法

2012年&#xff0c;我写了一篇介绍Windows系统下Ring3层API的hook方案——《一种注册表沙箱的思路、实现——Hook Nt函数》&#xff0c;其在底层使用了微软的Detours库。5年后&#xff0c;我又遇到这么一个问题&#xff0c;但是系统变成了Linux。我最开始的想法是找一个Linux下…

NAT的配置与相关概念的理解

试验背景&#xff1a;随着接入因特网的计算机数量不断猛增&#xff0c;IPv4版本地址资源也就愈加显得捉襟见肘。好多企业申请的IP地址都是经过子网不断划分得到的。A类&#xff0c;B类地址基本已用完&#xff0c;而一般的用户根本就申请不到整段的公网C类地址。如果&#xff0c…

AAAI 2020论文解读:商汤科技发布新视频语义分割和光流联合学习算法

来源 | Every Frame Counts: Joint Learning of Video Segmentation and Optical Flow编辑 | Carol出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09; 商汤科技研究团队发表论文《Every Frame Counts: Joint Learning of VideoSegmentation and Optical Flo…

互联网+和创业潮,互联网+前提条件是什么?互联网+做什么?

在大众创业&#xff0c;万众创新的大浪下&#xff0c;凭着对新技术的敏感和青春激情&#xff0c;创业新军不断涌现.... 互联网创业浪潮, 如雨后春笋......,互联网渗透每个人的心中。创业不是赶时髦&#xff0c;而是一条非常孤独&#xff0c;艰难的路。实施“互联网&#xff0b;…

C++拾趣——C++11的语法糖auto

C是一种强类型的语言&#xff0c;比如变量a&#xff0c;如果声明它是整型&#xff0c;则之后只能将它作为整型来用。这和其他弱类型的语言有很大的区别&#xff0c;比如python中&#xff0c;我们可以让a在第一行是个整型&#xff0c;第三行是一个字符串。&#xff08;转载请指明…

“数学不行,啥都干不好!”骨灰级程序员:这比努力重要1000倍

之前有很多程序员读者向我们抱怨&#xff1a;1&#xff09;做算法优化时&#xff0c;只能现搬书里的算法&#xff0c;遇到不一样的问题&#xff0c;就不会了。2&#xff09;面试一旦涉及到算法和数据结构&#xff0c;如果数学不行&#xff0c;面试基本就凉凉了。3&#xff09;一…

跳槽 你准备好了吗

“人往高处走”&#xff0c;这固然没有错。但是&#xff0c;说来轻巧的一句话&#xff0c;它却包含了为什么“走”、什么是“高”、怎么“走”、什么时候“走”&#xff0c;以及“走”了以后怎么办等一系列问题。跳槽是一门学问&#xff0c;也是一种策略。“人往高处走”&#…

C++:常类型Const

常类型&#xff1a;使用类型修饰符const说明的类型&#xff0c;常类型的变量或对象成员的值在程序运行期间是不可改变的。 3.10.1 常引用 如果在说明引用时用const修饰&#xff0c;则被说明的引用为常引用。如果用常引用做形参&#xff0c;便不会产生对实参 的不希望的更改。常…

JQuery制作的toolTip,针对图片预览效果

昨天做了一个文字版的toolTip&#xff0c;后来想想现在大家都爱看图&#xff0c;文字未免有点单调了点&#xff0c;那我们就来个图片式的预览。代码比较简单&#xff0c;我就不多说了。 欢迎来到 买礼网 选购礼品&#xff01; 畅游鄂西山水风光尽在 恩施旅游资讯网首先看看调用…

29篇计算机视觉领域论文,篇篇惊艳!内附链接!

作者 | 微软亚洲研究院本文经授权转载自微软研究院AI头条&#xff08;ID&#xff1a;MSRAsia&#xff09;1. Deep High-Resolution Representation Learning for Human Pose Estimation论文链接&#xff1a;https://arxiv.org/pdf/1902.09212.pdf该论文在提出了一个新的网络Hig…

绑定CPU逻辑核心的利器——taskset

在工作中&#xff0c;我们可能遇到这样的需求&#xff1a;如何评估程序在一核和多核下的工作效率差距&#xff1f;最简单的想法是找一台只有一个CPU逻辑核的机器和一台有多个逻辑核的机器。&#xff08;转载请指明出于breaksoftware的csdn博客&#xff09;但是这种方式有明显的…

IDE set arguments

2019独角兽企业重金招聘Python工程师标准>>> code::blocks -> Project -->set programs arguments qtcreater -> Projects --> Build&Run --> Run --> Arguments xcode -> super < -->build-->arguments 转载于:https://my.osch…

2020年AI如何走?Jeff Dean和其他四位“大神”已做预测!

作者 | Khari Johnson译者 | 王艳妮 责编 | 胡巍巍出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;人工智能已经不再是随时准备改变世界的状态&#xff0c;而是已经在改变世界。在迈入2020年这新的一年、以及新的20年代之际&#xff0c;笔者请到了AI方面最…

zookeeper快速入门——简介

在几十年前&#xff0c;一个独立的计算机上往往部署着一套完整的应用系统。当时因为网络稳定性及速度的限制&#xff0c;将相关联的服务部署在一台机器上&#xff0c;让它们使用系统机制通信——比如管道&#xff0c;文件等&#xff0c;往往是最稳定和最高效的。然而随着网络技…

为TextMate扩展全屏功能

今天看代码&#xff0c;感觉TextMate那个窗口太小了点&#xff0c;越看越不爽&#xff0c;就想把它弄成全屏的。于是搜索啊搜索啊搜索&#xff0c;终于让我找到一款很yd的小软件&#xff0c;叫megazoomer&#xff0c; 下载地址是&#xff1a;[url]http://ianhenderson.org/mega…

hdu1406

一道很水很水的题&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;#include<iostream> using namespace std; int main(){int num1,num2,i,k,j,sum,n;while(cin>>n){ while(n--){cin&g…

zookeeper快速入门——部署

zookeeper有两种运行模式&#xff1a;独立模式和仲裁模式。独立模式就是只运行一个Zookeeper Server&#xff0c;这自然没法解决服务崩溃导致系统不可用的问题。仲裁模式就是以集群的方式运行Zookeeper Server&#xff0c;这样在Leader不可用时&#xff0c;集群内部会发起选举&…

2020,人工智能和深度学习未来的五大趋势

来源 | forbes编译 | Shawn编辑 | Carol出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;虽然近年来人工智能经常成为热门议题&#xff0c;但它还远未实现真正的成就。人工智能技术发展的主要障碍在于投资成本&#xff0c;投资成本影响短期内的回报。而当时…

电脑常见故障 1

死机恐怕是所有电脑故障里面最常见的一种了&#xff0c;但是死机的原因是多种多样的。 如果从硬件入手&#xff0c;先是看看机箱里的温度是否很高&#xff0c;要检查CPU的风扇是否正常运转&#xff0c;并要注意电脑的散热问题&#xff1b;其次可检查内存&#xff0c;检查完内存…

linux常用命令-date-clock-hwclock-type-whois--help-man-info-cal

date&#xff1a;时间管理电子表&#xff1a;晶体震荡器 石英震荡器Linux&#xff1a;rtc 硬件时间NTP&#xff1a;网络时间协义硬件时间&#xff08;命令&#xff1a;clock&#xff09;系统时间&#xff08;命令&#xff1a;date&#xff09;type COMMAND 判断命令是内部命令…

内存、性能问题分析的利器——valgraind

valgrind是一个知名的分析软件集。我们可以使用它进行内存、多线程及性能等各种问题的分析。它采用非侵入方式&#xff0c;所谓非侵入方式是指&#xff1a;我们不用在代码中插入分析工具的库。这对于开发者来说是友好的。因为如果要将工具编译到文件中&#xff0c;或者要调用其…

这是我见过最卡通的 Python 算法了,通俗易懂

普通程序员&#xff0c;不学算法&#xff0c;也可以成为大神吗&#xff1f;对不起&#xff0c;这个&#xff0c;绝对不可以。可是算法好难啊~~看两页书就想睡觉……所以就不学了吗&#xff1f;就一直当普通程序员吗&#xff1f;如果有一本算法书&#xff0c;看着很轻松……又有…

WebService(Axis2)视频教程与QQ交流群发布

Axis2是目前比较流行的WebService引擎。WebService被应用在很多不同的场景。例如&#xff0c;可以使用WebService来发布服务端 Java类的方法&#xff0c;以便使用不同的客户端进行调用。这样可以有效地集成多种不同的技术来完成应用系统。WebService还经常被使用在SOA中&#x…

fragment类onresume里面刷新操作处理

今天项目中涉及fragment中嵌套多个fragment&#xff0c;但是要根据tag去展示对应的fragment&#xff0c;而不是默认展示的第一个fragment&#xff0c;如果使用activity很容易想到onpause(),onResume()中进行处理&#xff0c;但是你会发现fragment的onpause和onresume只调用一次…

内存问题分析的利器——valgrind的memcheck

在《内存、性能问题分析的利器——valgrind》一文中我们简单介绍了下valgrind工具集&#xff0c;本文将使用memcheck工具分析各种内存问题。&#xff08;转载请指明出于breaksoftware的csdn博客&#xff09; 本文所有的代码都是使用g -O0 -g mem_error.c -o mem_erro编译&#…

类项目中的配置文件app.config在打包安装后的信息获取的问题

在一个项目中碰到这样的一个问题&#xff0c;做一个WORD插件&#xff0c;功能在类库项目中实现了&#xff0c;配置信息存在类库项目的配置文件app.config中&#xff0c;在进行打包后&#xff0c;获取的配置文件中的DocType节点信息时&#xff0c;使用以下方法 ConfigurationMa…

AAAI 2020论文解读:商汤科技提出新弱监督目标检测框架

来源 | Object Instance Mining for WeaklySupervised Object Detection编辑 | Carol出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;商汤科技视频大数据团队发表论文《Object Instance Mining forWeakly Supervised Object Detection》&#xff0c;该论文…