enc_test.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2021 StarFive Technology Co., Ltd.
  4. */
  5. #include <stdio.h>
  6. #include <unistd.h>
  7. #include <signal.h>
  8. #include <getopt.h>
  9. #include <fcntl.h>
  10. #include <OMX_Core.h>
  11. #include <OMX_Component.h>
  12. #include <OMX_Video.h>
  13. #include <OMX_VideoExt.h>
  14. #include <OMX_IndexExt.h>
  15. #include <sys/time.h>
  16. #include <sys/types.h>
  17. #include <sys/ipc.h>
  18. #include <sys/msg.h>
  19. #include <errno.h>
  20. #include <string.h>
  21. #include <stdlib.h>
  22. #define OMX_INIT_STRUCTURE(a) \
  23. memset(&(a), 0, sizeof(a)); \
  24. (a).nSize = sizeof(a); \
  25. (a).nVersion.nVersion = 1; \
  26. (a).nVersion.s.nVersionMajor = 1; \
  27. (a).nVersion.s.nVersionMinor = 1; \
  28. (a).nVersion.s.nRevision = 1; \
  29. (a).nVersion.s.nStep = 1
  30. typedef struct Message
  31. {
  32. long msg_type;
  33. OMX_S32 msg_flag;
  34. OMX_BUFFERHEADERTYPE *pBuffer;
  35. } Message;
  36. typedef struct EncodeTestContext
  37. {
  38. OMX_HANDLETYPE hComponentEncoder;
  39. char sOutputFilePath[256];
  40. char sInputFilePath[256];
  41. FILE *pInputFile;
  42. char sInputFormat[64];
  43. char sOutputFormat[64];
  44. OMX_U32 nFrameBufferSize;
  45. OMX_U32 nBitrate;
  46. OMX_U32 nFrameRate;
  47. OMX_U32 nNumPFrame;
  48. OMX_STATETYPE comState;
  49. OMX_BUFFERHEADERTYPE *pInputBufferArray[64];
  50. OMX_BUFFERHEADERTYPE *pOutputBufferArray[64];
  51. int msgid;
  52. } EncodeTestContext;
  53. EncodeTestContext *encodeTestContext;
  54. static FILE *fb = NULL;
  55. static OMX_BOOL inputEndFlag = OMX_FALSE;
  56. static OMX_S32 FillInputBuffer(EncodeTestContext *encodeTestContext, OMX_BUFFERHEADERTYPE *pInputBuffer);
  57. static OMX_BOOL disableEVnt;
  58. static OMX_BOOL justQuit = OMX_FALSE;
  59. static OMX_ERRORTYPE event_handler(
  60. OMX_HANDLETYPE hComponent,
  61. OMX_PTR pAppData,
  62. OMX_EVENTTYPE eEvent,
  63. OMX_U32 nData1,
  64. OMX_U32 nData2,
  65. OMX_PTR pEventData)
  66. {
  67. EncodeTestContext *pEncodeTestContext = (EncodeTestContext *)pAppData;
  68. switch (eEvent)
  69. {
  70. case OMX_EventPortSettingsChanged:
  71. {
  72. OMX_PARAM_PORTDEFINITIONTYPE pOutputPortDefinition;
  73. OMX_INIT_STRUCTURE(pOutputPortDefinition);
  74. pOutputPortDefinition.nPortIndex = 1;
  75. OMX_GetParameter(pEncodeTestContext->hComponentEncoder, OMX_IndexParamPortDefinition, &pOutputPortDefinition);
  76. OMX_U32 nOutputBufferSize = pOutputPortDefinition.nBufferSize;
  77. OMX_U32 nOutputBufferCount = pOutputPortDefinition.nBufferCountMin;
  78. printf("enable output port and alloc buffer\n");
  79. OMX_SendCommand(pEncodeTestContext->hComponentEncoder, OMX_CommandPortEnable, 1, NULL);
  80. for (int i = 0; i < nOutputBufferCount; i++)
  81. {
  82. OMX_BUFFERHEADERTYPE *pBuffer = NULL;
  83. OMX_AllocateBuffer(hComponent, &pBuffer, 1, NULL, nOutputBufferSize);
  84. pEncodeTestContext->pOutputBufferArray[i] = pBuffer;
  85. OMX_FillThisBuffer(hComponent, pBuffer);
  86. }
  87. }
  88. break;
  89. case OMX_EventBufferFlag:
  90. {
  91. Message data;
  92. data.msg_type = 1;
  93. data.msg_flag = -1;
  94. if (msgsnd(pEncodeTestContext->msgid, (void *)&data, sizeof(data) - sizeof(data.msg_type), 0) == -1)
  95. {
  96. fprintf(stderr, "msgsnd failed\n");
  97. }
  98. }
  99. break;
  100. case OMX_EventCmdComplete:
  101. {
  102. switch ((OMX_COMMANDTYPE)(nData1))
  103. {
  104. case OMX_CommandStateSet:
  105. {
  106. pEncodeTestContext->comState = (OMX_STATETYPE)(nData2);
  107. }
  108. case OMX_CommandPortDisable:
  109. {
  110. if (nData2 == 1)
  111. disableEVnt = OMX_TRUE;
  112. }
  113. break;
  114. default:
  115. break;
  116. }
  117. }
  118. break;
  119. case OMX_EventError:
  120. {
  121. printf("receive err event %d %d\n", nData1, nData2);
  122. justQuit = OMX_TRUE;
  123. }
  124. break;
  125. default:
  126. break;
  127. }
  128. return OMX_ErrorNone;
  129. }
  130. static void help()
  131. {
  132. printf("video_enc_test - omx video hardware encode unit test case\r\n\r\n");
  133. printf("Usage:\r\n\r\n");
  134. printf("./video_enc_test -i <input file> input file \r\n");
  135. printf(" -o <output file> output file \r\n");
  136. printf(" -w <width> input width \r\n");
  137. printf(" -h <height> input hight \r\n");
  138. printf(" -s <Srcformat> stream format h264/h265 \r\n");
  139. printf(" -c <cformat> color format i420/nv12/nv21 \r\n");
  140. printf(" -b <bitrate> (optional) set bit rate \r\n");
  141. printf(" -v <frame rate> (optional) set frame rate \r\n");
  142. printf(" -g <num> (optional) Number of P frames between each I frame\r\n\r\n");
  143. printf("./video_enc_test --help: show this message\r\n");
  144. }
  145. static OMX_ERRORTYPE fill_output_buffer_done_handler(
  146. OMX_HANDLETYPE hComponent,
  147. OMX_PTR pAppData,
  148. OMX_BUFFERHEADERTYPE *pBuffer)
  149. {
  150. EncodeTestContext *pEncodeTestContext = (EncodeTestContext *)pAppData;
  151. Message data;
  152. data.msg_type = 1;
  153. if (pBuffer->nFlags & OMX_BUFFERFLAG_EOS)
  154. {
  155. data.msg_flag = -1;
  156. }
  157. else
  158. {
  159. data.msg_flag = 1;
  160. data.pBuffer = pBuffer;
  161. }
  162. if (msgsnd(pEncodeTestContext->msgid, (void *)&data, sizeof(data) - sizeof(data.msg_type), 0) == -1)
  163. {
  164. fprintf(stderr, "msgsnd failed\n");
  165. }
  166. return OMX_ErrorNone;
  167. }
  168. static OMX_ERRORTYPE empty_buffer_done_handler(
  169. OMX_HANDLETYPE hComponent,
  170. OMX_PTR pAppData,
  171. OMX_BUFFERHEADERTYPE *pBuffer)
  172. {
  173. EncodeTestContext *pEncodeTestContext = (EncodeTestContext *)pAppData;
  174. Message data;
  175. data.msg_type = 1;
  176. data.msg_flag = 0;
  177. data.pBuffer = pBuffer;
  178. if (msgsnd(pEncodeTestContext->msgid, (void *)&data, sizeof(data) - sizeof(data.msg_type), 0) == -1)
  179. {
  180. fprintf(stderr, "msgsnd failed\n");
  181. }
  182. return OMX_ErrorNone;
  183. }
  184. static void signal_handle(int sig)
  185. {
  186. printf("[%s,%d]: receive sig=%d \n", __FUNCTION__, __LINE__, sig);
  187. OMX_FreeHandle(encodeTestContext->hComponentEncoder);
  188. OMX_Deinit();
  189. if (fb)
  190. fclose(fb);
  191. if (encodeTestContext->pInputFile)
  192. fclose(encodeTestContext->pInputFile);
  193. exit(0);
  194. // Message data;
  195. // data.msg_type = 1;
  196. // data.msg_flag = -1;
  197. // if (msgsnd(encodeTestContext->msgid, (void *)&data, sizeof(data) - sizeof(data.msg_type), 0) == -1)
  198. // {
  199. // fprintf(stderr, "msgsnd failed\n");
  200. // }
  201. }
  202. static OMX_S32 FillInputBuffer(EncodeTestContext *encodeTestContext, OMX_BUFFERHEADERTYPE *pInputBuffer)
  203. {
  204. FILE *fp = encodeTestContext->pInputFile;
  205. OMX_U32 size = encodeTestContext->nFrameBufferSize;
  206. OMX_U32 count;
  207. if (inputEndFlag)
  208. {
  209. pInputBuffer->nFlags = 0;
  210. pInputBuffer->nFilledLen = 0;
  211. return 0;
  212. }
  213. count = fread(pInputBuffer->pBuffer, 1, size, fp);
  214. if (count < size)
  215. {
  216. pInputBuffer->nFlags = 0x1;
  217. pInputBuffer->nFilledLen = 0;
  218. count = 0;
  219. inputEndFlag = OMX_TRUE;
  220. }
  221. else
  222. {
  223. pInputBuffer->nFlags = 0x10;
  224. pInputBuffer->nFilledLen = size;
  225. }
  226. return count;
  227. }
  228. int main(int argc, char **argv)
  229. {
  230. printf("=============================\r\n");
  231. encodeTestContext = malloc(sizeof(EncodeTestContext));
  232. memset(encodeTestContext, 0, sizeof(EncodeTestContext));
  233. OMX_S32 msgid = -1;
  234. msgid = msgget(IPC_PRIVATE, 0666 | IPC_CREAT);
  235. if (msgid < 0)
  236. {
  237. perror("get ipc_id error");
  238. return -1;
  239. }
  240. encodeTestContext->msgid = msgid;
  241. struct option longOpt[] = {
  242. {"output", required_argument, NULL, 'o'},
  243. {"input", required_argument, NULL, 'f'},
  244. {"colorformat", required_argument, NULL, 'c'},
  245. {"streamformat", required_argument, NULL, 's'},
  246. {"bitrate", required_argument, NULL, 'b'},
  247. {"framerate", required_argument, NULL, 'v'},
  248. {"width", required_argument, NULL, 'w'},
  249. {"height", required_argument, NULL, 'h'},
  250. {"gop", required_argument, NULL, 'g'},
  251. {"help", no_argument, NULL, 0},
  252. {NULL, no_argument, NULL, 0},
  253. };
  254. char *shortOpt = "i:o:f:s:w:h:b:v:c:g:";
  255. OMX_U32 c;
  256. OMX_S32 l;
  257. if (argc == 0)
  258. {
  259. help();
  260. return 0;
  261. }
  262. OMX_U32 width = 0;
  263. OMX_U32 height = 0;
  264. while ((c = getopt_long(argc, argv, shortOpt, longOpt, (int *)&l)) != -1)
  265. {
  266. switch (c)
  267. {
  268. case 'i':
  269. printf("input: %s\r\n", optarg);
  270. if (access(optarg, R_OK) != -1)
  271. {
  272. memcpy(encodeTestContext->sInputFilePath, optarg, strlen(optarg));
  273. encodeTestContext->pInputFile = fopen(optarg, "r");
  274. }
  275. else
  276. {
  277. printf("input file not exist!\r\n");
  278. return -1;
  279. }
  280. break;
  281. case 'o':
  282. printf("output: %s\r\n", optarg);
  283. memcpy(encodeTestContext->sOutputFilePath, optarg, strlen(optarg));
  284. break;
  285. case 'c':
  286. printf("color format: %s\r\n", optarg);
  287. memcpy(encodeTestContext->sInputFormat, optarg, strlen(optarg));
  288. break;
  289. case 's':
  290. printf("stream format: %s\r\n", optarg);
  291. memcpy(encodeTestContext->sOutputFormat, optarg, strlen(optarg));
  292. break;
  293. case 'w':
  294. printf("width: %s\r\n", optarg);
  295. width = atoi(optarg);
  296. break;
  297. case 'h':
  298. printf("height: %s\r\n", optarg);
  299. height = atoi(optarg);
  300. break;
  301. case 'b':
  302. printf("bit rate: %s\r\n", optarg);
  303. encodeTestContext->nBitrate = atoi(optarg);
  304. break;
  305. case 'v':
  306. printf("frame rate: %s\r\n", optarg);
  307. encodeTestContext->nFrameRate = atoi(optarg);
  308. break;
  309. case 'g':
  310. printf("P frames: %s\r\n", optarg);
  311. encodeTestContext->nNumPFrame = atoi(optarg);
  312. break;
  313. case 0:
  314. default:
  315. help();
  316. return 0;
  317. }
  318. }
  319. encodeTestContext->nFrameBufferSize = width * height * 3 / 2;
  320. if (encodeTestContext == NULL ||
  321. encodeTestContext->nFrameBufferSize == 0 ||
  322. encodeTestContext->pInputFile == NULL)
  323. {
  324. help();
  325. return -1;
  326. }
  327. /*omx init*/
  328. OMX_HANDLETYPE hComponentEncoder = NULL;
  329. OMX_CALLBACKTYPE callbacks;
  330. int ret = OMX_ErrorNone;
  331. signal(SIGINT, signal_handle);
  332. printf("init omx\r\n");
  333. ret = OMX_Init();
  334. if (ret != OMX_ErrorNone)
  335. {
  336. printf("[%s,%d]: run OMX_Init failed. ret is %d \n", __FUNCTION__, __LINE__, ret);
  337. if (encodeTestContext->pInputFile)
  338. fclose(encodeTestContext->pInputFile);
  339. return 1;
  340. }
  341. callbacks.EventHandler = event_handler;
  342. callbacks.FillBufferDone = fill_output_buffer_done_handler;
  343. callbacks.EmptyBufferDone = empty_buffer_done_handler;
  344. printf("get handle %s\r\n", encodeTestContext->sOutputFormat);
  345. if (strstr(encodeTestContext->sOutputFormat, "h265") != NULL)
  346. {
  347. OMX_GetHandle(&hComponentEncoder, "OMX.sf.video_encoder.hevc", encodeTestContext, &callbacks);
  348. }
  349. if (hComponentEncoder == NULL)
  350. {
  351. printf("could not get handle\r\n");
  352. OMX_Deinit();
  353. if (encodeTestContext->pInputFile)
  354. fclose(encodeTestContext->pInputFile);
  355. return 0;
  356. }
  357. encodeTestContext->hComponentEncoder = hComponentEncoder;
  358. OMX_PARAM_PORTDEFINITIONTYPE pInputPortDefinition;
  359. OMX_INIT_STRUCTURE(pInputPortDefinition);
  360. pInputPortDefinition.nPortIndex = 0;
  361. OMX_GetParameter(hComponentEncoder, OMX_IndexParamPortDefinition, &pInputPortDefinition);
  362. pInputPortDefinition.format.video.nFrameWidth = width;
  363. pInputPortDefinition.format.video.nFrameHeight = height;
  364. if (strstr(encodeTestContext->sInputFormat, "i420") != NULL)
  365. {
  366. pInputPortDefinition.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
  367. }
  368. else if (strstr(encodeTestContext->sInputFormat, "nv12") != NULL)
  369. {
  370. pInputPortDefinition.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
  371. }
  372. else if (strstr(encodeTestContext->sInputFormat, "nv21") != NULL)
  373. {
  374. pInputPortDefinition.format.video.eColorFormat = OMX_COLOR_FormatYVU420SemiPlanar;
  375. }
  376. else
  377. {
  378. printf("unsupported color format: %s\r\n", encodeTestContext->sInputFormat);
  379. goto end;
  380. }
  381. if(encodeTestContext->nFrameRate){
  382. pInputPortDefinition.format.video.xFramerate = encodeTestContext->nFrameRate;
  383. }
  384. OMX_SetParameter(hComponentEncoder, OMX_IndexParamPortDefinition, &pInputPortDefinition);
  385. OMX_GetParameter(hComponentEncoder, OMX_IndexParamPortDefinition, &pInputPortDefinition);
  386. OMX_PARAM_PORTDEFINITIONTYPE pOutputPortDefinition;
  387. OMX_INIT_STRUCTURE(pOutputPortDefinition);
  388. pOutputPortDefinition.nPortIndex = 1;
  389. OMX_GetParameter(hComponentEncoder, OMX_IndexParamPortDefinition, &pOutputPortDefinition);
  390. pOutputPortDefinition.format.video.nFrameWidth = width;
  391. pOutputPortDefinition.format.video.nFrameHeight = height;
  392. pOutputPortDefinition.format.video.nBitrate = encodeTestContext->nBitrate;
  393. OMX_SetParameter(hComponentEncoder, OMX_IndexParamPortDefinition, &pOutputPortDefinition);
  394. if(encodeTestContext->nNumPFrame){
  395. if (strstr(encodeTestContext->sOutputFormat, "h264") != NULL)
  396. {
  397. OMX_VIDEO_PARAM_AVCTYPE avcType;
  398. OMX_INIT_STRUCTURE(avcType);
  399. avcType.nPortIndex = 1;
  400. OMX_GetParameter(hComponentEncoder, OMX_IndexParamVideoAvc, &avcType);
  401. avcType.nPFrames = encodeTestContext->nNumPFrame;
  402. OMX_SetParameter(hComponentEncoder, OMX_IndexParamVideoAvc, &avcType);
  403. }
  404. else if (strstr(encodeTestContext->sOutputFormat, "h265") != NULL)
  405. {
  406. OMX_VIDEO_PARAM_HEVCTYPE hevcType;
  407. OMX_INIT_STRUCTURE(hevcType);
  408. hevcType.nPortIndex = 1;
  409. OMX_GetParameter(hComponentEncoder, OMX_IndexParamVideoHevc, &hevcType);
  410. hevcType.nKeyFrameInterval = encodeTestContext->nNumPFrame;
  411. OMX_SetParameter(hComponentEncoder, OMX_IndexParamVideoHevc, &hevcType);
  412. }
  413. }
  414. /*Alloc input buffer*/
  415. OMX_U32 nInputBufferSize = pInputPortDefinition.nBufferSize;
  416. OMX_U32 nInputBufferCount = pInputPortDefinition.nBufferCountActual;
  417. disableEVnt = OMX_FALSE;
  418. OMX_SendCommand(hComponentEncoder, OMX_CommandPortDisable, 1, NULL);
  419. printf("wait for output port disable\r\n");
  420. while (!disableEVnt && !justQuit);
  421. if (justQuit)
  422. goto end;
  423. printf("output port disabled\r\n");
  424. OMX_SendCommand(hComponentEncoder, OMX_CommandStateSet, OMX_StateIdle, NULL);
  425. for (int i = 0; i < nInputBufferCount; i++)
  426. {
  427. OMX_BUFFERHEADERTYPE *pBuffer = NULL;
  428. OMX_AllocateBuffer(hComponentEncoder, &pBuffer, 0, NULL, nInputBufferSize);
  429. encodeTestContext->pInputBufferArray[i] = pBuffer;
  430. }
  431. printf("wait for Component idle\r\n");
  432. while (encodeTestContext->comState != OMX_StateIdle && !justQuit);
  433. if (justQuit)
  434. goto end;
  435. printf("Component in idle\r\n");
  436. for (int i = 0; i < nInputBufferCount; i++)
  437. {
  438. /*Fill Input Buffer*/
  439. FillInputBuffer(encodeTestContext, encodeTestContext->pInputBufferArray[i]);
  440. if (encodeTestContext->pInputBufferArray[i]->nFilledLen || encodeTestContext->pInputBufferArray[i]->nFlags)
  441. OMX_EmptyThisBuffer(hComponentEncoder, encodeTestContext->pInputBufferArray[i]);
  442. }
  443. fb = fopen(encodeTestContext->sOutputFilePath, "wb+");
  444. printf("start process\r\n");
  445. OMX_SendCommand(hComponentEncoder, OMX_CommandStateSet, OMX_StateExecuting, NULL);
  446. /*wait until decode finished*/
  447. Message data;
  448. while (OMX_TRUE)
  449. {
  450. if (msgrcv(msgid, (void *)&data, BUFSIZ, 0, 0) == -1)
  451. {
  452. fprintf(stderr, "msgrcv failed with errno: %d\n", errno);
  453. goto end;
  454. }
  455. switch (data.msg_flag)
  456. {
  457. case 0:
  458. {
  459. OMX_BUFFERHEADERTYPE *pBuffer = data.pBuffer;
  460. FillInputBuffer(encodeTestContext, pBuffer);
  461. if (pBuffer->nFilledLen || pBuffer->nFlags)
  462. OMX_EmptyThisBuffer(encodeTestContext->hComponentEncoder, pBuffer);
  463. }
  464. break;
  465. case 1:
  466. {
  467. OMX_BUFFERHEADERTYPE *pBuffer = data.pBuffer;
  468. fwrite(pBuffer->pBuffer, 1, pBuffer->nFilledLen, fb);
  469. if (pBuffer->nFlags & OMX_BUFFERFLAG_EOS)
  470. {
  471. goto end;
  472. }
  473. else
  474. {
  475. OMX_FillThisBuffer(encodeTestContext->hComponentEncoder, pBuffer);
  476. }
  477. }
  478. break;
  479. case 2:
  480. break;
  481. default:
  482. goto end;
  483. }
  484. }
  485. end:
  486. /*free resource*/
  487. if (encodeTestContext->comState == OMX_StateExecuting)
  488. {
  489. OMX_SendCommand(hComponentEncoder, OMX_CommandStateSet, OMX_StateIdle, NULL);
  490. printf("wait for Component idle\r\n");
  491. while (encodeTestContext->comState != OMX_StateIdle && !justQuit);
  492. printf("Component in idle\r\n");
  493. }
  494. OMX_FreeHandle(hComponentEncoder);
  495. OMX_Deinit();
  496. if (fb)
  497. fclose(fb);
  498. if (encodeTestContext->pInputFile)
  499. fclose(encodeTestContext->pInputFile);
  500. }