enc_test.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  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. pInputBuffer->nFlags = 0x1;
  161. pInputBuffer->nFilledLen = 0;
  162. count = 0;
  163. }
  164. else
  165. {
  166. pInputBuffer->nFlags = 0x10;
  167. pInputBuffer->nFilledLen = size;
  168. }
  169. return count;
  170. }
  171. int main(int argc, char **argv)
  172. {
  173. printf("=============================\r\n");
  174. encodeTestContext = malloc(sizeof(EncodeTestContext));
  175. memset(encodeTestContext, 0, sizeof(EncodeTestContext));
  176. OMX_S32 msgid = -1;
  177. msgid = msgget(IPC_PRIVATE, 0666 | IPC_CREAT);
  178. if (msgid < 0)
  179. {
  180. perror("get ipc_id error");
  181. return -1;
  182. }
  183. encodeTestContext->msgid = msgid;
  184. struct option longOpt[] = {
  185. {"output", required_argument, NULL, 'o'},
  186. {"input", required_argument, NULL, 'f'},
  187. {"color format", required_argument, NULL, 'c'},
  188. {"stream format", required_argument, NULL, 's'},
  189. {"bit rate", optional_argument, NULL, 'b'},
  190. {"width", required_argument, NULL, 'w'},
  191. {"height", required_argument, NULL, 'h'},
  192. {NULL, no_argument, NULL, 0},
  193. };
  194. char *shortOpt = "i:o:f:s:w:h:b:c:";
  195. OMX_U32 c;
  196. OMX_S32 l;
  197. if (argc == 0)
  198. {
  199. help();
  200. return 0;
  201. }
  202. OMX_U32 width = 0;
  203. OMX_U32 height = 0;
  204. while ((c = getopt_long(argc, argv, shortOpt, longOpt, (int *)&l)) != -1)
  205. {
  206. switch (c)
  207. {
  208. case 'i':
  209. printf("input: %s\r\n", optarg);
  210. if (access(optarg, R_OK) != -1)
  211. {
  212. memcpy(encodeTestContext->sInputFilePath, optarg, strlen(optarg));
  213. encodeTestContext->pInputFile = fopen(optarg, "r");
  214. }
  215. else
  216. {
  217. printf("input file not exist!\r\n");
  218. return -1;
  219. }
  220. break;
  221. case 'o':
  222. printf("output: %s\r\n", optarg);
  223. memcpy(encodeTestContext->sOutputFilePath, optarg, strlen(optarg));
  224. break;
  225. case 'c':
  226. printf("color format: %s\r\n", optarg);
  227. memcpy(encodeTestContext->sInputFormat, optarg, strlen(optarg));
  228. break;
  229. case 's':
  230. printf("stream format: %s\r\n", optarg);
  231. memcpy(encodeTestContext->sOutputFormat, optarg, strlen(optarg));
  232. break;
  233. case 'w':
  234. printf("width: %s\r\n", optarg);
  235. width = atoi(optarg);
  236. break;
  237. case 'h':
  238. printf("height: %s\r\n", optarg);
  239. height = atoi(optarg);
  240. break;
  241. case 'b':
  242. printf("bit rate: %s\r\n", optarg);
  243. encodeTestContext->nBitrate = atoi(optarg);
  244. break;
  245. default:
  246. help();
  247. return 0;
  248. }
  249. }
  250. encodeTestContext->nFrameBufferSize = width * height * 3 / 2;
  251. if (encodeTestContext->sInputFilePath == NULL ||
  252. encodeTestContext->sOutputFilePath == NULL ||
  253. encodeTestContext->nFrameBufferSize == 0 ||
  254. encodeTestContext->pInputFile == NULL)
  255. {
  256. help();
  257. return -1;
  258. }
  259. /*omx init*/
  260. OMX_HANDLETYPE hComponentEncoder = NULL;
  261. OMX_CALLBACKTYPE callbacks;
  262. int ret = OMX_ErrorNone;
  263. signal(SIGINT, signal_handle);
  264. printf("init omx\r\n");
  265. ret = OMX_Init();
  266. if (ret != OMX_ErrorNone)
  267. {
  268. printf("[%s,%d]: run OMX_Init failed. ret is %d \n", __FUNCTION__, __LINE__, ret);
  269. return 1;
  270. }
  271. callbacks.EventHandler = event_handler;
  272. callbacks.FillBufferDone = fill_output_buffer_done_handler;
  273. callbacks.EmptyBufferDone = empty_buffer_done_handler;
  274. printf("get handle %s\r\n", encodeTestContext->sOutputFormat);
  275. if (strstr(encodeTestContext->sOutputFormat, "h264") != NULL)
  276. {
  277. OMX_GetHandle(&hComponentEncoder, "sf.enc.encoder.h264", encodeTestContext, &callbacks);
  278. }
  279. else if (strstr(encodeTestContext->sOutputFormat, "h265") != NULL)
  280. {
  281. OMX_GetHandle(&hComponentEncoder, "sf.enc.encoder.h265", encodeTestContext, &callbacks);
  282. }
  283. if (hComponentEncoder == NULL)
  284. {
  285. printf("could not get handle\r\n");
  286. return 0;
  287. }
  288. encodeTestContext->hComponentEncoder = hComponentEncoder;
  289. OMX_PARAM_PORTDEFINITIONTYPE pInputPortDefinition;
  290. OMX_INIT_STRUCTURE(pInputPortDefinition);
  291. pInputPortDefinition.nPortIndex = 0;
  292. OMX_GetParameter(hComponentEncoder, OMX_IndexParamPortDefinition, &pInputPortDefinition);
  293. pInputPortDefinition.format.video.nFrameWidth = width;
  294. pInputPortDefinition.format.video.nFrameHeight = height;
  295. if (strstr(encodeTestContext->sInputFormat, "i420") != NULL)
  296. {
  297. pInputPortDefinition.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
  298. }
  299. else if (strstr(encodeTestContext->sInputFormat, "nv12") != NULL)
  300. {
  301. pInputPortDefinition.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
  302. }
  303. else if (strstr(encodeTestContext->sInputFormat, "nv21") != NULL)
  304. {
  305. pInputPortDefinition.format.video.eColorFormat = OMX_COLOR_FormatYUV420PackedSemiPlanar;
  306. }
  307. else
  308. {
  309. printf("unsupported color format: %s\r\n", encodeTestContext->sInputFormat);
  310. goto end;
  311. }
  312. OMX_SetParameter(hComponentEncoder, OMX_IndexParamPortDefinition, &pInputPortDefinition);
  313. OMX_GetParameter(hComponentEncoder, OMX_IndexParamPortDefinition, &pInputPortDefinition);
  314. OMX_PARAM_PORTDEFINITIONTYPE pOutputPortDefinition;
  315. OMX_INIT_STRUCTURE(pOutputPortDefinition);
  316. pOutputPortDefinition.nPortIndex = 1;
  317. OMX_GetParameter(hComponentEncoder, OMX_IndexParamPortDefinition, &pOutputPortDefinition);
  318. pOutputPortDefinition.format.video.nFrameWidth = width;
  319. pOutputPortDefinition.format.video.nFrameHeight = height;
  320. pOutputPortDefinition.format.video.nBitrate = encodeTestContext->nBitrate;
  321. OMX_SetParameter(hComponentEncoder, OMX_IndexParamPortDefinition, &pOutputPortDefinition);
  322. /*Alloc input buffer*/
  323. OMX_U32 nInputBufferSize = pInputPortDefinition.nBufferSize;
  324. OMX_U32 nInputBufferCount = pInputPortDefinition.nBufferCountActual;
  325. OMX_SendCommand(hComponentEncoder, OMX_CommandStateSet, OMX_StateIdle, NULL);
  326. for (int i = 0; i < nInputBufferCount; i++)
  327. {
  328. OMX_BUFFERHEADERTYPE *pBuffer = NULL;
  329. OMX_AllocateBuffer(hComponentEncoder, &pBuffer, 0, NULL, nInputBufferSize);
  330. encodeTestContext->pInputBufferArray[i] = pBuffer;
  331. /*Fill Input Buffer*/
  332. FillInputBuffer(encodeTestContext, pBuffer);
  333. OMX_EmptyThisBuffer(hComponentEncoder, pBuffer);
  334. }
  335. OMX_SendCommand(hComponentEncoder, OMX_CommandStateSet, OMX_StateExecuting, NULL);
  336. /*wait until decode finished*/
  337. Message data;
  338. while (OMX_TRUE)
  339. {
  340. if (msgrcv(msgid, (void *)&data, BUFSIZ, 0, 0) == -1)
  341. {
  342. fprintf(stderr, "msgrcv failed with errno: %d\n", errno);
  343. goto end;
  344. }
  345. switch (data.msg_flag)
  346. {
  347. case 0:
  348. {
  349. OMX_BUFFERHEADERTYPE *pBuffer = data.pBuffer;
  350. FillInputBuffer(encodeTestContext, pBuffer);
  351. OMX_EmptyThisBuffer(encodeTestContext->hComponentEncoder, pBuffer);
  352. }
  353. break;
  354. case 1:
  355. {
  356. OMX_BUFFERHEADERTYPE *pBuffer = data.pBuffer;
  357. OMX_STRING sFilePath = encodeTestContext->sOutputFilePath;
  358. FILE *fb = fopen(sFilePath, "ab+");
  359. fwrite(pBuffer->pBuffer, 1, pBuffer->nFilledLen, fb);
  360. fclose(fb);
  361. if ((pBuffer->nFlags) & (OMX_BUFFERFLAG_EOS == OMX_BUFFERFLAG_EOS))
  362. {
  363. goto end;
  364. }
  365. else
  366. {
  367. OMX_FillThisBuffer(encodeTestContext->hComponentEncoder, pBuffer);
  368. }
  369. }
  370. break;
  371. case 2:
  372. break;
  373. default:
  374. goto end;
  375. }
  376. }
  377. end:
  378. /*free resource*/
  379. fclose(encodeTestContext->pInputFile);
  380. OMX_FreeHandle(hComponentEncoder);
  381. OMX_Deinit();
  382. }