zoukankan      html  css  js  c++  java
  • 海思HI35xx平台软件开发快速入门之H264解码实例学习

    前言

      H264视频编码技术诞生于2003年,至今已有十余载,技术相当成熟,它的优势在于有高的视频的压缩率,利用帧间和帧内预测(Estimation)、变换(Transform)和反变换、量化(Quantization)和反量化、环路滤波(Loop Filter)、熵编码(Entropy Coding)等视频编码技术,可以实现高质量、低码率的视频流编码。H.264提供了网络抽象层NALU(Network Abstraction Layer)概念对编码出来的视频码流进一步格式封装,使得H.264的文件能容易地在不同网络上传输,以达到低带宽占用、低播放延时的目的。相信在未来几年H.264仍是视频编码的主流技术,尽管在2013年提出了H.265新一代视频编码技术,但是H265的压缩率仅仅提高40%,复杂程度却提升%50以上,这对硬件性能提出新的要求。本文讲述如何在海思HI35xx平台上实现H.264解码。

    背景知识

      先来弄清楚视频格式和视频编码的相互关系,视频格式可以理解为一个容器,它将编码器生成的多媒体内容(视频,音频,字幕,章节信息等)混合封装在一起的标准,这样就能很好处理视频、音频、字幕的播放同步问题,常见的视频格式有mp4、avi、flv、rmvb、mkv等等。视频编码属于后处理技术,它其实是非必须的,但是从摄像机采集出来的数据十分庞大,不适合网络传输和存储,故需要对视频进行编码压缩,以达到低码率、高成像质量的目的,常见的视频编码技术有h.263,h.264,mpeg-4。接下来我们了解一下海思HIMPP平台解码的概念,HIMPP平台音视频编解码架构遵循下图所示的数据处理流程。H264解码实例走的是HARD DISK->VDEC->VPSS->VO->显示器的流程,这个流程一定要熟悉牢记,代码实现都是围绕这条主线来编写的。

    H264解码实例

      实例源码很简单,先来了解一下实现H.264解码实例的几个函数,以达到了解实例源码大概构造组成,然后再对每个函数进行具体分析。

     
    1. /*

    2. **函数描述:linux标准信号捕捉函数

    3. **函数功用:接收Ctrl+C信号,用来退出程序,并销毁HIMPP调用

    4. */

    5. HI_VOID SAMPLE_VDEC_HandleSig(HI_S32 signo)

    6. {

    7. ......

    8. }

    9. /*

    10. **函数描述:用于音视频文件读写推流

    11. **函数功用:用fread等文件操作函数读取音视频文件,并解析后推送HIMPP进行解码

    12. */

    13. int SAMPLE_COMM_VDEC_H264_SendStream( VdecThreadParam *pArgs)

    14. {

    15. ......

    16. }

    17. }

    18. /*

    19. **函数描述:HIMPP系统初始化

    20. **函数功用:配置HIMPP系统的各项参数以满足对目标进行编解码

    21. */

    22. HI_S32 HI_S32 SAMPLE_VDEC_VdhH264(char *filename)

    23. {

    24. ......

    25. }

    26.  
    27. /*

    28. **主函数

    29. */

    30. int main(int argc, char *argv[])

    31. {

    32. ......

    33. }

      下面重点讲解SAMPLE_VDEC_VdhH264(char*filename)这个函数,它是H264解码样例的重点函数。HIMPP系统的API函数是海思提供的SDK开发包,调用它相关的接口,在编译时必须将其提供的相应库文件进行包含编译。下面结合样例程序讲述如何使用HIMPP提供的API实现自己的业务逻辑。H.264视频解码实例走的是HARDDISK->VDEC->VPSS->VO->显示器的处理流程,这个过程可以细分为八大步骤,这八大步骤在其他类型的音视频编解码样例也类似,可以说这八大步骤是使用海思HIMPP API的灵魂。下面简单介绍这个八大步骤的内容:

    Step1:初始化HIMPP SYS和通用VB缓冲,包括设置缓冲区的大小,缓冲区块的数目。需要注意的是,在设置通用VB参数之前,必须确保HIMPP系统已经退出,否则设置失败。

    Step2:设置通用缓冲区的公共缓冲池属性。

    Step3:配置解码器,包括指定解码类型,这里是H.264解码样例,当然选PT_H264啦,然后指定视频大小、解码优先级等等。然后创建解码通道,并是能加收解码流。

    Step4:配置VPSS参数,VPSS是对VDEC解码后的流进行处理,如裁剪、降噪等,MPEG解码实例从简单应用出发,仅仅按默认的方式配置VPSS。

    Step5:配置VO参数,这一步也很关键,因为它指定了画面输出,包括常见的HDMI和VGA,主要是配置输出显示,图层属性设置、输出位置等信息。

    Step6:绑定VDEC与VPSS,实现H264解码流程。

    Step7:绑定VPSS与VO,实现H264解码流程。

    Step8:推送视频流数据,这一步需要文件读写配合使用,对于H264一般做法是先从NALU层中找到视频I帧,然后将I帧推流至VDEC,紧接下来就按帧推送就好了,该注意的是H264解码必须先推送I帧,否则会视频会花屏。

     
    1. /*

    2. **函数功能:HIMPP系统初始化及配置

    3. **HARDDISK->VDEC->VPSS->VO->显示器的处理流程

    4. */

    5. HARDDISK->VDEC->VPSS->VO->显示器的处理流程

    6. HI_S32 SAMPLE_VDEC_VdhH264(char *filename)

    7. {

    8. VB_CONF_S stVbConf, stModVbConf;

    9. HI_S32 i, s32Ret = HI_SUCCESS;

    10. VdecThreadParam pstVdecSend;

    11. SIZE_S stSize;

    12. VO_PUB_ATTR_S stVoPubAttr;

    13. VO_VIDEO_LAYER_ATTR_S stVoLayerAttr;

    14. stSize.u32Width = HD_WIDTH;

    15. stSize.u32Height = HD_HEIGHT;

    16.  
    17. /************************************************

    18. step1: HIMPP系统初始化以及通用视频缓冲池配置

    19. *************************************************/

    20. MPP_SYS_CONF_S stSysConf = {0};

    21.  
    22. memset(&stVbConf,0,sizeof(stVbConf));

    23. stSize.u32Width = HD_WIDTH; //指定宽度

    24. stSize.u32Height = HD_HEIGHT; //指定高度

    25. stVbConf.u32MaxPoolCnt = 1; //指定最大缓冲池数量,我们只创建一路H264解码

    26. stVbConf.astCommPool[0].u32BlkSize = (stSize.u32Width * stSize.u32Height* 4) >> 1; //指定缓冲池大小,经验值一般为分辨率的1.5倍左右,这里取2倍

    27. stVbConf.astCommPool[0].u32BlkCnt = 3;

    28. memset(stVbConf.astCommPool[0].acMmzName,0,sizeof(stVbConf.astCommPool[0].acMmzName));

    29.  
    30. HI_MPI_SYS_Exit(); //设置前先去初始换HIMPP调用

    31.  
    32. for(i=0;i<22;i++)

    33. {

    34. HI_MPI_VB_ExitModCommPool(i);

    35. }

    36. for(i=0; i<256; i++)

    37. {

    38. HI_MPI_VB_DestroyPool(i);

    39. }

    40. HI_MPI_VB_Exit();

    41.  
    42. s32Ret = HI_MPI_VB_SetConf(&stVbConf);//配置缓冲池

    43. if (HI_SUCCESS != s32Ret)

    44. {

    45. hidebug("HI_MPI_VB_SetConf failed! ");

    46. return HI_FAILURE;

    47. }

    48. s32Ret = HI_MPI_VB_Init();//缓冲池初始化

    49. if (HI_SUCCESS != s32Ret)

    50. {

    51. hidebug("HI_MPI_VB_Init failed! ");

    52. return HI_FAILURE;

    53. }

    54. stSysConf.u32AlignWidth = 16;

    55. /*set config of mpp system*/

    56. s32Ret = HI_MPI_SYS_SetConf(&stSysConf);//HIMPP配置

    57. if (HI_SUCCESS != s32Ret)

    58. {

    59. hidebug("HI_MPI_SYS_SetConf failed! ");

    60. return HI_FAILURE;

    61. }

    62. s32Ret = HI_MPI_SYS_Init(); //HIMPP系统初始化

    63. if (HI_SUCCESS != s32Ret)

    64. {

    65. hidebug("HI_MPI_SYS_Init failed! ");

    66. return HI_FAILURE;

    67. }

    68. /************************************************

    69. step2: 系统缓冲池模块初始化配置

    70. *************************************************/

    71. memset(&stModVbConf, 0, sizeof(VB_CONF_S));

    72. stModVbConf.u32MaxPoolCnt = 2;

    73. stModVbConf.astCommPool[0].u32BlkSize = (stSize.u32Width * stSize.u32Height* 4) >> 1;;

    74. stModVbConf.astCommPool[0].u32BlkCnt = 5;

    75.  
    76. stModVbConf.astCommPool[1].u32BlkSize = (stSize.u32Width * stSize.u32Height* 4) >> 1;;

    77. stModVbConf.astCommPool[1].u32BlkCnt = 5;

    78.  
    79. HI_MPI_VB_ExitModCommPool(VB_UID_VDEC);

    80. HI_MPI_VB_SetModPoolConf(VB_UID_VDEC, &stModVbConf);

    81. HI_MPI_VB_InitModCommPool(VB_UID_VDEC);

    82.  
    83.  
    84. /************************************************

    85. step3: 解码器配置及初始化

    86. *************************************************/

    87. VDEC_CHN_ATTR_S stVdecChnAttr;

    88.  
    89. stVdecChnAttr.enType = PT_H264; //创建H264类型的解码器

    90. stVdecChnAttr.u32BufSize = 3 * stSize.u32Width * stSize.u32Height;//指定解码缓冲区大小

    91. stVdecChnAttr.u32Priority = 5; //设置解码优先级

    92. stVdecChnAttr.u32PicWidth = stSize.u32Width; //解码宽高

    93. stVdecChnAttr.u32PicHeight =stSize.u32Height;

    94.  
    95. stVdecChnAttr.stVdecVideoAttr.enMode = VIDEO_MODE_FRAME; //帧式解码模式

    96. stVdecChnAttr.stVdecVideoAttr.u32RefFrameNum = 2;

    97. stVdecChnAttr.stVdecVideoAttr.bTemporalMvpEnable = 0;

    98.  
    99. HI_MPI_VDEC_SetChnVBCnt(0, 10);

    100. HI_MPI_VDEC_CreateChn(0, &stVdecChnAttr);

    101. HI_MPI_VDEC_StartRecvStream(0);

    102.  
    103. /************************************************

    104. step4: VPSS配置及初始化

    105. *************************************************/

    106. VPSS_GRP_PARAM_S stVpssParam = {0};

    107. VPSS_CHN_ATTR_S stChnAttr = {0};

    108. VPSS_GRP_ATTR_S stVpssGrpAttr;

    109.  
    110. stVpssGrpAttr.enDieMode = VPSS_DIE_MODE_NODIE;

    111. stVpssGrpAttr.bIeEn = HI_FALSE;

    112. stVpssGrpAttr.bDciEn = HI_TRUE;

    113. stVpssGrpAttr.bNrEn = HI_FALSE;

    114. stVpssGrpAttr.bHistEn = HI_FALSE;

    115. stVpssGrpAttr.bEsEn = HI_FALSE;

    116. stVpssGrpAttr.enPixFmt = PIXEL_FORMAT_YUV_SEMIPLANAR_420;//解码像素格式YUV420

    117. stVpssGrpAttr.u32MaxW = stSize.u32Width;

    118. stVpssGrpAttr.u32MaxH = stSize.u32Height;

    119.  
    120. /*** create vpss group ***/

    121. s32Ret = HI_MPI_VPSS_CreateGrp(0, &stVpssGrpAttr);//创建VPSS Group,在HI3536平台一个Group有4个VPSS Channel

    122. if (s32Ret != HI_SUCCESS)

    123. {

    124. hidebug("HI_MPI_VPSS_CreateGrp failed! ");

    125. return HI_FAILURE;

    126. }

    127. /*** set vpss param ***/

    128. s32Ret = HI_MPI_VPSS_GetGrpParam(0, &stVpssParam);//设置VPSS Group属性

    129. if(s32Ret != HI_SUCCESS)

    130. {

    131. hidebug("HI_MPI_VPSS_GetGrpParam failed! ");

    132. return HI_FAILURE;

    133. }

    134. stVpssParam.u32IeStrength = 0;

    135. s32Ret = HI_MPI_VPSS_SetGrpParam(0, &stVpssParam);

    136. if(s32Ret != HI_SUCCESS)

    137. {

    138. hidebug("HI_MPI_VPSS_GetGrpParam failed! ");

    139. return HI_FAILURE;

    140. }

    141. /*** enable vpss chn, with frame ***/

    142. /* Set Vpss Chn attr */

    143. stChnAttr.bSpEn = HI_FALSE;

    144. stChnAttr.bUVInvert = HI_FALSE;

    145. stChnAttr.bBorderEn = HI_TRUE;

    146. stChnAttr.stBorder.u32Color = 0xffffff;//背景色为黑色

    147. stChnAttr.stBorder.u32LeftWidth = 2;

    148. stChnAttr.stBorder.u32RightWidth = 2;

    149. stChnAttr.stBorder.u32TopWidth = 2;

    150. stChnAttr.stBorder.u32BottomWidth = 2;

    151.  
    152. s32Ret = HI_MPI_VPSS_SetChnAttr(0, 0, &stChnAttr);

    153. if(s32Ret != HI_SUCCESS)

    154. {

    155. hidebug("HI_MPI_VPSS_SetChnAttr failed! ");

    156. return HI_FAILURE;

    157. }

    158. s32Ret = HI_MPI_VPSS_EnableChn(0, 0);//由于只有一路H264解码,故只用Group0 及 Channel 0

    159. if(s32Ret != HI_SUCCESS)

    160. {

    161. hidebug("HI_MPI_VPSS_EnableChn failed! ");

    162. return HI_FAILURE;

    163. }

    164. /*** start vpss group ***/

    165. s32Ret = HI_MPI_VPSS_StartGrp(0);

    166. if(s32Ret != HI_SUCCESS)

    167. {

    168. hidebug("HI_MPI_VPSS_StartGrp failed! ");

    169. return HI_FAILURE;

    170. }

    171.  
    172. /************************************************

    173. step5: 配置VO及初始化VO

    174. *************************************************/

    175. VO_CHN_ATTR_S stChnAttr1;

    176.  
    177. stVoPubAttr.enIntfSync = VO_OUTPUT_1080P60;//VO输出模式为1080p 60帧,普通显示器的输出

    178. stVoPubAttr.enIntfType = VO_INTF_VGA | VO_INTF_HDMI;//启用VGA及HDMI输出

    179. s32Ret = HI_MPI_VO_SetPubAttr(0, &stVoPubAttr);

    180. if(s32Ret != HI_SUCCESS)

    181. {

    182. hidebug("HI_MPI_VO_SetPubAttr failed! ");

    183. return HI_FAILURE;

    184. }

    185. s32Ret = HI_MPI_VO_Enable(0);

    186. if (s32Ret != HI_SUCCESS)

    187. {

    188. hidebug("HI_MPI_VO_Enable failed! ");

    189. return HI_FAILURE;

    190. }

    191. //设置VO Layer显示配置,如显示位置,大小,像素类型

    192. stVoLayerAttr.u32DispFrmRt = 60;

    193. stVoLayerAttr.stDispRect.u32Width = 1920;

    194. stVoLayerAttr.stDispRect.u32Height = 1080;

    195. stVoLayerAttr.stImageSize.u32Width = stVoLayerAttr.stDispRect.u32Width;

    196. stVoLayerAttr.stImageSize.u32Height = stVoLayerAttr.stDispRect.u32Height;

    197. stVoLayerAttr.bClusterMode = HI_FALSE;

    198. stVoLayerAttr.bDoubleFrame = HI_FALSE;

    199. stVoLayerAttr.enPixFormat = PIXEL_FORMAT_YUV_SEMIPLANAR_420;

    200. s32Ret = HI_MPI_VO_SetVideoLayerAttr(0, &stVoLayerAttr);

    201. if(s32Ret != HI_SUCCESS)

    202. {

    203. hidebug("HI_MPI_VO_SetVideoLayerAttr failed! ");

    204. return HI_FAILURE;

    205. }

    206. s32Ret = HI_MPI_VO_EnableVideoLayer(0);

    207. if (s32Ret != HI_SUCCESS)

    208. {

    209. hidebug("HI_MPI_VO_EnableVideoLayer failed! ");

    210. return HI_FAILURE;

    211. }

    212. /*

    213. if (HI_SUCCESS != SAMPLE_COMM_VO_HdmiStart(stVoPubAttr.enIntfSync))

    214. {

    215. hidebug("Start SAMPLE_COMM_VO_HdmiStart failed! ");

    216. }

    217. */

    218. //设置VO Channel显示位置,大小

    219. stChnAttr1.stRect.s32X = 0;

    220. stChnAttr1.stRect.s32Y = 0;

    221. stChnAttr1.stRect.u32Width = 1920;

    222. stChnAttr1.stRect.u32Height = 1080;

    223. stChnAttr1.u32Priority = 0;

    224. stChnAttr1.bDeflicker = HI_FALSE;

    225.  
    226. s32Ret = HI_MPI_VO_SetChnAttr(0, 0, &stChnAttr1);

    227. if (s32Ret != HI_SUCCESS)

    228. {

    229. hidebug("failed with %#x! ", s32Ret);

    230. }

    231. s32Ret = HI_MPI_VO_EnableChn(0,0);

    232. if (s32Ret != HI_SUCCESS)

    233. {

    234. hidebug("failed with %#x! ", s32Ret);

    235.  
    236. }

    237. /************************************************

    238. step6: 解码器绑定VPSS

    239. *************************************************/

    240. MPP_CHN_S stSrcChn;

    241. MPP_CHN_S stDestChn;

    242.  
    243. stSrcChn.enModId = HI_ID_VDEC;

    244. stSrcChn.s32DevId = 0;

    245. stSrcChn.s32ChnId = 0;

    246.  
    247. stDestChn.enModId = HI_ID_VPSS;

    248. stDestChn.s32DevId = 0;

    249. stDestChn.s32ChnId = 0;

    250. s32Ret = HI_MPI_SYS_Bind(&stSrcChn, &stDestChn);

    251. if(s32Ret != HI_SUCCESS)

    252. {

    253. hidebug("HI_MPI_SYS_Bind failed! ");

    254. return HI_FAILURE;

    255. }

    256.  
    257. /************************************************

    258. step7: VPSS绑定VO

    259. *************************************************/

    260. stSrcChn.enModId = HI_ID_VPSS;

    261. stSrcChn.s32DevId = 0;

    262. stSrcChn.s32ChnId = 0;

    263.  
    264. stDestChn.enModId = HI_ID_VOU;

    265. stDestChn.s32DevId = 0;

    266. stDestChn.s32ChnId = 0;

    267. s32Ret = HI_MPI_SYS_Bind(&stSrcChn, &stDestChn);

    268. if(s32Ret != HI_SUCCESS)

    269. {

    270. hidebug("HI_MPI_SYS_Bind failed! ");

    271. return HI_FAILURE;

    272. }

    273.  
    274. /************************************************

    275. step8: 发送解码流,推送H264流至VDEC

    276. *************************************************/

    277. sprintf(pstVdecSend.cFileName,filename);

    278. pstVdecSend.s32MilliSec = 0;

    279. pstVdecSend.s32ChnId = 0;

    280. pstVdecSend.s32IntervalTime = 1;

    281. pstVdecSend.u64PtsInit = 0;

    282. pstVdecSend.u64PtsIncrease = 0;

    283. pstVdecSend.eCtrlSinal = VDEC_CTRL_START;

    284. pstVdecSend.bLoopSend = HI_TRUE;

    285. pstVdecSend.bManuSend = HI_FALSE;

    286. pstVdecSend.enType = PT_H264;

    287. pstVdecSend.s32MinBufSize = (stVdecChnAttr.u32PicWidth *stVdecChnAttr.u32PicHeight * 3)>>1;

    288. pstVdecSend.s32StreamMode = VIDEO_MODE_FRAME;

    289. SAMPLE_COMM_VDEC_H264_SendStream(&pstVdecSend);

    290.  
    291. return s32Ret;

    292. }

    293.  
    294.  
    295. int main(int argc, char *argv[])

    296. {

    297. if(argc != 2)

    298. {

    299. printf("Usage: h264 filename ");

    300. exit(0);

    301. }

    302. signal(SIGINT, SAMPLE_VDEC_HandleSig);

    303. signal(SIGTERM, SAMPLE_VDEC_HandleSig);

    304. SAMPLE_VDEC_VdhH264(argv[1]);

    305.  
    306. return 0;

    307. }

    H264的NALU

      这里讲一下H264编码的NALU基础知识,NAL全称Network Abstract Layer, 即网络抽象层。如何从NAL里面找到我们需要的帧呢,原来实际的H264数据帧中,往往在帧前面带有00 00 00 01 或 00 00 01分隔符,来标识一帧的起始位置。以00 00 00 01分割之后的下一个字节就是NALU类型,将其转为二进制数据后,解读顺序为从左往右算,第一位为禁止位,值为1表示语法出错;第2~3位为参考级别;第4~8为是NAL单元类型。常见的NALU的类型有序列参数集SPS,它的NAL单元类型值为0x67,即0000 0001 0110 0111;图像参数集PPS,它的NAL单元类型值为0x68,即0000 00010110 1000;IDR图像中的片(I帧) ,它的NAL单元类型值为0x65,即0000 0001 0110 0101。所以判断是否为I帧的算法为: (NALU类型 & 0001  1111)= 5,即NALU类型 & 1F= 5,比如0x65 & 1F = 5。结合H264推流的代码看一下,这段代码的通过读取H.264文件到一个缓冲区,然后对缓冲区进行数据处理,判断I帧的起始位置。

     
    1. //解析H264文件的I帧信息

    2. else if ( (pstVdecThreadParam->s32StreamMode==VIDEO_MODE_FRAME) && (pstVdecThreadParam->enType == PT_H264) )

    3. {

    4. bFindStart = HI_FALSE;

    5. bFindEnd = HI_FALSE;

    6. fseek(fpStrm, s32UsedBytes, SEEK_SET);

    7. s32ReadLen = fread(pu8Buf, 1, pstVdecThreadParam->s32MinBufSize, fpStrm);

    8. if (s32ReadLen == 0)

    9. {

    10. if (pstVdecThreadParam->bLoopSend)

    11. {

    12. s32UsedBytes = 0;

    13. fseek(fpStrm, 0, SEEK_SET);

    14. s32ReadLen = fread(pu8Buf, 1, pstVdecThreadParam->s32MinBufSize, fpStrm);

    15. }

    16. else

    17. {

    18. break;

    19. }

    20. }

    21.  
    22. for (i=0; i<s32ReadLen-8; i++)

    23. {

    24. int tmp = pu8Buf[i+3] & 0x1F; //判断I帧

    25. if ( pu8Buf[i] == 0 && pu8Buf[i+1] == 0 && pu8Buf[i+2] == 1 &&

    26. (

    27. ((tmp == 5 || tmp == 1) && ((pu8Buf[i+4]&0x80) == 0x80)) ||

    28. (tmp == 20 && (pu8Buf[i+7]&0x80) == 0x80)

    29. )

    30. )

    31. {

    32. bFindStart = HI_TRUE;

    33. i += 8;

    34. break;

    35. }

    36. }

    37.  
    38. for (; i<s32ReadLen-8; i++)

    39. {

    40. int tmp = pu8Buf[i+3] & 0x1F;//判断I帧

    41. if ( pu8Buf[i ] == 0 && pu8Buf[i+1] == 0 && pu8Buf[i+2] == 1 &&

    42. (

    43. tmp == 15 || tmp == 7 || tmp == 8 || tmp == 6 ||

    44. ((tmp == 5 || tmp == 1) && ((pu8Buf[i+4]&0x80) == 0x80)) ||

    45. (tmp == 20 && (pu8Buf[i+7]&0x80) == 0x80)

    46. )

    47. )

    48. {

    49. bFindEnd = HI_TRUE;

    50. break;

    51. }

    52. }

    53.  
    54. if(i > 0) s32ReadLen = i;

    55. if (bFindStart == HI_FALSE)

    56. {

    57. printf("SAMPLE_TEST: chn %d can not find start code!s32ReadLen %d, s32UsedBytes %d. ",

    58. pstVdecThreadParam->s32ChnId, s32ReadLen, s32UsedBytes);

    59. }

    60. else if (bFindEnd == HI_FALSE)

    61. {

    62. s32ReadLen = i+8;

    63. }

    64.  
    65. }

    总结

      H.264解码实例参考了海思提供的样例及库,程序源码及相关库文件请点击这里,修改不同的编译链工具,即可在不同HI35XX系列平台运行,整个H.264解码实例提供了最简单的解码实现方式,当然还可以实现快进播放、暂停播放等常用的视频播放控制逻辑,这需要读者进一步摸索。

  • 相关阅读:
    Python-异常处理机制
    递归函数——斐波那契数列j
    函数及相关操作
    字符串及相关操作
    集合及相关操作
    元组
    字典
    列表元素增删改排操作
    multiprocessing模块简单应用
    02 for循环创建进程
  • 原文地址:https://www.cnblogs.com/schips/p/11504705.html
Copyright © 2011-2022 走看看