enc_test.c 12 KB

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