enc_test.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2021 StarFive Technology Co., Ltd.
  4. */
  5. #include <stdio.h>
  6. #include <signal.h>
  7. #include <getopt.h>
  8. #include <fcntl.h>
  9. #include <OMX_Core.h>
  10. #include <OMX_Component.h>
  11. #include <OMX_Video.h>
  12. #include <OMX_IndexExt.h>
  13. #include <sys/time.h>
  14. #include <sys/types.h>
  15. #include <sys/ipc.h>
  16. #include <sys/msg.h>
  17. #include <errno.h>
  18. #include <string.h>
  19. #include <stdlib.h>
  20. #define OMX_INIT_STRUCTURE(a) \
  21. memset(&(a), 0, sizeof(a)); \
  22. (a).nSize = sizeof(a); \
  23. (a).nVersion.nVersion = 1; \
  24. (a).nVersion.s.nVersionMajor = 1; \
  25. (a).nVersion.s.nVersionMinor = 1; \
  26. (a).nVersion.s.nRevision = 1; \
  27. (a).nVersion.s.nStep = 1
  28. typedef struct Message
  29. {
  30. long msg_type;
  31. OMX_S32 msg_flag;
  32. OMX_BUFFERHEADERTYPE *pBuffer;
  33. } Message;
  34. typedef struct EncodeTestContext
  35. {
  36. OMX_HANDLETYPE hComponentEncoder;
  37. char sOutputFilePath[64];
  38. char sInputFilePath[64];
  39. FILE *pInputFile;
  40. char sInputFormat[64];
  41. char sOutputFormat[64];
  42. OMX_U32 nFrameBufferSize;
  43. OMX_U32 nBitrate;
  44. OMX_BUFFERHEADERTYPE *pInputBufferArray[64];
  45. OMX_BUFFERHEADERTYPE *pOutputBufferArray[64];
  46. int msgid;
  47. } EncodeTestContext;
  48. EncodeTestContext *encodeTestContext;
  49. static OMX_S32 FillInputBuffer(EncodeTestContext *encodeTestContext, OMX_BUFFERHEADERTYPE *pInputBuffer);
  50. static OMX_ERRORTYPE event_handler(
  51. OMX_HANDLETYPE hComponent,
  52. OMX_PTR pAppData,
  53. OMX_EVENTTYPE eEvent,
  54. OMX_U32 nData1,
  55. OMX_U32 nData2,
  56. OMX_PTR pEventData)
  57. {
  58. EncodeTestContext *pEncodeTestContext = (EncodeTestContext *)pAppData;
  59. switch (eEvent)
  60. {
  61. case OMX_EventPortSettingsChanged:
  62. {
  63. OMX_PARAM_PORTDEFINITIONTYPE pOutputPortDefinition;
  64. OMX_INIT_STRUCTURE(pOutputPortDefinition);
  65. pOutputPortDefinition.nPortIndex = 1;
  66. OMX_GetParameter(pEncodeTestContext->hComponentEncoder, OMX_IndexParamPortDefinition, &pOutputPortDefinition);
  67. OMX_U32 nOutputBufferSize = pOutputPortDefinition.nBufferSize;
  68. OMX_U32 nOutputBufferCount = pOutputPortDefinition.nBufferCountMin;
  69. for (int i = 0; i < nOutputBufferCount; i++)
  70. {
  71. OMX_BUFFERHEADERTYPE *pBuffer = NULL;
  72. OMX_AllocateBuffer(hComponent, &pBuffer, 1, NULL, nOutputBufferSize);
  73. pEncodeTestContext->pOutputBufferArray[i] = pBuffer;
  74. OMX_FillThisBuffer(hComponent, pBuffer);
  75. }
  76. }
  77. break;
  78. case OMX_EventBufferFlag:
  79. {
  80. Message data;
  81. data.msg_type = 1;
  82. data.msg_flag = -1;
  83. if (msgsnd(pEncodeTestContext->msgid, (void *)&data, sizeof(data) - sizeof(data.msg_type), 0) == -1)
  84. {
  85. fprintf(stderr, "msgsnd failed\n");
  86. }
  87. }
  88. break;
  89. default:
  90. break;
  91. }
  92. return OMX_ErrorNone;
  93. }
  94. static void help()
  95. {
  96. printf("./video_enc_test -i <input file> -o <output file> -w <width> -h <height> "
  97. "-c <yuv/nv12/nv21> -s <h264/h265> -b <bitrate>\r\n");
  98. }
  99. static OMX_ERRORTYPE fill_output_buffer_done_handler(
  100. OMX_HANDLETYPE hComponent,
  101. OMX_PTR pAppData,
  102. OMX_BUFFERHEADERTYPE *pBuffer)
  103. {
  104. EncodeTestContext *pEncodeTestContext = (EncodeTestContext *)pAppData;
  105. Message data;
  106. data.msg_type = 1;
  107. if ((pBuffer->nFlags) & (OMX_BUFFERFLAG_EOS == OMX_BUFFERFLAG_EOS))
  108. {
  109. data.msg_flag = -1;
  110. }
  111. else
  112. {
  113. data.msg_flag = 1;
  114. data.pBuffer = pBuffer;
  115. }
  116. if (msgsnd(pEncodeTestContext->msgid, (void *)&data, sizeof(data) - sizeof(data.msg_type), 0) == -1)
  117. {
  118. fprintf(stderr, "msgsnd failed\n");
  119. }
  120. return OMX_ErrorNone;
  121. }
  122. static OMX_ERRORTYPE empty_buffer_done_handler(
  123. OMX_HANDLETYPE hComponent,
  124. OMX_PTR pAppData,
  125. OMX_BUFFERHEADERTYPE *pBuffer)
  126. {
  127. EncodeTestContext *pEncodeTestContext = (EncodeTestContext *)pAppData;
  128. Message data;
  129. data.msg_type = 1;
  130. data.msg_flag = 0;
  131. data.pBuffer = pBuffer;
  132. if (msgsnd(pEncodeTestContext->msgid, (void *)&data, sizeof(data) - sizeof(data.msg_type), 0) == -1)
  133. {
  134. fprintf(stderr, "msgsnd failed\n");
  135. }
  136. return OMX_ErrorNone;
  137. }
  138. static void signal_handle(int sig)
  139. {
  140. printf("[%s,%d]: receive sig=%d \n", __FUNCTION__, __LINE__, sig);
  141. OMX_FreeHandle(encodeTestContext->hComponentEncoder);
  142. OMX_Deinit();
  143. exit(0);
  144. // Message data;
  145. // data.msg_type = 1;
  146. // data.msg_flag = -1;
  147. // if (msgsnd(encodeTestContext->msgid, (void *)&data, sizeof(data) - sizeof(data.msg_type), 0) == -1)
  148. // {
  149. // fprintf(stderr, "msgsnd failed\n");
  150. // }
  151. }
  152. static OMX_S32 FillInputBuffer(EncodeTestContext *encodeTestContext, OMX_BUFFERHEADERTYPE *pInputBuffer)
  153. {
  154. FILE *fp = encodeTestContext->pInputFile;
  155. OMX_U32 size = encodeTestContext->nFrameBufferSize;
  156. OMX_U32 count;
  157. count = fread(pInputBuffer->pBuffer, 1, size, fp);
  158. if (count < size)
  159. {
  160. Message data;
  161. data.msg_type = 1;
  162. data.msg_flag = -1;
  163. pInputBuffer->nFlags = 0x1;
  164. pInputBuffer->nFilledLen = 0;
  165. count = 0;
  166. if (msgsnd(encodeTestContext->msgid, (void *)&data, sizeof(data) - sizeof(data.msg_type), 0) == -1)
  167. {
  168. fprintf(stderr, "msgsnd failed\n");
  169. }
  170. }
  171. else
  172. {
  173. pInputBuffer->nFlags = 0x10;
  174. pInputBuffer->nFilledLen = size;
  175. }
  176. return count;
  177. }
  178. int main(int argc, char **argv)
  179. {
  180. printf("=============================\r\n");
  181. encodeTestContext = malloc(sizeof(EncodeTestContext));
  182. memset(encodeTestContext, 0, sizeof(EncodeTestContext));
  183. OMX_S32 msgid = -1;
  184. msgid = msgget(IPC_PRIVATE, 0666 | IPC_CREAT);
  185. if (msgid < 0)
  186. {
  187. perror("get ipc_id error");
  188. return -1;
  189. }
  190. encodeTestContext->msgid = msgid;
  191. struct option longOpt[] = {
  192. {"output", required_argument, NULL, 'o'},
  193. {"input", required_argument, NULL, 'f'},
  194. {"color format", required_argument, NULL, 'c'},
  195. {"stream format", required_argument, NULL, 's'},
  196. {"bit rate", optional_argument, NULL, 'b'},
  197. {"width", required_argument, NULL, 'w'},
  198. {"height", required_argument, NULL, 'h'},
  199. {NULL, no_argument, NULL, 0},
  200. };
  201. char *shortOpt = "i:o:f:s:w:h:b:c:";
  202. OMX_U32 c;
  203. OMX_S32 l;
  204. if (argc == 0)
  205. {
  206. help();
  207. return 0;
  208. }
  209. OMX_U32 width = 0;
  210. OMX_U32 height = 0;
  211. while ((c = getopt_long(argc, argv, shortOpt, longOpt, (int *)&l)) != -1)
  212. {
  213. switch (c)
  214. {
  215. case 'i':
  216. printf("input: %s\r\n", optarg);
  217. if (access(optarg, R_OK) != -1)
  218. {
  219. memcpy(encodeTestContext->sInputFilePath, optarg, strlen(optarg));
  220. encodeTestContext->pInputFile = fopen(optarg, "r");
  221. }
  222. else
  223. {
  224. printf("input file not exist!\r\n");
  225. return -1;
  226. }
  227. break;
  228. case 'o':
  229. printf("output: %s\r\n", optarg);
  230. memcpy(encodeTestContext->sOutputFilePath, optarg, strlen(optarg));
  231. break;
  232. case 'c':
  233. printf("color format: %s\r\n", optarg);
  234. memcpy(encodeTestContext->sInputFormat, optarg, strlen(optarg));
  235. break;
  236. case 's':
  237. printf("stream format: %s\r\n", optarg);
  238. memcpy(encodeTestContext->sOutputFormat, optarg, strlen(optarg));
  239. break;
  240. case 'w':
  241. printf("width: %s\r\n", optarg);
  242. width = atoi(optarg);
  243. break;
  244. case 'h':
  245. printf("height: %s\r\n", optarg);
  246. height = atoi(optarg);
  247. break;
  248. case 'b':
  249. printf("bit rate: %s\r\n", optarg);
  250. encodeTestContext->nBitrate = atoi(optarg);
  251. break;
  252. default:
  253. help();
  254. return 0;
  255. }
  256. }
  257. encodeTestContext->nFrameBufferSize = width * height * 3 / 2;
  258. if (encodeTestContext->sInputFilePath == NULL ||
  259. encodeTestContext->sOutputFilePath == NULL ||
  260. encodeTestContext->nFrameBufferSize == 0 ||
  261. encodeTestContext->pInputFile == NULL)
  262. {
  263. help();
  264. return -1;
  265. }
  266. /*omx init*/
  267. OMX_HANDLETYPE hComponentEncoder = NULL;
  268. OMX_CALLBACKTYPE callbacks;
  269. int ret = OMX_ErrorNone;
  270. signal(SIGINT, signal_handle);
  271. printf("init omx\r\n");
  272. ret = OMX_Init();
  273. if (ret != OMX_ErrorNone)
  274. {
  275. printf("[%s,%d]: run OMX_Init failed. ret is %d \n", __FUNCTION__, __LINE__, ret);
  276. return 1;
  277. }
  278. callbacks.EventHandler = event_handler;
  279. callbacks.FillBufferDone = fill_output_buffer_done_handler;
  280. callbacks.EmptyBufferDone = empty_buffer_done_handler;
  281. printf("get handle %s\r\n", encodeTestContext->sOutputFormat);
  282. if (strstr(encodeTestContext->sOutputFormat, "h264") != NULL)
  283. {
  284. OMX_GetHandle(&hComponentEncoder, "sf.enc.encoder.h264", encodeTestContext, &callbacks);
  285. }
  286. else if (strstr(encodeTestContext->sOutputFormat, "h265") != NULL)
  287. {
  288. OMX_GetHandle(&hComponentEncoder, "sf.enc.encoder.h265", encodeTestContext, &callbacks);
  289. }
  290. if (hComponentEncoder == NULL)
  291. {
  292. printf("could not get handle\r\n");
  293. return 0;
  294. }
  295. encodeTestContext->hComponentEncoder = hComponentEncoder;
  296. OMX_PARAM_PORTDEFINITIONTYPE pInputPortDefinition;
  297. OMX_INIT_STRUCTURE(pInputPortDefinition);
  298. pInputPortDefinition.nPortIndex = 0;
  299. OMX_GetParameter(hComponentEncoder, OMX_IndexParamPortDefinition, &pInputPortDefinition);
  300. pInputPortDefinition.format.video.nFrameWidth = width;
  301. pInputPortDefinition.format.video.nFrameHeight = height;
  302. if (strstr(encodeTestContext->sInputFormat, "i420") != NULL)
  303. {
  304. pInputPortDefinition.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
  305. }
  306. else if (strstr(encodeTestContext->sInputFormat, "nv12") != NULL)
  307. {
  308. pInputPortDefinition.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
  309. }
  310. else if (strstr(encodeTestContext->sInputFormat, "nv21") != NULL)
  311. {
  312. pInputPortDefinition.format.video.eColorFormat = OMX_COLOR_FormatYUV420PackedSemiPlanar;
  313. }
  314. else
  315. {
  316. printf("unsupported color format: %s\r\n", encodeTestContext->sInputFormat);
  317. goto end;
  318. }
  319. OMX_SetParameter(hComponentEncoder, OMX_IndexParamPortDefinition, &pInputPortDefinition);
  320. OMX_GetParameter(hComponentEncoder, OMX_IndexParamPortDefinition, &pInputPortDefinition);
  321. OMX_PARAM_PORTDEFINITIONTYPE pOutputPortDefinition;
  322. OMX_INIT_STRUCTURE(pOutputPortDefinition);
  323. pOutputPortDefinition.nPortIndex = 1;
  324. OMX_GetParameter(hComponentEncoder, OMX_IndexParamPortDefinition, &pOutputPortDefinition);
  325. pOutputPortDefinition.format.video.nFrameWidth = width;
  326. pOutputPortDefinition.format.video.nFrameHeight = height;
  327. pOutputPortDefinition.format.video.nBitrate = encodeTestContext->nBitrate;
  328. OMX_SetParameter(hComponentEncoder, OMX_IndexParamPortDefinition, &pOutputPortDefinition);
  329. /*Alloc input buffer*/
  330. OMX_U32 nInputBufferSize = pInputPortDefinition.nBufferSize;
  331. OMX_U32 nInputBufferCount = pInputPortDefinition.nBufferCountActual;
  332. OMX_SendCommand(hComponentEncoder, OMX_CommandStateSet, OMX_StateIdle, NULL);
  333. for (int i = 0; i < nInputBufferCount; i++)
  334. {
  335. OMX_BUFFERHEADERTYPE *pBuffer = NULL;
  336. OMX_AllocateBuffer(hComponentEncoder, &pBuffer, 0, NULL, nInputBufferSize);
  337. encodeTestContext->pInputBufferArray[i] = pBuffer;
  338. /*Fill Input Buffer*/
  339. FillInputBuffer(encodeTestContext, pBuffer);
  340. OMX_EmptyThisBuffer(hComponentEncoder, pBuffer);
  341. }
  342. OMX_SendCommand(hComponentEncoder, OMX_CommandStateSet, OMX_StateExecuting, NULL);
  343. /*wait until decode finished*/
  344. Message data;
  345. while (OMX_TRUE)
  346. {
  347. if (msgrcv(msgid, (void *)&data, BUFSIZ, 0, 0) == -1)
  348. {
  349. fprintf(stderr, "msgrcv failed with errno: %d\n", errno);
  350. goto end;
  351. }
  352. switch (data.msg_flag)
  353. {
  354. case 0:
  355. {
  356. OMX_BUFFERHEADERTYPE *pBuffer = data.pBuffer;
  357. FillInputBuffer(encodeTestContext, pBuffer);
  358. OMX_EmptyThisBuffer(encodeTestContext->hComponentEncoder, pBuffer);
  359. }
  360. break;
  361. case 1:
  362. {
  363. OMX_BUFFERHEADERTYPE *pBuffer = data.pBuffer;
  364. OMX_STRING sFilePath = encodeTestContext->sOutputFilePath;
  365. FILE *fb = fopen(sFilePath, "ab+");
  366. fwrite(pBuffer->pBuffer, 1, pBuffer->nFilledLen, fb);
  367. fclose(fb);
  368. if ((pBuffer->nFlags) & (OMX_BUFFERFLAG_EOS == OMX_BUFFERFLAG_EOS))
  369. {
  370. goto end;
  371. }
  372. else
  373. {
  374. OMX_FillThisBuffer(encodeTestContext->hComponentEncoder, pBuffer);
  375. }
  376. }
  377. break;
  378. case 2:
  379. break;
  380. default:
  381. goto end;
  382. }
  383. }
  384. end:
  385. /*free resource*/
  386. fclose(encodeTestContext->pInputFile);
  387. OMX_FreeHandle(hComponentEncoder);
  388. OMX_Deinit();
  389. }