首页 > 其他分享 >mp4v2再学习 -- H264视频编码成MP4文件

mp4v2再学习 -- H264视频编码成MP4文件

时间:2023-04-03 20:01:30浏览次数:60  
标签:int -- MP4Encoder char H264 MP4 nalu size


一、H264视频编码成MP4文件

参看:H264视频编码成MP4文件

参看:mp4v2在VS2010下的编译与在项目中的使用

最近做项目需要将H264文件封装为mp4文件,从网上找到了MP4V2库,下载下来后不知道从何下手,官方网站https://code.google.com/p/mp4v2/在windows下的编译过程介绍的很简短,对刚刚开始使用VS2010做大型项目的人来说,实在是有些无力。于是从网上找到了下面几篇博客文章,亲测可用,留下来以备查看。

(1)mp4v2 库在VS2017下的编译过程

    注:此段内容参考:编译MP4v2

Mp4v2 一开始是与 mpeg4ip 这个开源项目捆绑在一起的,现在已经脱离mpeg4ip以一个单独的库存在着。Mp4v2 库提供了一些 API 用来创建修改 MP4 文件。

源码在 http://mp4v2.googlecode.com/svn/trunk/,首先新建一个文件夹用来导入源码,创建文件夹后右键 SVN checkout(需要预先在电脑上安装 TortoiseSVN 客户端),在 URL  of repository 中填入http://mp4v2.googlecode.com/svn/trunk/ 这个网址,点击ok后导入代码,再把vstudio9.0\libmp4v2\Version.rc 放入 src 文件夹下。


上面的内容其实就是获取 MP4V2 源码。上面两个谷歌网站没有进入,原因你懂的。可从 CSDN 下载。

下载:mp4v2最新源码

mp4v2再学习 -- H264视频编码成MP4文件_ide

然后在进入 vs2013 目录下,用 vs2017 打开 mp4v2.sln 。选择配置为 release win32,成功后,编译 libmp4v2。

在 mp4v2-master\buildwin\lib.vs2013\Win32\Release 下会生成 4 个文件,lbmp4v2.lib、libmp4v2.dll、libmp4v2.pdb、libmp4v2.exp。这样就完成了。

mp4v2再学习 -- H264视频编码成MP4文件_封装_02


mp4v2再学习 -- H264视频编码成MP4文件_封装_03


备注:

1. mp4v2 的源码下载需要用到 SVN 客户端 TortoiseSVN,官方网站上能下载的是 Linux 平台下的代码。

Linux下安装编译之前有讲,参看:mp4v2再学习 -- mp4v2 安装说明
2. 此过程在 VS2017 下打开没有问题。
3. 以后在你的项目中会用到 lbmp4v2.lib、libmp4v2.dll 这两个文件。

上面的操作有几处需要注意的:

(1)首先选择配置为 release win32,这个该如何配置?

配置方法:生成->配置管理器,然后将 libmp4v2 配置改为 Release 

mp4v2再学习 -- H264视频编码成MP4文件_封装_04

mp4v2再学习 -- H264视频编码成MP4文件_#include_05

(2)问题分析

出现 无法打开包括文件: “corecrt.h”

mp4v2再学习 -- H264视频编码成MP4文件_封装_06

解决方法,参看:VS2015无法打开包括文件corecrt.h

简单来说就是按如下图, 把里面的 10.0.15063.0 文件复制一份,重命名成 10.0.10240.0

mp4v2再学习 -- H264视频编码成MP4文件_封装_07

mp4v2再学习 -- H264视频编码成MP4文件_ide_08

(2)mp4v2库在VS2010中的使用

注:此处测试代码参考:H264视频编码成MP4文件,作者代码写的很好,赞一个。此处只是把配置过程再详讲一下。

原文如下:
最近需要将H264视频编码成MP4格式。研究了一下,一种方法是采用ffmpeg库,可以先将H264文件解码,再编码生成MP4文件,但这种方式效率较低,10M的视频可能需要几秒钟才能完成。另一种方式根据MP4文件协议直接将H264包封装成MP4格式,由于是直接基于MP4的封装,因而效率很高。H264可以很方便的封装成FLV文件,但MP4格式格式相对比较复杂,封装起来会比较麻烦。由于没时间研究MP4协议,在Google Code上找到一个开源的MP4编解码库Mp4v2(https://code.google.com/p/mp4v2/),通过Mp4v2可以很方便的将H264编码成MP4格式文件。为了方便使用,基于该库封装了一个MP4Encoder类,MP4Encoder封装的接口如下。目前仅支持将H264文件或数据帧编码成MP4文件。

[cpp]  view plain  copy


  1. class MP4Encoder    
  2. {    
  3. public:    
  4. void);    
  5. void);    
  6. public:    
  7. // open or creat a mp4 file.    
  8. const char *fileName,int width,int height,int timeScale = 90000,int frameRate = 25);    
  9. // wirte 264 metadata in mp4 file.    
  10. bool Write264Metadata(MP4FileHandle hMp4File,LPMP4ENC_Metadata lpMetadata);    
  11. // wirte 264 data, data can contain  multiple frame.    
  12. int WriteH264Data(MP4FileHandle hMp4File,const unsigned char* pData,int size);     
  13. // close mp4 file.    
  14. void CloseMP4File(MP4FileHandle hMp4File);    
  15. // convert H264 file to mp4 file.    
  16. // no need to call CreateMP4File and CloseMP4File,it will create/close mp4 file automaticly.    
  17. bool WriteH264File(const char* pFile264,const char* pFileMp4);    
  18. // Prase H264 metamata from H264 data frame    
  19. static bool PraseMetadata(const unsigned char* pData,int size,MP4ENC_Metadata &metadata);    
  20. };     

客户端调用示例代码:

[cpp]  view plain  copy


  1. #include <stdio.h>    
  2. #include "MP4Encoder.h"    
  3.     
  4. int main(int argc, char** argv)    
  5. {    
  6.     MP4Encoder mp4Encoder;    
  7. // convert H264 file to mp4 file    
  8. "test.264","test.mp4");    
  9. }    

MP4Encoder的完整代码如下:

[cpp]  view plain  copy


  1. /********************************************************************  
  2. filename:   MP4Encoder.h 
  3. created:    2013-04-16 
  4. author:     firehood  
  5. purpose:    MP4编码器,基于开源库mp4v2实现(https://code.google.com/p/mp4v2/)。 
  6. *********************************************************************/    
  7. #pragma once    
  8. #include "mp4v2\mp4v2.h"    
  9.     
  10. // NALU单元    
  11. typedef struct _MP4ENC_NaluUnit    
  12. {    
  13. int type;    
  14. int size;    
  15. char *data;    
  16. }MP4ENC_NaluUnit;    
  17.     
  18. typedef struct _MP4ENC_Metadata    
  19. {    
  20. // video, must be h264 type    
  21. int    nSpsLen;    
  22. char   Sps[1024];    
  23. int    nPpsLen;    
  24. char   Pps[1024];    
  25.     
  26. } MP4ENC_Metadata,*LPMP4ENC_Metadata;    
  27.     
  28. class MP4Encoder    
  29. {    
  30. public:    
  31. void);    
  32. void);    
  33. public:    
  34. // open or creat a mp4 file.    
  35. const char *fileName,int width,int height,int timeScale = 90000,int frameRate = 25);    
  36. // wirte 264 metadata in mp4 file.    
  37. bool Write264Metadata(MP4FileHandle hMp4File,LPMP4ENC_Metadata lpMetadata);    
  38. // wirte 264 data, data can contain  multiple frame.    
  39. int WriteH264Data(MP4FileHandle hMp4File,const unsigned char* pData,int size);     
  40. // close mp4 file.    
  41. void CloseMP4File(MP4FileHandle hMp4File);    
  42. // convert H264 file to mp4 file.    
  43. // no need to call CreateMP4File and CloseMP4File,it will create/close mp4 file automaticly.    
  44. bool WriteH264File(const char* pFile264,const char* pFileMp4);    
  45. // Prase H264 metamata from H264 data frame    
  46. static bool PraseMetadata(const unsigned char* pData,int size,MP4ENC_Metadata &metadata);    
  47. private:    
  48. // read one nalu from H264 data buffer    
  49. static int ReadOneNaluFromBuf(const unsigned char *buffer,unsigned int nBufferSize,unsigned int offSet,MP4ENC_NaluUnit &nalu);    
  50. private:    
  51. int m_nWidth;    
  52. int m_nHeight;    
  53. int m_nFrameRate;    
  54. int m_nTimeScale;    
  55.     MP4TrackId m_videoId;    
  56. };     

MP4Encoder.cpp

[cpp]  view plain  copy


  1. /********************************************************************  
  2. filename:   MP4Encoder.cpp 
  3. created:    2013-04-16 
  4. author:     firehood  
  5. purpose:    MP4编码器,基于开源库mp4v2实现(https://code.google.com/p/mp4v2/)。 
  6. *********************************************************************/    
  7. #include "MP4Encoder.h"    
  8. #include <string.h>    
  9.     
  10. #define BUFFER_SIZE  (1024*1024)    
  11.     
  12. MP4Encoder::MP4Encoder(void):    
  13. m_videoId(NULL),    
  14. m_nWidth(0),    
  15. m_nHeight(0),    
  16. m_nTimeScale(0),    
  17. m_nFrameRate(0)    
  18. {    
  19. }    
  20.     
  21. MP4Encoder::~MP4Encoder(void)    
  22. {    
  23. }    
  24.     
  25. MP4FileHandle MP4Encoder::CreateMP4File(const char *pFileName,int width,int height,int timeScale/* = 90000*/,int frameRate/* = 25*/)    
  26. {    
  27. if(pFileName == NULL)    
  28.     {    
  29. return false;    
  30.     }    
  31. // create mp4 file    
  32.     MP4FileHandle hMp4file = MP4Create(pFileName);    
  33. if (hMp4file == MP4_INVALID_FILE_HANDLE)    
  34.     {    
  35. "ERROR:Open file fialed.\n");    
  36. return false;    
  37.     }    
  38.     m_nWidth = width;    
  39.     m_nHeight = height;    
  40.     m_nTimeScale = 90000;    
  41.     m_nFrameRate = 25;    
  42.     MP4SetTimeScale(hMp4file, m_nTimeScale);    
  43. return hMp4file;    
  44. }    
  45.     
  46. bool MP4Encoder::Write264Metadata(MP4FileHandle hMp4File,LPMP4ENC_Metadata lpMetadata)    
  47. {    
  48.     m_videoId = MP4AddH264VideoTrack    
  49.         (hMp4File,     
  50.         m_nTimeScale,     
  51.         m_nTimeScale / m_nFrameRate,     
  52. // width    
  53. // height    
  54. // sps[1] AVCProfileIndication    
  55. // sps[2] profile_compat    
  56. // sps[3] AVCLevelIndication    
  57. // 4 bytes length before each NAL unit    
  58. if (m_videoId == MP4_INVALID_TRACK_ID)    
  59.     {    
  60. "add video track failed.\n");    
  61. return false;    
  62.     }    
  63. //  Simple Profile @ Level 3    
  64.     
  65. // write sps    
  66.     MP4AddH264SequenceParameterSet(hMp4File,m_videoId,lpMetadata->Sps,lpMetadata->nSpsLen);    
  67.     
  68. // write pps    
  69.     MP4AddH264PictureParameterSet(hMp4File,m_videoId,lpMetadata->Pps,lpMetadata->nPpsLen);    
  70.     
  71. return true;    
  72. }    
  73.     
  74. int MP4Encoder::WriteH264Data(MP4FileHandle hMp4File,const unsigned char* pData,int size)    
  75. {    
  76. if(hMp4File == NULL)    
  77.     {    
  78. return -1;    
  79.     }    
  80. if(pData == NULL)    
  81.     {    
  82. return -1;    
  83.     }    
  84.     MP4ENC_NaluUnit nalu;    
  85. int pos = 0, len = 0;    
  86. while (len = ReadOneNaluFromBuf(pData,size,pos,nalu))    
  87.     {    
  88. if(nalu.type == 0x07) // sps    
  89.         {    
  90. // 添加h264 track        
  91.             m_videoId = MP4AddH264VideoTrack    
  92.                 (hMp4File,     
  93.                 m_nTimeScale,     
  94.                 m_nTimeScale / m_nFrameRate,     
  95. // width    
  96. // height    
  97. // sps[1] AVCProfileIndication    
  98. // sps[2] profile_compat    
  99. // sps[3] AVCLevelIndication    
  100. // 4 bytes length before each NAL unit    
  101. if (m_videoId == MP4_INVALID_TRACK_ID)    
  102.             {    
  103. "add video track failed.\n");    
  104. return 0;    
  105.             }    
  106. //  Simple Profile @ Level 3    
  107.     
  108.             MP4AddH264SequenceParameterSet(hMp4File,m_videoId,nalu.data,nalu.size);    
  109.         }    
  110. else if(nalu.type == 0x08) // pps    
  111.         {    
  112.             MP4AddH264PictureParameterSet(hMp4File,m_videoId,nalu.data,nalu.size);    
  113.         }    
  114. else    
  115.         {    
  116. int datalen = nalu.size+4;    
  117. char *data = new unsigned char[datalen];    
  118. // MP4 Nalu前四个字节表示Nalu长度    
  119.             data[0] = nalu.size>>24;    
  120.             data[1] = nalu.size>>16;    
  121.             data[2] = nalu.size>>8;    
  122.             data[3] = nalu.size&0xff;    
  123.             memcpy(data+4,nalu.data,nalu.size);    
  124. if(!MP4WriteSample(hMp4File, m_videoId, data, datalen,MP4_INVALID_DURATION, 0, 1))    
  125.             {    
  126. return 0;    
  127.             }    
  128. delete[] data;    
  129.         }    
  130.             
  131.         pos += len;    
  132.     }    
  133. return pos;    
  134. }    
  135.     
  136. int MP4Encoder::ReadOneNaluFromBuf(const unsigned char *buffer,unsigned int nBufferSize,unsigned int offSet,MP4ENC_NaluUnit &nalu)    
  137. {    
  138. int i = offSet;    
  139. while(i<nBufferSize)    
  140.     {    
  141. if(buffer[i++] == 0x00 &&    
  142.             buffer[i++] == 0x00 &&    
  143.             buffer[i++] == 0x00 &&    
  144.             buffer[i++] == 0x01    
  145.             )    
  146.         {    
  147. int pos = i;    
  148. while (pos<nBufferSize)    
  149.             {    
  150. if(buffer[pos++] == 0x00 &&    
  151.                     buffer[pos++] == 0x00 &&    
  152.                     buffer[pos++] == 0x00 &&    
  153.                     buffer[pos++] == 0x01    
  154.                     )    
  155.                 {    
  156. break;    
  157.                 }    
  158.             }    
  159. if(pos == nBufferSize)    
  160.             {    
  161.                 nalu.size = pos-i;      
  162.             }    
  163. else    
  164.             {    
  165.                 nalu.size = (pos-4)-i;    
  166.             }    
  167.     
  168.             nalu.type = buffer[i]&0x1f;    
  169. char*)&buffer[i];    
  170. return (nalu.size+i-offSet);    
  171.         }    
  172.     }    
  173. return 0;    
  174. }    
  175.     
  176. void MP4Encoder::CloseMP4File(MP4FileHandle hMp4File)    
  177. {    
  178. if(hMp4File)    
  179.     {    
  180.         MP4Close(hMp4File);    
  181.         hMp4File = NULL;    
  182.     }    
  183. }    
  184.     
  185. bool MP4Encoder::WriteH264File(const char* pFile264,const char* pFileMp4)    
  186. {    
  187. if(pFile264 == NULL || pFileMp4 == NULL)    
  188.     {    
  189. return false;    
  190.     }    
  191.     
  192.     MP4FileHandle hMp4File = CreateMP4File(pFileMp4,352,288);    
  193.     
  194. if(hMp4File == NULL)    
  195.     {    
  196. "ERROR:Create file failed!");    
  197. return false;    
  198.     }    
  199.     
  200. FILE *fp = fopen(pFile264, "rb");      
  201. if(!fp)      
  202.     {      
  203. "ERROR:open file failed!");    
  204. return false;    
  205.     }      
  206.     fseek(fp, 0, SEEK_SET);    
  207.     
  208. char *buffer  = new unsigned char[BUFFER_SIZE];    
  209. int pos = 0;    
  210. while(1)    
  211.     {    
  212. int readlen = fread(buffer+pos, sizeof(unsigned char), BUFFER_SIZE-pos, fp);    
  213.     
  214.     
  215. if(readlen<=0)    
  216.         {    
  217. break;    
  218.         }    
  219.     
  220.         readlen += pos;    
  221.     
  222. int writelen = 0;    
  223. for(int i = readlen-1; i>=0; i--)    
  224.         {    
  225. if(buffer[i--] == 0x01 &&    
  226.                     buffer[i--] == 0x00 &&    
  227.                     buffer[i--] == 0x00 &&    
  228.                     buffer[i--] == 0x00    
  229.                     )    
  230.                 {    
  231.                     writelen = i+5;    
  232. break;    
  233.                 }    
  234.         }    
  235.             
  236.         writelen = WriteH264Data(hMp4File,buffer,writelen);    
  237. if(writelen<=0)    
  238.         {    
  239. break;    
  240.         }    
  241.         memcpy(buffer,buffer+writelen,readlen-writelen+1);    
  242.         pos = readlen-writelen+1;    
  243.     }    
  244.     fclose(fp);    
  245.     
  246. delete[] buffer;    
  247.     CloseMP4File(hMp4File);    
  248.     
  249. return true;    
  250. }    
  251.     
  252. bool MP4Encoder:: PraseMetadata(const unsigned char* pData,int size,MP4ENC_Metadata &metadata)    
  253. {    
  254. if(pData == NULL || size<4)    
  255.     {    
  256. return false;    
  257.     }    
  258.     MP4ENC_NaluUnit nalu;    
  259. int pos = 0;    
  260. bool bRet1 = false,bRet2 = false;    
  261. while (int len = ReadOneNaluFromBuf(pData,size,pos,nalu))    
  262.     {    
  263. if(nalu.type == 0x07)    
  264.         {    
  265.             memcpy(metadata.Sps,nalu.data,nalu.size);    
  266.             metadata.nSpsLen = nalu.size;    
  267. true;    
  268.         }    
  269. else if((nalu.type == 0x08))    
  270.         {    
  271.             memcpy(metadata.Pps,nalu.data,nalu.size);    
  272.             metadata.nPpsLen = nalu.size;    
  273. true;    
  274.         }    
  275.         pos += len;    
  276.     }    
  277. if(bRet1 && bRet2)    
  278.     {    
  279. return true;    
  280.     }    
  281. return false;    
  282. }    

其实讲 ffmpeg 时就已经讲了VS 开发环境搭建。参看:ffmpeg再学习 -- Windows下安装说明

好吧,那我再讲一遍。。

(1)新建项目

打开 VS;


文件->新建->项目->Win32控制台应用程序->选择空项目,点击完成。


注意,选择的位置最好不要有 空格或者汉字。


mp4v2再学习 -- H264视频编码成MP4文件_#include_09


mp4v2再学习 -- H264视频编码成MP4文件_#include_10


mp4v2再学习 -- H264视频编码成MP4文件_ide_11

(2)拷贝考法文件

头文件( *.h)拷贝至项目文件夹的 include 子文件夹下
导入库文件( *.lib)拷贝至项目文件夹的 lib 子文件夹下
动态库文件( *.dll) 拷贝至项目文件夹下




这三组文件具体是,mp4v2-master文件夹下的 include 文件夹 和 mp4v2-master\buildwin\lib.vs2013\Win32\Release 文件夹下的 libmp4v2.lib 和 libmp4v2.dll


mp4v2再学习 -- H264视频编码成MP4文件_ide_12




点击右键,选择在资源管理器中打开文件夹,进入项目目录。


(注意,如果手动进入注意文件夹位置,我就是没找好位置,试了半天最后才发现,将上面的这些文件拷贝到错误的文件夹下了)


mp4v2再学习 -- H264视频编码成MP4文件_#include_13




放置完成即下图:


mp4v2再学习 -- H264视频编码成MP4文件_封装_14


(3)添加代码


右击 MP4Encoder 工程,添加->类


mp4v2再学习 -- H264视频编码成MP4文件_封装_15


双击 C++类 进入 一般 C++类向导,类名写为 CMP4Encoder ,然后把上面 MP4Encoder.h 和MP4Encoder.cpp 的代码拷贝到对应的文件中。



mp4v2再学习 -- H264视频编码成MP4文件_封装_16




右击工程 MP4Encoder ->添加->新建项



mp4v2再学习 -- H264视频编码成MP4文件_封装_17




选择C++文件,名称写做 main.cpp,位置默认即可,然后将上面的“客户端调用示例代码”拷贝到此文件。


mp4v2再学习 -- H264视频编码成MP4文件_#include_18



(4)配置开发文件


打开属性面板

解决方案资源管理器->右键单击项目->属性


mp4v2再学习 -- H264视频编码成MP4文件_#include_19




头文件配置

配置属性->C/C++->常规->附加包含目录,输入“ include”(刚才拷贝头文件的目录)


mp4v2再学习 -- H264视频编码成MP4文件_ide_20


导入库配置

配置属性->链接器->常规->附加库目录,输入“ lib” (刚才拷贝库文件的目录)


mp4v2再学习 -- H264视频编码成MP4文件_封装_21


配置属性->链接器->输入->附加依赖项,输入 libmp4v2.lib;


mp4v2再学习 -- H264视频编码成MP4文件_封装_22


动态库不用配置



(5)测试

首先拷贝一个 H264 测试文件 (后缀为.264) 到 MP4Encoder 文件夹下。

测试文件可以从此处,下载:[开源世界]分享H.264视频文件下载地址 


注意,需要将该264文件,重命名为 test.h264,否则生成的 MP4 文件大小为1K。

或者你更改主函数:

mp4v2再学习 -- H264视频编码成MP4文件_#include_23

然后点击本地Windows调试器,出现此项目已经过期,选择 是。


mp4v2再学习 -- H264视频编码成MP4文件_#include_24

mp4v2再学习 -- H264视频编码成MP4文件_封装_25


即可生成 test.mp4 文件,可以用VLC播放器打开看看。

mp4v2再学习 -- H264视频编码成MP4文件_封装_26


不过生成文件时会出现,无法查找或打开 PDB 文件。如下图:

mp4v2再学习 -- H264视频编码成MP4文件_封装_27


它对于生成文件没有影响的。如果看着不舒服,可参看:无法查找或打开 PDB 文件解决办法

这是我写的工程文件:MP4Encoder 工程文件

二、工程文件(可用)

讲了这么多,你发现没有上面这个例子只是将 H264 视频编码成MP4文件,缺少音频啊亲。


下面这个即音视频编码转MP4文件的例子, 下载:MP4v2 -- h264 转 MP4






标签:int,--,MP4Encoder,char,H264,MP4,nalu,size
From: https://blog.51cto.com/u_15979522/6167183

相关文章

  • Hi3516A开发-- UBI 文件系统使用指南
    这篇文章在Hi3516AV100R001C01SPC050\02.OnlyforReference\02.software\documents_cn\UBI文件系统使用指南.pdf拿出来只为了和上篇文章做一个比较。一、概述linux-2.6.27后,内核加入了一种新型的FLASH文件系统UBI(UnsortedBlockImages)。主要针对FLASH的特有属性,通过......
  • FFmpeg再学习 -- Windows下安装说明
    看了半晌雷霄骅的ffmpeg的视频。待续稍后总结。一、FFmpeg简介FFmpeg是一个开源免费跨平台的视频和音频流方案,属于自由软件,采用LGPL或GPL许可证(依据你选择的组件)。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保......
  • threejs 拖拽 画矩形
    import*asTHREEfrom"three";import{OrbitControls}from"three/examples/jsm/controls/OrbitControls";exportfunctioninitThree(){THREE.Object3D.DefaultUp.set(0,0,1);varscene=newTHREE.Scene();varcamera=newTHR......
  • 移动端适配
    原文链接:https://blog.csdn.net/weixin_39602178/article/details/1260340591.rem方案安装插件npminstallamfe-flexible--savenpminstallpostcss-pxtorem--save-dev在main.js中引入amfe-flexibleimport'amfe-flexible';在postcss.config.js文件中配置postcss-px......
  • 二维数组-杨辉三角
    输入:5输出:1 11 121 1331 14641 #include<iostream>#include<cstring>usingnamespacestd;intmain(){/*111121133114641*/inta[101][101]={};intn;scanf("%d",&am......
  • 4月杂题
    距离NOI2023还有109天,不能再沉溺于省选的成功了。开始更新博客!4月重点在whk上,不会更很多,为了调和whk的。1.[NOI2023联合省选]填数游戏考虑对于第\(i\)个数,把\(T_i\)中的两个数连边,特别地,只有一个数连自环。此时每个连通块只能是树/基环树。基环树是好做的,因......
  • 高可靠myql配置-双MysqlRouter+MHA
    普通的主备方案 双MysqlRouter+MHA  3.1资源角色 主机IP 软件版本 备注RouterMaster 192.10.13.203 8.0.16 192.10.13.205RouterSlave 192.10.13.204 8.0.16 192.10.13.205MHAManager 192.10.13.206 MHA0.56 MHANode&Mysql主 192.10.13.201 MHA0.56&My......
  • 4.3电梯演说视频和原型展示
               团队项目电梯演说_哔哩哔哩_bilibili......
  • 从输入URL后浏览器的渲染逻辑
    从输入URL到浏览器渲染页面需要经过很多过程,本文简单说明下各个环节的内容主要渲染节点如下:一、浏览器进程说明出于安全考虑,打开一个浏览器的Tab页签,会生成1个浏览器主进程、1个网络进程、1个GPU进程以及多个渲染进程和多个插件进程,所以不同页签数据无法相互访问,多个进程也可......
  • Java判断文件夹、文件是否存在,不存在则新建
    Java判断文件夹、文件是否存在,不存在则新建原文链接:https://blog.csdn.net/asfsdgdfgdf/article/details/1283162781、Java判断是否存在文件夹,不存在则新建Filefile=newFile("D:/test/filetest/test.txt");if(!file.getParentFile().exists()){file.getParentFile().......