aqws

aqws

0个粉丝

5

问答

0

专栏

0

资料

aqws  发布于  2022-12-04 11:42:07
采纳率 20%
5个问答
1052

Hi3536编码采用CBR,手动控制编码帧率和码率,报0xa0088003(参数超出合法范围)错误

 

从网上找到一个读取YUV文件并编码为H264的样例程序,正常运行成功,输入和输出帧率均为30fps,采用CBR固定码率编码,平均码率为6mbps;然后我做实验需要在控制码率一定的情况下编码出不同帧率的码流,于是直接修改VENC_ATTR_H264_CBR_S结构体的目标帧率fr32DstFrmRate为25,编译运行后报错:参数超出合法范围。
程序代码如下:

  1. #ifdef __cplusplus
  2. #if __cplusplus
  3. extern "C" {
  4. #endif
  5. #endif /* End of #ifdef __cplusplus */
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <unistd.h>
  10. #include <pthread.h>
  11. #include <signal.h>
  12. #include "sample_comm.h"
  13. VIDEO_NORM_E gs_enNorm = VIDEO_ENCODING_MODE_NTSC;
  14. /**
  15. VI_DEV_ATTR_S DEV_ATTR_BT1120_1080P_BASE_1 = {
  16. //interface mode
  17. VI_MODE_BT1120_STANDARD,
  18. //multiplex mode
  19. VI_WORK_MODE_1Multiplex,
  20. {0xFF000000, 0xFF0000},
  21. VI_SCAN_PROGRESSIVE,
  22. { -1, -1, -1, -1},
  23. VI_INPUT_DATA_UVUV,
  24. {
  25. VI_VSYNC_PULSE, VI_VSYNC_NEG_HIGH, VI_HSYNC_VALID_SINGNAL, VI_HSYNC_NEG_HIGH, VI_VSYNC_NORM_PULSE, VI_VSYNC_VALID_NEG_HIGH,
  26. {
  27. 0, 1920, 0,
  28. 0, 1080, 0,
  29. 0, 0, 0
  30. }
  31. },
  32. VI_PATH_BYPASS,
  33. VI_DATA_TYPE_YUV,
  34. HI_FALSE,
  35. // {0, 0, 1920, 1080}
  36. };
  37. **/
  38. /******************************************************************************
  39. * funciton : 编码通道处理主流程
  40. ******************************************************************************/
  41. HI_VOID* SAMPLE_COMM_VENC_GetVencStreamProcEx(HI_VOID)
  42. {
  43. VENC_CHN_ATTR_S stVencChnAttr;
  44. struct timeval TimeoutVal;
  45. fd_set read_fds;
  46. HI_S32 VencFd;
  47. FILE *pFile1, *pFile2;
  48. VENC_CHN_STAT_S stStat;
  49. VENC_STREAM_S stStream;
  50. HI_S32 s32Ret ,frame = 0;
  51. VENC_CHN VencChn = 0;
  52. PAYLOAD_TYPE_E enPayLoadType = PT_H264;
  53. /******************************************************************************************************************
  54. step 1: check & prepare save-file & venc-fd, decide the stream file name, and open file to save stream,Set Venc Fd
  55. ********************************************************************************************************************/
  56. pFile1 = fopen("dog_512_8.h264","wb+");
  57. if(pFile1 == NULL)
  58. {
  59. printf("new test.h264 file failed\n");
  60. return -1;
  61. }
  62. pFile2 = fopen("./dog.yuv","rb");
  63. if(pFile2 == NULL)
  64. {
  65. printf("open yuv file failed\n");
  66. return -1;
  67. }
  68. VencFd = HI_MPI_VENC_GetFd(VencChn);
  69. if (VencFd < 0)
  70. {
  71. SAMPLE_PRT("HI_MPI_VENC_GetFd failed with %#x!\n",VencFd);
  72. return NULL;
  73. }
  74. VB_BLK handleY = VB_INVALID_HANDLE;
  75. HI_U64 phyYaddr;
  76. HI_U64 *pVirYaddr;
  77. VIDEO_FRAME_INFO_S *pstFrame = malloc(sizeof(VIDEO_FRAME_INFO_S));
  78. /*************************************************************
  79. step 2: Start to get streams of each channel.
  80. ***************************************************************/
  81. while(frame < 450) {
  82. /* 分配物理buffer并且映射到用户空间 */
  83. do
  84. {
  85. handleY = HI_MPI_VB_GetBlock(VB_INVALID_POOLID, 1920 * 1080 * 3 / 2 , NULL);
  86. if (VB_INVALID_HANDLE == handleY) {
  87. SAMPLE_PRT("handleY is VB_INVALID_HANDLE\n");
  88. }
  89. }while (VB_INVALID_HANDLE == handleY);
  90. if(handleY == VB_INVALID_HANDLE)
  91. {
  92. printf("getblock for y failed\n");
  93. return -1;
  94. }else {
  95. printf("handleY is %d\n", handleY);
  96. }
  97. VB_POOL poolID = HI_MPI_VB_Handle2PoolId (handleY);//得到poolID
  98. printf("pool ID = %d\n", poolID);
  99. phyYaddr = HI_MPI_VB_Handle2PhysAddr(handleY);
  100. if( phyYaddr == 0)
  101. {
  102. printf("HI_MPI_VB_Handle2PhysAddr for handleY failed\n");
  103. return -1;
  104. }
  105. pVirYaddr = (HI_U64 *) HI_MPI_SYS_Mmap(phyYaddr, 1920 * 1080 * 3 / 2);
  106. /* 图像帧结构初始化 */
  107. memset(&(pstFrame->stVFrame),0x00,sizeof(VIDEO_FRAME_S));
  108. pstFrame->stVFrame.u32Width = 1920;
  109. pstFrame->stVFrame.u32Height = 1080;
  110. pstFrame->stVFrame.enPixelFormat = PIXEL_FORMAT_YUV_SEMIPLANAR_420;
  111. // pstFrame->stVFrame.enPixelFormat = PIXEL_FORMAT_YUV_PLANAR_420;
  112. pstFrame->u32PoolId = poolID;
  113. pstFrame->stVFrame.u32PhyAddr[0] = phyYaddr;
  114. pstFrame->stVFrame.u32PhyAddr[1] = phyYaddr + 1920 * 1080;
  115. pstFrame->stVFrame.pVirAddr[0] = (HI_U64)pVirYaddr;
  116. pstFrame->stVFrame.pVirAddr[1] = (HI_U64)pVirYaddr + 1920 * 1080;
  117. pstFrame->stVFrame.u32Stride[0] = 1920 ;
  118. pstFrame->stVFrame.u32Stride[1] = 1920 ;
  119. pstFrame->stVFrame.u32Field = VIDEO_FIELD_FRAME;
  120. pstFrame->stVFrame.enCompressMode = COMPRESS_MODE_NONE;
  121. pstFrame->stVFrame.enVideoFormat = VIDEO_FORMAT_LINEAR;
  122. pstFrame->stVFrame.u64pts = frame * 33;
  123. pstFrame->stVFrame.u32TimeRef = frame * 2;
  124. s32Ret = fread(pVirYaddr,1920 * 1080 * 3 / 2, 1, pFile2);
  125. if(s32Ret < 0)
  126. {
  127. printf("fread yuv420sp failed\n");
  128. return -1;
  129. }
  130. s32Ret = HI_MPI_VENC_SendFrame(VencChn, pstFrame, -1);
  131. if(s32Ret != 0)
  132. {
  133. printf("HI_MPI_VENC_SendFrame failed %#x\n",s32Ret);
  134. return -1;
  135. }
  136. /* 使用select循环读取编码后的数据 */
  137. FD_ZERO(&read_fds);
  138. FD_SET(VencFd, &read_fds);
  139. TimeoutVal.tv_sec = 2;
  140. TimeoutVal.tv_usec = 0;
  141. s32Ret = select(VencFd + 1, &read_fds, NULL, NULL, &TimeoutVal);
  142. if (s32Ret < 0)
  143. {
  144. SAMPLE_PRT("select failed!\n");
  145. break;
  146. }
  147. else if (s32Ret == 0)
  148. {
  149. SAMPLE_PRT("get venc stream time out, exit thread\n");
  150. continue;
  151. }
  152. else
  153. {
  154. if (FD_ISSET(VencFd, &read_fds))
  155. {
  156. printf("select has data can read\n");
  157. memset(&stStream, 0, sizeof(stStream));
  158. /* 查询编码器状态 */
  159. s32Ret = HI_MPI_VENC_Query(VencChn, &stStat);
  160. if (HI_SUCCESS != s32Ret)
  161. {
  162. SAMPLE_PRT("HI_MPI_VENC_Query chn[%d] failed with %#x!\n", VencChn, s32Ret);
  163. break;
  164. }
  165. if(0 == stStat.u32CurPacks)
  166. {
  167. SAMPLE_PRT("NOTE: Current frame is NULL!\n");
  168. continue;
  169. }
  170. /* 分配buffer准备读取Pack */
  171. stStream.pstPack = (VENC_PACK_S*)malloc(sizeof(VENC_PACK_S) * stStat.u32CurPacks);
  172. if (NULL == stStream.pstPack)
  173. {
  174. SAMPLE_PRT("malloc stream pack failed!\n");
  175. break;
  176. }
  177. /* 读取编码好的数据 */
  178. stStream.u32PackCount = stStat.u32CurPacks;
  179. s32Ret = HI_MPI_VENC_GetStream(VencChn, &stStream, HI_TRUE);
  180. if (HI_SUCCESS != s32Ret)
  181. {
  182. free(stStream.pstPack);
  183. stStream.pstPack = NULL;
  184. SAMPLE_PRT("HI_MPI_VENC_GetStream failed with %#x!\n", s32Ret);
  185. break;
  186. }
  187. /* 保存读取到的编码数据 */
  188. s32Ret = SAMPLE_COMM_VENC_SaveStream(enPayLoadType, pFile1, &stStream);
  189. if (HI_SUCCESS != s32Ret)
  190. {
  191. free(stStream.pstPack);
  192. stStream.pstPack = NULL;
  193. SAMPLE_PRT("save stream failed with %#x\n", s32Ret);
  194. break;
  195. }
  196. /* 释放buffer给编码通道 */
  197. s32Ret = HI_MPI_VENC_ReleaseStream(VencChn, &stStream);
  198. if (HI_SUCCESS != s32Ret)
  199. {
  200. free(stStream.pstPack);
  201. stStream.pstPack = NULL;
  202. break;
  203. }
  204. free(stStream.pstPack);
  205. stStream.pstPack = NULL;
  206. }
  207. }
  208. // HI_MPI_VI_ReleaseFrame(ViChn, pstFrame);
  209. HI_MPI_VB_ReleaseBlock(handleY);
  210. HI_MPI_VB_DestroyPool(poolID);
  211. printf("frame %d\n",frame);
  212. frame++;
  213. }
  214. fclose(pFile1);
  215. fclose(pFile2);
  216. return HI_SUCCESS;
  217. }
  218. /******************************************************************************
  219. * function : H.264@1080p@30fps+H.264@VGA@30fps
  220. ******************************************************************************/
  221. HI_S32 SAMPLE_VENC_1080P_CLASSIC(HI_VOID)
  222. {
  223. PAYLOAD_TYPE_E enPayLoad = PT_H264;
  224. PIC_SIZE_E enSize = PIC_HD1080;
  225. VB_CONF_S stVbConf;
  226. // VPSS_GRP VpssGrp;
  227. // VPSS_CHN VpssChn;
  228. // VPSS_GRP_ATTR_S stVpssGrpAttr;
  229. // VPSS_CHN_ATTR_S stVpssChnAttr;
  230. // VPSS_CHN_MODE_S stVpssChnMode;
  231. VENC_CHN VencChn;
  232. SAMPLE_RC_E enRcMode= SAMPLE_RC_CBR;
  233. // SAMPLE_RC_E enRcMode= SAMPLE_RC_VBR;
  234. HI_S32 s32ChnNum=1;
  235. HI_S32 s32Ret = HI_SUCCESS;
  236. HI_U32 u32BlkSize;
  237. SIZE_S stSize;
  238. /******************************************
  239. step 1: 初始化系统
  240. ******************************************/
  241. memset(&stVbConf,0,sizeof(VB_CONF_S));
  242. stVbConf.u32MaxPoolCnt = 128;
  243. u32BlkSize = SAMPLE_COMM_SYS_CalcPicVbBlkSize(gs_enNorm,enSize, SAMPLE_PIXEL_FORMAT, SAMPLE_SYS_ALIGN_WIDTH);
  244. stVbConf.astCommPool[0].u32BlkSize = u32BlkSize;
  245. stVbConf.astCommPool[0].u32BlkCnt = 20;
  246. printf("--------blksize = %d--------\n",u32BlkSize);
  247. /******************************************
  248. step 2: 初始化mmp
  249. ******************************************/
  250. s32Ret = SAMPLE_COMM_SYS_Init(&stVbConf);
  251. if (HI_SUCCESS != s32Ret)
  252. {
  253. SAMPLE_PRT("system init failed with %d!\n", s32Ret);
  254. goto END_VENC_1080P_CLASSIC_0;
  255. }
  256. /******************************************
  257. step 4: 启动venc编码通道
  258. ******************************************/
  259. VencChn = 0;
  260. s32Ret = SAMPLE_COMM_VENC_Start(VencChn, enPayLoad, gs_enNorm, enSize, enRcMode);
  261. if (HI_SUCCESS != s32Ret)
  262. {
  263. SAMPLE_PRT("Start Venc failed! %#x\n", s32Ret);
  264. goto END_VENC_1080P_CLASSIC_5;
  265. }
  266. /******************************************
  267. step 5: 采集帧,处理帧,保存帧
  268. ******************************************/
  269. s32Ret = SAMPLE_COMM_VENC_GetVencStreamProcEx();
  270. if (HI_SUCCESS != s32Ret)
  271. {
  272. SAMPLE_PRT("Start Venc failed---! %#x\n",s32Ret);
  273. goto END_VENC_1080P_CLASSIC_5;
  274. }
  275. /******************************************
  276. step 6: exit process
  277. ******************************************/
  278. END_VENC_1080P_CLASSIC_5:
  279. END_VENC_1080P_CLASSIC_0:
  280. SAMPLE_COMM_VENC_Stop(VencChn);
  281. SAMPLE_COMM_SYS_Exit();
  282. return s32Ret;
  283. }
  284. /******************************************************************************
  285. * function : to process abnormal case
  286. ******************************************************************************/
  287. void SAMPLE_VENC_HandleSig(HI_S32 signo)
  288. {
  289. if (SIGINT == signo || SIGTERM == signo)
  290. {
  291. // SAMPLE_COMM_ISP_Stop();
  292. SAMPLE_COMM_SYS_Exit();
  293. printf("\033[0;31mprogram termination abnormally!\033[0;39m\n");
  294. }
  295. exit(-1);
  296. }
  297. /******************************************************************************
  298. * function : main()
  299. * Description : video venc sample
  300. ******************************************************************************/
  301. int main(int argc, char* argv[])
  302. {
  303. HI_S32 s32Ret;
  304. signal(SIGINT, SAMPLE_VENC_HandleSig);
  305. signal(SIGTERM, SAMPLE_VENC_HandleSig);
  306. /* 开启编码流程 */
  307. s32Ret = SAMPLE_VENC_1080P_CLASSIC();
  308. if (HI_SUCCESS == s32Ret)
  309. {
  310. printf("program exit normally!\n");
  311. }
  312. else
  313. {
  314. printf("program exit abnormally!\n");
  315. }
  316. exit(s32Ret);
  317. }
  318. #ifdef __cplusplus
  319. #if __cplusplus
  320. }
  321. #endif
  322. #endif /* End of #ifdef __cplusplus */

然后我修改帧率和码率是直接在SDK的sample中的sample_comm_venc.c中SAMPLE_COMM_VENC_Start()函数的CBR部分修改的。
logmpp的输出如下:

运行时查看venc调试信息如下(好像没有获取到我的输入帧率和目标帧率):

麻烦各位大神帮忙看一下

我来回答
回答4个
时间排序
认可量排序

邓晓

20个粉丝

1

问答

0

专栏

19

资料

邓晓 2022-12-07 15:00:17
认可0

可能是pstFrame->stVFrame.u64pts = frame 33;
pstFrame->stVFrame.u32TimeRef = frame 2;参数有问题
另外,send和get放在1个线程里,其实是没法保证帧率的,最好两个线程,1个发,一个取

aqws
aqws   回复   邓晓  2022-12-07 17:28:55
0

老师,我这里把sample_comm_venc.c中SAMPLE_COMM_VENC_Start()函数中CBR的输入和输出帧率改成一致的,就是说如果我要编帧率为25的码流,将stH264Cbr.u32SrcFrmRate和stH264Cbr.fr32DstFrmRate都改成25,能够成功运行,但是输出的码流我只看到画质变差,码流时长和帧数都没有变化

邓晓
邓晓   回复   aqws  2022-12-07 17:36:54
0

读文件和取流需要时间的,没法真正控制输入帧率是25fps

aqws
aqws   回复   邓晓  2022-12-09 15:11:17
0

老师,不好意思打扰您了。我还想问一下,比如一段10s,300帧的YUV视频序列,我通过VENC模块固定编码码率,修改输出帧率,将其变成15fps的es码流,它的播放效果体现在时长和帧数上应该有什么不同呢?我在使用HI_MPI_VENC_SetFrameRate()修改输入和输出帧率后得到ES流,在H264浏览器中显示还是30fps,总共300帧,就是后150帧一直在重复前2帧的内容。

或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
+ 添加网盘链接/附件

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

易百纳技术社区