最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打包、解包的文档和代码。功夫不负有心人,找到不少有价值的文档和代码。参考这些资料,写了H264 RTP打包类、解包类,实现了单个NAL单元包和FU_A分片单元包。对于丢包处理,采用简单的策略:丢弃随后的所有数据包,直到收到关键帧。测试效果还不错,代码贴上来,若能为同道中人借鉴一二,足矣。两个类的使用说明如下(省略了错误处理过程):

DWORD H264SSRC ;

 CH264_RTP_PACK pack ( H264SSRC ) ;

 BYTE *pVideoData ;

 DWORD Size, ts ;

 bool IsEndOfFrame ;

 WORD wLen ;

 pack.Set ( pVideoData, Size, ts, IsEndOfFrame ) ;

 BYTE *pPacket ;

 while ( pPacket = pack.Get ( &wLen ) )

 {

  // rtp packet process

  // ...

 }

HRESULT hr ;

 CH264_RTP_UNPACK unpack ( hr ) ;

 BYTE *pRtpData ;

 WORD inSize;

 int outSize ;

 BYTE *pFrame = unpack.Parse_RTP_Packet ( pRtpData, inSize, &outSize ) ;

 if ( pFrame != NULL )

 {

  // frame process

  // ...

 }

[cpp] view
plain
 copy

  1. //////////////////////////////////////////////////////////////////////////////////////////
  2. // class CH264_RTP_PACK start
  3. class CH264_RTP_PACK
  4. {
  5. #define RTP_VERSION 2
  6. typedef struct NAL_msg_s
  7. {
  8. bool eoFrame ;
  9. unsigned char type;     // NAL type
  10. unsigned char *start;   // pointer to first location in the send buffer
  11. unsigned char *end; // pointer to last location in send buffer
  12. unsigned long size ;
  13. } NAL_MSG_t;
  14. typedef struct
  15. {
  16. //LITTLE_ENDIAN
  17. unsigned short   cc:4;      /* CSRC count                 */
  18. unsigned short   x:1;       /* header extension flag      */
  19. unsigned short   p:1;       /* padding flag               */
  20. unsigned short   v:2;       /* packet type                */
  21. unsigned short   pt:7;      /* payload type               */
  22. unsigned short   m:1;       /* marker bit                 */
  23. unsigned short    seq;      /* sequence number            */
  24. unsigned long     ts;       /* timestamp                  */
  25. unsigned long     ssrc;     /* synchronization source     */
  26. } rtp_hdr_t;
  27. typedef struct tagRTP_INFO
  28. {
  29. NAL_MSG_t   nal;        // NAL information
  30. rtp_hdr_t   rtp_hdr;    // RTP header is assembled here
  31. int hdr_len;            // length of RTP header
  32. unsigned char *pRTP;    // pointer to where RTP packet has beem assembled
  33. unsigned char *start;   // pointer to start of payload
  34. unsigned char *end;     // pointer to end of payload
  35. unsigned int s_bit;     // bit in the FU header
  36. unsigned int e_bit;     // bit in the FU header
  37. bool FU_flag;       // fragmented NAL Unit flag
  38. } RTP_INFO;
  39. public:
  40. CH264_RTP_PACK(unsigned long H264SSRC, unsigned char H264PAYLOADTYPE=96, unsigned short MAXRTPPACKSIZE=1472 )
  41. {
  42. m_MAXRTPPACKSIZE = MAXRTPPACKSIZE ;
  43. if ( m_MAXRTPPACKSIZE > 10000 )
  44. {
  45. m_MAXRTPPACKSIZE = 10000 ;
  46. }
  47. if ( m_MAXRTPPACKSIZE < 50 )
  48. {
  49. m_MAXRTPPACKSIZE = 50 ;
  50. }
  51. memset ( &m_RTP_Info, 0, sizeof(m_RTP_Info) ) ;
  52. m_RTP_Info.rtp_hdr.pt = H264PAYLOADTYPE ;
  53. m_RTP_Info.rtp_hdr.ssrc = H264SSRC ;
  54. m_RTP_Info.rtp_hdr.v = RTP_VERSION ;
  55. m_RTP_Info.rtp_hdr.seq = 0 ;
  56. }
  57. ~CH264_RTP_PACK(void)
  58. {
  59. }
  60. //传入Set的数据必须是一个完整的NAL,起始码为0x00000001。
  61. //起始码之前至少预留10个字节,以避免内存COPY操作。
  62. //打包完成后,原缓冲区内的数据被破坏。
  63. bool Set ( unsigned char *NAL_Buf, unsigned long NAL_Size, unsigned long Time_Stamp, bool End_Of_Frame )
  64. {
  65. unsigned long startcode = StartCode(NAL_Buf) ;
  66. if ( startcode != 0x01000000 )
  67. {
  68. return false ;
  69. }
  70. int type = NAL_Buf[4] & 0x1f ;
  71. if ( type < 1 || type > 12 )
  72. {
  73. return false ;
  74. }
  75. m_RTP_Info.nal.start = NAL_Buf ;
  76. m_RTP_Info.nal.size = NAL_Size ;
  77. m_RTP_Info.nal.eoFrame = End_Of_Frame ;
  78. m_RTP_Info.nal.type = m_RTP_Info.nal.start[4] ;
  79. m_RTP_Info.nal.end = m_RTP_Info.nal.start + m_RTP_Info.nal.size ;
  80. m_RTP_Info.rtp_hdr.ts = Time_Stamp ;
  81. m_RTP_Info.nal.start += 4 ; // skip the syncword
  82. if ( (m_RTP_Info.nal.size + 7) > m_MAXRTPPACKSIZE )
  83. {
  84. m_RTP_Info.FU_flag = true ;
  85. m_RTP_Info.s_bit = 1 ;
  86. m_RTP_Info.e_bit = 0 ;
  87. m_RTP_Info.nal.start += 1 ; // skip NAL header
  88. }
  89. else
  90. {
  91. m_RTP_Info.FU_flag = false ;
  92. m_RTP_Info.s_bit = m_RTP_Info.e_bit = 0 ;
  93. }
  94. m_RTP_Info.start = m_RTP_Info.end = m_RTP_Info.nal.start ;
  95. m_bBeginNAL = true ;
  96. return true ;
  97. }
  98. //循环调用Get获取RTP包,直到返回值为NULL
  99. unsigned char* Get ( unsigned short *pPacketSize )
  100. {
  101. if ( m_RTP_Info.end == m_RTP_Info.nal.end )
  102. {
  103. *pPacketSize = 0 ;
  104. return NULL ;
  105. }
  106. if ( m_bBeginNAL )
  107. {
  108. m_bBeginNAL = false ;
  109. }
  110. else
  111. {
  112. m_RTP_Info.start = m_RTP_Info.end;  // continue with the next RTP-FU packet
  113. }
  114. int bytesLeft = m_RTP_Info.nal.end - m_RTP_Info.start ;
  115. int maxSize = m_MAXRTPPACKSIZE - 12 ;   // sizeof(basic rtp header) == 12 bytes
  116. if ( m_RTP_Info.FU_flag )
  117. maxSize -= 2 ;
  118. if ( bytesLeft > maxSize )
  119. {
  120. m_RTP_Info.end = m_RTP_Info.start + maxSize ;   // limit RTP packetsize to 1472 bytes
  121. }
  122. else
  123. {
  124. m_RTP_Info.end = m_RTP_Info.start + bytesLeft ;
  125. }
  126. if ( m_RTP_Info.FU_flag )
  127. {   // multiple packet NAL slice
  128. if ( m_RTP_Info.end == m_RTP_Info.nal.end )
  129. {
  130. m_RTP_Info.e_bit = 1 ;
  131. }
  132. }
  133. m_RTP_Info.rtp_hdr.m =  m_RTP_Info.nal.eoFrame ? 1 : 0 ; // should be set at EofFrame
  134. if ( m_RTP_Info.FU_flag && !m_RTP_Info.e_bit )
  135. {
  136. m_RTP_Info.rtp_hdr.m = 0 ;
  137. }
  138. m_RTP_Info.rtp_hdr.seq++ ;
  139. unsigned char *cp = m_RTP_Info.start ;
  140. cp -= ( m_RTP_Info.FU_flag ? 14 : 12 ) ;
  141. m_RTP_Info.pRTP = cp ;
  142. unsigned char *cp2 = (unsigned char *)&m_RTP_Info.rtp_hdr ;
  143. cp[0] = cp2[0] ;
  144. cp[1] = cp2[1] ;
  145. cp[2] = ( m_RTP_Info.rtp_hdr.seq >> 8 ) & 0xff ;
  146. cp[3] = m_RTP_Info.rtp_hdr.seq & 0xff ;
  147. cp[4] = ( m_RTP_Info.rtp_hdr.ts >> 24 ) & 0xff ;
  148. cp[5] = ( m_RTP_Info.rtp_hdr.ts >> 16 ) & 0xff ;
  149. cp[6] = ( m_RTP_Info.rtp_hdr.ts >>  8 ) & 0xff ;
  150. cp[7] = m_RTP_Info.rtp_hdr.ts & 0xff ;
  151. cp[8] =  ( m_RTP_Info.rtp_hdr.ssrc >> 24 ) & 0xff ;
  152. cp[9] =  ( m_RTP_Info.rtp_hdr.ssrc >> 16 ) & 0xff ;
  153. cp[10] = ( m_RTP_Info.rtp_hdr.ssrc >>  8 ) & 0xff ;
  154. cp[11] = m_RTP_Info.rtp_hdr.ssrc & 0xff ;
  155. m_RTP_Info.hdr_len = 12 ;
  156. /*!
  157. * /n The FU indicator octet has the following format:
  158. * /n
  159. * /n      +---------------+
  160. * /n MSB  |0|1|2|3|4|5|6|7|  LSB
  161. * /n      +-+-+-+-+-+-+-+-+
  162. * /n      |F|NRI|  Type   |
  163. * /n      +---------------+
  164. * /n
  165. * /n The FU header has the following format:
  166. * /n
  167. * /n      +---------------+
  168. * /n      |0|1|2|3|4|5|6|7|
  169. * /n      +-+-+-+-+-+-+-+-+
  170. * /n      |S|E|R|  Type   |
  171. * /n      +---------------+
  172. */
  173. if ( m_RTP_Info.FU_flag )
  174. {
  175. // FU indicator  F|NRI|Type
  176. cp[12] = ( m_RTP_Info.nal.type & 0xe0 ) | 28 ;  //Type is 28 for FU_A
  177. //FU header     S|E|R|Type
  178. cp[13] = ( m_RTP_Info.s_bit << 7 ) | ( m_RTP_Info.e_bit << 6 ) | ( m_RTP_Info.nal.type & 0x1f ) ; //R = 0, must be ignored by receiver
  179. m_RTP_Info.s_bit = m_RTP_Info.e_bit= 0 ;
  180. m_RTP_Info.hdr_len = 14 ;
  181. }
  182. m_RTP_Info.start = &cp[m_RTP_Info.hdr_len] ;    // new start of payload
  183. *pPacketSize = m_RTP_Info.hdr_len + ( m_RTP_Info.end - m_RTP_Info.start ) ;
  184. return m_RTP_Info.pRTP ;
  185. }
  186. private:
  187. unsigned int StartCode( unsigned char *cp )
  188. {
  189. unsigned int d32 ;
  190. d32 = cp[3] ;
  191. d32 <<= 8 ;
  192. d32 |= cp[2] ;
  193. d32 <<= 8 ;
  194. d32 |= cp[1] ;
  195. d32 <<= 8 ;
  196. d32 |= cp[0] ;
  197. return d32 ;
  198. }
  199. private:
  200. RTP_INFO m_RTP_Info ;
  201. bool m_bBeginNAL ;
  202. unsigned short m_MAXRTPPACKSIZE ;
  203. };
  204. // class CH264_RTP_PACK end
  205. //////////////////////////////////////////////////////////////////////////////////////////
  206. //////////////////////////////////////////////////////////////////////////////////////////
  207. // class CH264_RTP_UNPACK start
  208. class CH264_RTP_UNPACK
  209. {
  210. #define RTP_VERSION 2
  211. #define BUF_SIZE (1024 * 500)
  212. typedef struct
  213. {
  214. //LITTLE_ENDIAN
  215. unsigned short   cc:4;      /* CSRC count                 */
  216. unsigned short   x:1;       /* header extension flag      */
  217. unsigned short   p:1;       /* padding flag               */
  218. unsigned short   v:2;       /* packet type                */
  219. unsigned short   pt:7;      /* payload type               */
  220. unsigned short   m:1;       /* marker bit                 */
  221. unsigned short    seq;      /* sequence number            */
  222. unsigned long     ts;       /* timestamp                  */
  223. unsigned long     ssrc;     /* synchronization source     */
  224. } rtp_hdr_t;
  225. public:
  226. CH264_RTP_UNPACK ( HRESULT &hr, unsigned char H264PAYLOADTYPE = 96 )
  227. : m_bSPSFound(false)
  228. , m_bWaitKeyFrame(true)
  229. , m_bPrevFrameEnd(false)
  230. , m_bAssemblingFrame(false)
  231. , m_wSeq(1234)
  232. , m_ssrc(0)
  233. {
  234. m_pBuf = new BYTE[BUF_SIZE] ;
  235. if ( m_pBuf == NULL )
  236. {
  237. hr = E_OUTOFMEMORY ;
  238. return ;
  239. }
  240. m_H264PAYLOADTYPE = H264PAYLOADTYPE ;
  241. m_pEnd = m_pBuf + BUF_SIZE ;
  242. m_pStart = m_pBuf ;
  243. m_dwSize = 0 ;
  244. hr = S_OK ;
  245. }
  246. ~CH264_RTP_UNPACK(void)
  247. {
  248. delete [] m_pBuf ;
  249. }
  250. //pBuf为H264 RTP视频数据包,nSize为RTP视频数据包字节长度,outSize为输出视频数据帧字节长度。
  251. //返回值为指向视频数据帧的指针。输入数据可能被破坏。
  252. BYTE* Parse_RTP_Packet ( BYTE *pBuf, unsigned short nSize, int *outSize )
  253. {
  254. if ( nSize <= 12 )
  255. {
  256. return NULL ;
  257. }
  258. BYTE *cp = (BYTE*)&m_RTP_Header ;
  259. cp[0] = pBuf[0] ;
  260. cp[1] = pBuf[1] ;
  261. m_RTP_Header.seq = pBuf[2] ;
  262. m_RTP_Header.seq <<= 8 ;
  263. m_RTP_Header.seq |= pBuf[3] ;
  264. m_RTP_Header.ts = pBuf[4] ;
  265. m_RTP_Header.ts <<= 8 ;
  266. m_RTP_Header.ts |= pBuf[5] ;
  267. m_RTP_Header.ts <<= 8 ;
  268. m_RTP_Header.ts |= pBuf[6] ;
  269. m_RTP_Header.ts <<= 8 ;
  270. m_RTP_Header.ts |= pBuf[7] ;
  271. m_RTP_Header.ssrc = pBuf[8] ;
  272. m_RTP_Header.ssrc <<= 8 ;
  273. m_RTP_Header.ssrc |= pBuf[9] ;
  274. m_RTP_Header.ssrc <<= 8 ;
  275. m_RTP_Header.ssrc |= pBuf[10] ;
  276. m_RTP_Header.ssrc <<= 8 ;
  277. m_RTP_Header.ssrc |= pBuf[11] ;
  278. BYTE *pPayload = pBuf + 12 ;
  279. DWORD PayloadSize = nSize - 12 ;
  280. // Check the RTP version number (it should be 2):
  281. if ( m_RTP_Header.v != RTP_VERSION )
  282. {
  283. return NULL ;
  284. }
  285. /*
  286. // Skip over any CSRC identifiers in the header:
  287. if ( m_RTP_Header.cc )
  288. {
  289. long cc = m_RTP_Header.cc * 4 ;
  290. if ( Size < cc )
  291. {
  292. return NULL ;
  293. }
  294. Size -= cc ;
  295. p += cc ;
  296. }
  297. // Check for (& ignore) any RTP header extension
  298. if ( m_RTP_Header.x )
  299. {
  300. if ( Size < 4 )
  301. {
  302. return NULL ;
  303. }
  304. Size -= 4 ;
  305. p += 2 ;
  306. long l = p[0] ;
  307. l <<= 8 ;
  308. l |= p[1] ;
  309. p += 2 ;
  310. l *= 4 ;
  311. if ( Size < l ) ;
  312. {
  313. return NULL ;
  314. }
  315. Size -= l ;
  316. p += l ;
  317. }
  318. // Discard any padding bytes:
  319. if ( m_RTP_Header.p )
  320. {
  321. if ( Size == 0 )
  322. {
  323. return NULL ;
  324. }
  325. long Padding = p[Size-1] ;
  326. if ( Size < Padding )
  327. {
  328. return NULL ;
  329. }
  330. Size -= Padding ;
  331. }*/
  332. // Check the Payload Type.
  333. if ( m_RTP_Header.pt != m_H264PAYLOADTYPE )
  334. {
  335. return NULL ;
  336. }
  337. int PayloadType = pPayload[0] & 0x1f ;
  338. int NALType = PayloadType ;
  339. if ( NALType == 28 ) // FU_A
  340. {
  341. if ( PayloadSize < 2 )
  342. {
  343. return NULL ;
  344. }
  345. NALType = pPayload[1] & 0x1f ;
  346. }
  347. if ( m_ssrc != m_RTP_Header.ssrc )
  348. {
  349. m_ssrc = m_RTP_Header.ssrc ;
  350. SetLostPacket () ;
  351. }
  352. if ( NALType == 0x07 ) // SPS
  353. {
  354. m_bSPSFound = true ;
  355. }
  356. if ( !m_bSPSFound )
  357. {
  358. return NULL ;
  359. }
  360. if ( NALType == 0x07 || NALType == 0x08 ) // SPS PPS
  361. {
  362. m_wSeq = m_RTP_Header.seq ;
  363. m_bPrevFrameEnd = true ;
  364. pPayload -= 4 ;
  365. *((DWORD*)(pPayload)) = 0x01000000 ;
  366. *outSize = PayloadSize + 4 ;
  367. return pPayload ;
  368. }
  369. if ( m_bWaitKeyFrame )
  370. {
  371. if ( m_RTP_Header.m ) // frame end
  372. {
  373. m_bPrevFrameEnd = true ;
  374. if ( !m_bAssemblingFrame )
  375. {
  376. m_wSeq = m_RTP_Header.seq ;
  377. return NULL ;
  378. }
  379. }
  380. if ( !m_bPrevFrameEnd )
  381. {
  382. m_wSeq = m_RTP_Header.seq ;
  383. return NULL ;
  384. }
  385. else
  386. {
  387. if ( NALType != 0x05 ) // KEY FRAME
  388. {
  389. m_wSeq = m_RTP_Header.seq ;
  390. m_bPrevFrameEnd = false ;
  391. return NULL ;
  392. }
  393. }
  394. }
  395. ///////////////////////////////////////////////////////////////
  396. if ( m_RTP_Header.seq != (WORD)( m_wSeq + 1 ) ) // lost packet
  397. {
  398. m_wSeq = m_RTP_Header.seq ;
  399. SetLostPacket () ;
  400. return NULL ;
  401. }
  402. else
  403. {
  404. // 码流正常
  405. m_wSeq = m_RTP_Header.seq ;
  406. m_bAssemblingFrame = true ;
  407. if ( PayloadType != 28 ) // whole NAL
  408. {
  409. *((DWORD*)(m_pStart)) = 0x01000000 ;
  410. m_pStart += 4 ;
  411. m_dwSize += 4 ;
  412. }
  413. else // FU_A
  414. {
  415. if ( pPayload[1] & 0x80 ) // FU_A start
  416. {
  417. *((DWORD*)(m_pStart)) = 0x01000000 ;
  418. m_pStart += 4 ;
  419. m_dwSize += 4 ;
  420. pPayload[1] = ( pPayload[0] & 0xE0 ) | NALType ;
  421. pPayload += 1 ;
  422. PayloadSize -= 1 ;
  423. }
  424. else
  425. {
  426. pPayload += 2 ;
  427. PayloadSize -= 2 ;
  428. }
  429. }
  430. if ( m_pStart + PayloadSize < m_pEnd )
  431. {
  432. CopyMemory ( m_pStart, pPayload, PayloadSize ) ;
  433. m_dwSize += PayloadSize ;
  434. m_pStart += PayloadSize ;
  435. }
  436. else // memory overflow
  437. {
  438. SetLostPacket () ;
  439. return NULL ;
  440. }
  441. if ( m_RTP_Header.m ) // frame end
  442. {
  443. *outSize = m_dwSize ;
  444. m_pStart = m_pBuf ;
  445. m_dwSize = 0 ;
  446. if ( NALType == 0x05 ) // KEY FRAME
  447. {
  448. m_bWaitKeyFrame = false ;
  449. }
  450. return m_pBuf ;
  451. }
  452. else
  453. {
  454. return NULL ;
  455. }
  456. }
  457. }
  458. void SetLostPacket()
  459. {
  460. m_bSPSFound = false ;
  461. m_bWaitKeyFrame = true ;
  462. m_bPrevFrameEnd = false ;
  463. m_bAssemblingFrame = false ;
  464. m_pStart = m_pBuf ;
  465. m_dwSize = 0 ;
  466. }
  467. private:
  468. rtp_hdr_t m_RTP_Header ;
  469. BYTE *m_pBuf ;
  470. bool m_bSPSFound ;
  471. bool m_bWaitKeyFrame ;
  472. bool m_bAssemblingFrame ;
  473. bool m_bPrevFrameEnd ;
  474. BYTE *m_pStart ;
  475. BYTE *m_pEnd ;
  476. DWORD m_dwSize ;
  477. WORD m_wSeq ;
  478. BYTE m_H264PAYLOADTYPE ;
  479. DWORD m_ssrc ;
  480. };
  481. // class CH264_RTP_UNPACK end
  482. //////////////////////////////////////////////////////////////////////////////////////////

【FFMPEG】基于RTP的H264视频数据打包解包类的更多相关文章

  1. (转)基于RTP的H264视频数据打包解包类

    最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打包.解包的文档和代码.功夫不负有心人,找到不少有价值的文档和代码.参考这些资料,写了H264 RTP打包类.解包类,实现 ...

  2. 基于RTP的H264视频数据打包解包类

    from:http://blog.csdn.net/dengzikun/article/details/5807694 最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打 ...

  3. h264_rtp打包解包类及实现demo

    打包头文件: class CH2642Rtp { public: CH2642Rtp(uint32_t ssrc, uint8_t payloadType = 96, uint8_t fps = 25 ...

  4. indows下PHP通过ffmpeg给上传的视频截图详解

    windows下PHP通过ffmpeg给上传的视频截图详解,php_ffmpeg.dll安装下载,找了很久php_ffmpeg.dll的下载地址和应用,发现有用的资源很少,现在问题解决了,贴出来跟大家 ...

  5. Java之集合初探(二)Iterator(迭代器),collections,打包/解包(装箱拆箱),泛型(Generic),comparable接口

    Iterator(迭代器) 所有实现了Collection接口的容器都有一个iterator方法, 用来返回一个实现了Iterator接口的对象 Iterator对象称作迭代器, 用来方便的实现对容器 ...

  6. 07.进程管理+作业控制+文件查找与压缩+文件压缩与打包+tar打包解包+NFS

    进程管理 程序放在磁盘上叫文件,把它复制到内存,并在cpu运行,就叫进程, 进程多少也反映当前运行程序的多少 进程在系统中会为每个进程生成一个进程号,在所有的进程中有一个特殊进程即init进程, 它是 ...

  7. Mtk Android 打包解包*.img

    打包/解包 boot.img, system.img, userdata.img, or recovery.img [DESCRIPTION] MTK codebase编译出来的image必须使用MT ...

  8. 【Unity】AssetBundle的使用——打包/解包

    最近参考了各位大神的资源,初步学习了Unity的资源管理模式,包括在编辑器管理(使用AssetDatabase)和在运行时管理(使用Resources和AssetBundle).在此简单总结运行时用A ...

  9. xpack文件打包解包代码库

    Github ###概述 xpack是一个文件资源打包工具及类库,可以对多文件进行打包解包. 其使用文件名的hash作为索引,建立hash索引表以加速文件查找. ###特性 支持hashid自动解冲突 ...

随机推荐

  1. python内置函数(二)之filter,map,sorted

    filter filter()函数接收一个函数 f 和一个iterable的对象,这个函数 f 的作用是对每个元素进行判断,返回 True或 False,filter()根据判断结果自动过滤掉不符合条 ...

  2. Qt 程序自动重启的实现

    正常退出调用exit() 或quit()就行,想要自已重启可按下面代码: void XXX:onRestart() { //类中调用 qApp->exit(); } 主main函数中处理 int ...

  3. BZOJ 1188 / Luogu P3185 [HNOI2007]分裂游戏 (SG函数)

    题意 有n个格子,标号为0 ~ n-1,每个格子上有若干石子,每次操作可以选一个0 ~ n-2的格子上的一颗石子,分裂为两颗,然后任意放在后面的两个格子内,这两个格子可以相同.求使先手必胜的第一步的方 ...

  4. App自动化-python-Unittest框架

    TestCase: 一段Testcase代码示例: # -*- coding: utf-8 -*- ''' Created on 2019-6-27 @author: adminstrator ''' ...

  5. luogu 4411 [BJWC2010]取数游戏 约数+dp

    不大难的dp,暴力拆一下约数然后按照约数来统计即可. 注意:vector 很慢,所以一定特判一下,如果没有该数,就不要添加. Code: #include <bits/stdc++.h> ...

  6. 洛谷【P2257】 YY的GCD

    出处:http://www.cnblogs.com/peng-ym/p/8652288.html   (  直接去出处那看就好了 ) 题目描述 神犇YY虐完数论后给傻×kAc出了一题 给定N, M,求 ...

  7. java 面试心得总结-BAT、网易

    http://blog.csdn.net/sinat_26812289/article/details/50898693

  8. JAVA的面向对象1

    如何理解面向对象 我们说面向对象具有三大特征:封装性.继承性和多态性,那么我们怎么去理解所谓的封装.继承.多态? 1.封装:功能都给你做好了,你不必去理解它是怎么写出来的,直接使用即可. 如:房子.电 ...

  9. .NetCore 读取配置文件

    1.创建config.json配置,并设置成始终复制 2.需要安装 nuget 包 Microsoft.Extensions.Configuration .Microsoft.Extensions.C ...

  10. mov 与 lea 区别

    转自:https://blog.csdn.net/fengyuanye/article/details/85715565 https://my.oschina.net/guonaihong/blog/ ...