enc_test.c 16 KB

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