Преглед изворни кода

omx-il: add omx-il unit test for video dec and enc

Signed-off-by: sw.multimedia <sw.multimedia@starfivetech.com>
Andy Hu пре 2 година
родитељ
комит
fca1b9c538
3 измењених фајлова са 795 додато и 1 уклоњено
  1. 19 1
      soft_3rdpart/omx-il/Makefile
  2. 389 0
      soft_3rdpart/omx-il/tests/dec_test.c
  3. 387 0
      soft_3rdpart/omx-il/tests/enc_test.c

+ 19 - 1
soft_3rdpart/omx-il/Makefile

@@ -27,11 +27,13 @@ INCLUDES += -I$(STAGING_DIR)/usr/include/wave511/sample_v2/component_decoder/
 INCLUDES += -I$(STAGING_DIR)/usr/include/wave511/
 INCLUDES += -I$(STAGING_DIR)/usr/include/wave511/vpuapi/
 INCLUDES += -I$(STAGING_DIR)/usr/include/wave511/sample_v2/helper/
+INCLUDES += -I$(STAGING_DIR)/usr/include/
 
 CFLAGS  += -g -I. -Wno-implicit-function-declaration -Wno-format -Wl,--fatal-warning $(INCLUDES) $(DEFINES) $(PLATFORM_FLAGS)
 CFLAGS  += -fpic
 ARFLAGS += cru
 LDFLAGS = -ldl -lpthread
+LDFLAGS_FFMPEG = -lavformat -lavcodec -lavutil -lswresample
 
 OBJDIR=obj
 ALLOBJS=*.o
@@ -41,6 +43,9 @@ RM=rm -f
 MKDIR=mkdir -p
 SOURCES_COMMON = SF_OMX_Core.c SF_OMX_video_common.c 
 SOURCES_COMMON += SF_OMX_Vdec_decoder.c SF_OMX_Venc_encoder.c
+#test
+SOURCES_DEC_TEST = dec_test.c
+SOURCES_ENC_TEST = enc_test.c
 
 VPATH  = component/video/common:
 VPATH += component/video/enc:
@@ -50,11 +55,24 @@ VPATH += tests:
 
 OBJECTNAMES_COMMON=$(patsubst %.c,%.o,$(SOURCES_COMMON))
 OBJECTPATHS_COMMON=$(addprefix $(OBJDIR)/,$(notdir $(OBJECTNAMES_COMMON)))
+OBJECTNAMES_DEC_TEST=$(patsubst %.c,%.o,$(SOURCES_DEC_TEST))
+OBJECTPATHS_DEC_TEST=$(addprefix $(OBJDIR)/,$(notdir $(OBJECTNAMES_DEC_TEST)))
+OBJECTNAMES_ENC_TEST=$(patsubst %.c,%.o,$(SOURCES_ENC_TEST))
+OBJECTPATHS_ENC_TEST=$(addprefix $(OBJDIR)/,$(notdir $(OBJECTNAMES_ENC_TEST)))
 
+all: omx-il
 
-all: CREATE_DIR $(OBJECTPATHS_COMMON)
+omx-il: CREATE_DIR $(OBJECTPATHS_COMMON)
 	$(CC) -fPIC -shared -o libsf-omx-il.so $(LDFLAGS) $(OBJECTPATHS_COMMON)
 
+test: video-dec-test video-enc-test
+
+video-dec-test: CREATE_DIR $(OBJECTPATHS_DEC_TEST)
+	$(CC) -o video_dec_test $(LDFLAGS) $(LDFLAGS_FFMPEG) -lsf-omx-il $(OBJECTPATHS_DEC_TEST) -L./
+
+video-enc-test: CREATE_DIR $(OBJECTPATHS_ENC_TEST)
+	$(CC) -o video_enc_test $(LDFLAGS) $(LDFLAGS_FFMPEG) -lsf-omx-il $(OBJECTPATHS_ENC_TEST) -L./
+
 clean:
 
 CREATE_DIR:

+ 389 - 0
soft_3rdpart/omx-il/tests/dec_test.c

@@ -0,0 +1,389 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
+ */
+#include <stdio.h>
+#include <signal.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include "libavformat/avformat.h"
+#include <OMX_Core.h>
+#include <OMX_Component.h>
+#include <OMX_Video.h>
+#include <OMX_IndexExt.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+
+#define OMX_INIT_STRUCTURE(a)         \
+    memset(&(a), 0, sizeof(a));       \
+    (a).nSize = sizeof(a);            \
+    (a).nVersion.nVersion = 1;        \
+    (a).nVersion.s.nVersionMajor = 1; \
+    (a).nVersion.s.nVersionMinor = 1; \
+    (a).nVersion.s.nRevision = 1;     \
+    (a).nVersion.s.nStep = 1
+
+typedef struct Message
+{
+    long msg_type;
+    OMX_S32 msg_flag;
+    OMX_BUFFERHEADERTYPE *pBuffer;
+} Message;
+
+typedef struct DecodeTestContext
+{
+    OMX_HANDLETYPE hComponentDecoder;
+    char sOutputFilePath[64];
+    char sInputFilePath[64];
+    OMX_BUFFERHEADERTYPE *pInputBufferArray[64];
+    OMX_BUFFERHEADERTYPE *pOutputBufferArray[64];
+    AVFormatContext *avContext;
+    int msgid;
+} DecodeTestContext;
+DecodeTestContext *decodeTestContext;
+static OMX_S32 FillInputBuffer(DecodeTestContext *decodeTestContext, OMX_BUFFERHEADERTYPE *pInputBuffer);
+
+static OMX_ERRORTYPE event_handler(
+    OMX_HANDLETYPE hComponent,
+    OMX_PTR pAppData,
+    OMX_EVENTTYPE eEvent,
+    OMX_U32 nData1,
+    OMX_U32 nData2,
+    OMX_PTR pEventData)
+{
+    DecodeTestContext *pDecodeTestContext = (DecodeTestContext *)pAppData;
+
+    switch (eEvent)
+    {
+    case OMX_EventPortSettingsChanged:
+    {
+        OMX_PARAM_PORTDEFINITIONTYPE pOutputPortDefinition;
+        OMX_INIT_STRUCTURE(pOutputPortDefinition);
+        pOutputPortDefinition.nPortIndex = 1;
+        OMX_GetParameter(pDecodeTestContext->hComponentDecoder, OMX_IndexParamPortDefinition, &pOutputPortDefinition);
+        OMX_U32 nOutputBufferSize = pOutputPortDefinition.nBufferSize;
+        OMX_U32 nOutputBufferCount = pOutputPortDefinition.nBufferCountMin;
+        for (int i = 0; i < nOutputBufferCount; i++)
+        {
+            OMX_BUFFERHEADERTYPE *pBuffer = NULL;
+            OMX_AllocateBuffer(hComponent, &pBuffer, 1, NULL, nOutputBufferSize);
+            pDecodeTestContext->pOutputBufferArray[i] = pBuffer;
+            OMX_FillThisBuffer(hComponent, pBuffer);
+        }
+    }
+    break;
+    case OMX_EventBufferFlag:
+    {
+        Message data;
+        data.msg_type = 1;
+        data.msg_flag = -1;
+        if (msgsnd(pDecodeTestContext->msgid, (void *)&data, sizeof(data) - sizeof(data.msg_type), 0) == -1)
+        {
+            fprintf(stderr, "msgsnd failed\n");
+        }
+    }
+    break;
+    default:
+        break;
+    }
+    return OMX_ErrorNone;
+}
+
+static void help()
+{
+    printf("./video_dec_test -i <input file> -o <output file> \r\n");
+}
+
+static OMX_ERRORTYPE fill_output_buffer_done_handler(
+    OMX_HANDLETYPE hComponent,
+    OMX_PTR pAppData,
+    OMX_BUFFERHEADERTYPE *pBuffer)
+{
+    DecodeTestContext *pDecodeTestContext = (DecodeTestContext *)pAppData;
+
+    Message data;
+    data.msg_type = 1;
+    if (pBuffer->nFlags & OMX_BUFFERFLAG_EOS == OMX_BUFFERFLAG_EOS)
+    {
+        data.msg_flag = -1;
+    }
+    else
+    {
+        data.msg_flag = 1;
+        data.pBuffer = pBuffer;
+    }
+    if (msgsnd(pDecodeTestContext->msgid, (void *)&data, sizeof(data) - sizeof(data.msg_type), 0) == -1)
+    {
+        fprintf(stderr, "msgsnd failed\n");
+    }
+
+    return OMX_ErrorNone;
+}
+
+static OMX_ERRORTYPE empty_buffer_done_handler(
+    OMX_HANDLETYPE hComponent,
+    OMX_PTR pAppData,
+    OMX_BUFFERHEADERTYPE *pBuffer)
+{
+    DecodeTestContext *pDecodeTestContext = (DecodeTestContext *)pAppData;
+    Message data;
+    data.msg_type = 1;
+    data.msg_flag = 0;
+    data.pBuffer = pBuffer;
+    if (msgsnd(pDecodeTestContext->msgid, (void *)&data, sizeof(data) - sizeof(data.msg_type), 0) == -1)
+    {
+        fprintf(stderr, "msgsnd failed\n");
+    }
+    return OMX_ErrorNone;
+}
+
+static void signal_handle(int sig)
+{
+    printf("[%s,%d]: receive sig=%d \n", __FUNCTION__, __LINE__, sig);
+    Message data;
+    data.msg_type = 1;
+    data.msg_flag = -1;
+    if (msgsnd(decodeTestContext->msgid, (void *)&data, sizeof(data) - sizeof(data.msg_type), 0) == -1)
+    {
+        fprintf(stderr, "msgsnd failed\n");
+    }
+}
+
+static OMX_S32 FillInputBuffer(DecodeTestContext *decodeTestContext, OMX_BUFFERHEADERTYPE *pInputBuffer)
+{
+    AVFormatContext *avFormatContext = decodeTestContext->avContext;
+    AVPacket avpacket;
+    OMX_S32 error;
+    av_init_packet(&avpacket);
+    error = av_read_frame(avFormatContext, &avpacket);
+    if (error < 0)
+    {
+        if (error == AVERROR_EOF || avFormatContext->pb->eof_reached == OMX_TRUE)
+        {
+            pInputBuffer->nFlags = 0x1;
+            pInputBuffer->nFilledLen = 0;
+            return 0;
+        }
+        else
+        {
+            printf("%s:%d failed to av_read_frame error(0x%08x)\n", __FUNCTION__, __LINE__, error);
+            return 0;
+        }
+    }
+    pInputBuffer->nFlags = 0x10;
+    pInputBuffer->nFilledLen = avpacket.size;
+    memcpy(pInputBuffer->pBuffer, avpacket.data, avpacket.size);
+    return avpacket.size;
+}
+
+int main(int argc, char *argv)
+{
+    printf("=============================\r\n");
+    OMX_S32 error;
+    decodeTestContext = malloc(sizeof(DecodeTestContext));
+    memset(decodeTestContext, 0, sizeof(DecodeTestContext));
+
+    OMX_S32 msgid = -1;
+    msgid = msgget(IPC_PRIVATE, 0666 | IPC_CREAT);
+    if (msgid < 0)
+    {
+        perror("get ipc_id error");
+        return;
+    }
+    decodeTestContext->msgid = msgid;
+    struct option longOpt[] = {
+        {"output", required_argument, NULL, 'o'},
+        {"input", required_argument, NULL, 'f'},
+        {NULL, no_argument, NULL, 0},
+    };
+    OMX_S8 *shortOpt = "i:o:";
+    OMX_U32 c;
+    OMX_S32 l;
+
+    if (argc == 0)
+    {
+        help();
+        return;
+    }
+
+    while ((c = getopt_long(argc, argv, shortOpt, longOpt, &l)) != -1)
+    {
+        switch (c)
+        {
+        case 'i':
+            printf("input: %s\r\n", optarg);
+            if (access(optarg, R_OK) != -1)
+            {
+                memcpy(decodeTestContext->sInputFilePath, optarg, strlen(optarg));
+            }
+            else
+            {
+                printf("input file not exist!\r\n");
+                return;
+            }
+            break;
+        case 'o':
+            printf("output: %s\r\n", optarg);
+            memcpy(decodeTestContext->sOutputFilePath, optarg, strlen(optarg));
+            break;
+        case 'h':
+        default:
+            help();
+            return;
+        }
+    }
+
+    if (decodeTestContext->sInputFilePath == NULL || decodeTestContext->sOutputFilePath == NULL)
+    {
+        help();
+        return;
+    }
+    /*ffmpeg init*/
+    printf("init ffmpeg\r\n");
+    AVFormatContext *avContext = NULL;
+    AVCodecParameters *codecParameters = NULL;
+    AVInputFormat *fmt = NULL;
+    OMX_S32 videoIndex;
+    if ((avContext = avformat_alloc_context()) == NULL)
+    {
+        printf("avformat_alloc_context fail\r\n");
+        return;
+    }
+    avContext->flags |= AV_CODEC_FLAG_TRUNCATED;
+
+    printf("avformat_open_input\r\n");
+    if ((error = avformat_open_input(&avContext, decodeTestContext->sInputFilePath, fmt, NULL)))
+    {
+        printf("%s:%d failed to av_open_input_file error(%d), %s\n",
+               __FILE__, __LINE__, error, decodeTestContext->sInputFilePath);
+        return;
+    }
+
+    printf("avformat_find_stream_info\r\n");
+    if ((error = avformat_find_stream_info(avContext, NULL)) < 0)
+    {
+        printf("%s:%d failed to avformat_find_stream_info. error(%d)\n",
+               __FUNCTION__, __LINE__, error);
+        return;
+    }
+
+    printf("av_find_best_stream\r\n");
+    videoIndex = av_find_best_stream(avContext, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
+    if (videoIndex < 0)
+    {
+        printf("%s:%d failed to av_find_best_stream.\n", __FUNCTION__, __LINE__);
+        return;
+    }
+    printf("video index = %d\r\n", videoIndex);
+    decodeTestContext->avContext = avContext;
+    /*get video info*/
+    codecParameters = avContext->streams[videoIndex]->codecpar;
+    printf("codec_id = %d, width = %d, height = %d\r\n", (int)codecParameters->codec_id,
+           codecParameters->width, codecParameters->height);
+
+    /*omx init*/
+    OMX_HANDLETYPE hComponentDecoder;
+    OMX_CALLBACKTYPE callbacks;
+    int ret = OMX_ErrorNone;
+    signal(SIGINT, signal_handle);
+    printf("init omx\r\n");
+    ret = OMX_Init();
+    if (ret != OMX_ErrorNone)
+    {
+        printf("[%s,%d]: run OMX_Init failed. ret is %d \n", __FUNCTION__, __LINE__, ret);
+        return 1;
+    }
+
+    callbacks.EventHandler = event_handler;
+    callbacks.FillBufferDone = fill_output_buffer_done_handler;
+    callbacks.EmptyBufferDone = empty_buffer_done_handler;
+    printf("get handle\r\n");
+    if (codecParameters->codec_id == AV_CODEC_ID_H264)
+    {
+        OMX_GetHandle(&hComponentDecoder, "sf.dec.decoder.h264", decodeTestContext, &callbacks);
+    }
+    else if (codecParameters->codec_id == AV_CODEC_ID_HEVC)
+    {
+        OMX_GetHandle(&hComponentDecoder, "sf.dec.decoder.h265", decodeTestContext, &callbacks);
+    }
+    if (hComponentDecoder == NULL)
+    {
+        printf("could not get handle\r\n");
+        return 0;
+    }
+    decodeTestContext->hComponentDecoder = hComponentDecoder;
+    OMX_SendCommand(hComponentDecoder, OMX_CommandStateSet, OMX_StateIdle, NULL);
+
+    OMX_PARAM_PORTDEFINITIONTYPE pInputPortDefinition;
+    OMX_INIT_STRUCTURE(pInputPortDefinition);
+    pInputPortDefinition.nPortIndex = 0;
+    OMX_GetParameter(hComponentDecoder, OMX_IndexParamPortDefinition, &pInputPortDefinition);
+    pInputPortDefinition.format.video.nFrameWidth = codecParameters->width;
+    pInputPortDefinition.format.video.nFrameHeight = codecParameters->height;
+    OMX_SetParameter(hComponentDecoder, OMX_IndexParamPortDefinition, &pInputPortDefinition);
+    /*Alloc input buffer*/
+    OMX_U32 nInputWidth = codecParameters->width;
+    OMX_U32 nInputHeight = codecParameters->height;
+    OMX_U32 nInputBufferSize = nInputWidth * nInputHeight * 2;
+    OMX_U32 nInputBufferCount = pInputPortDefinition.nBufferCountActual;
+    for (int i = 0; i < nInputBufferCount; i++)
+    {
+        OMX_BUFFERHEADERTYPE *pBuffer = NULL;
+        OMX_AllocateBuffer(hComponentDecoder, &pBuffer, 0, NULL, nInputBufferSize);
+        decodeTestContext->pInputBufferArray[i] = pBuffer;
+        /*Fill Input Buffer*/
+        FillInputBuffer(decodeTestContext, pBuffer);
+        OMX_EmptyThisBuffer(hComponentDecoder, pBuffer);
+    }
+
+    OMX_SendCommand(hComponentDecoder, OMX_CommandStateSet, OMX_StateExecuting, NULL);
+
+    /*wait until decode finished*/
+    Message data;
+    while (OMX_TRUE)
+    {
+        if (msgrcv(msgid, (void *)&data, BUFSIZ, 0, 0) == -1)
+        {
+            fprintf(stderr, "msgrcv failed with errno: %d\n", errno);
+            goto end;
+        }
+        switch (data.msg_flag)
+        {
+        case 0:
+        {
+            OMX_BUFFERHEADERTYPE *pBuffer = data.pBuffer;
+            FillInputBuffer(decodeTestContext, pBuffer);
+            OMX_EmptyThisBuffer(decodeTestContext->hComponentDecoder, pBuffer);
+        }
+        break;
+        case 1:
+        {
+            OMX_BUFFERHEADERTYPE *pBuffer = data.pBuffer;
+            OMX_STRING sFilePath = decodeTestContext->sOutputFilePath;
+            FILE *fb = fopen(sFilePath, "ab+");
+            fwrite(pBuffer->pBuffer, 1, pBuffer->nFilledLen, fb);
+            fclose(fb);
+            if (pBuffer->nFlags & OMX_BUFFERFLAG_EOS == OMX_BUFFERFLAG_EOS)
+            {
+                goto end;
+            }
+            else
+            {
+                OMX_FillThisBuffer(decodeTestContext->hComponentDecoder, pBuffer);
+            }
+        }
+        break;
+        case 2:
+            break;
+        default:
+            goto end;
+        }
+    }
+
+end:
+    /*free resource*/
+    OMX_FreeHandle(hComponentDecoder);
+    OMX_Deinit();
+}

+ 387 - 0
soft_3rdpart/omx-il/tests/enc_test.c

@@ -0,0 +1,387 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
+ */
+#include <stdio.h>
+#include <signal.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <OMX_Core.h>
+#include <OMX_Component.h>
+#include <OMX_Video.h>
+#include <OMX_IndexExt.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <errno.h>
+
+#define OMX_INIT_STRUCTURE(a)         \
+    memset(&(a), 0, sizeof(a));       \
+    (a).nSize = sizeof(a);            \
+    (a).nVersion.nVersion = 1;        \
+    (a).nVersion.s.nVersionMajor = 1; \
+    (a).nVersion.s.nVersionMinor = 1; \
+    (a).nVersion.s.nRevision = 1;     \
+    (a).nVersion.s.nStep = 1
+
+typedef struct Message
+{
+    long msg_type;
+    OMX_S32 msg_flag;
+    OMX_BUFFERHEADERTYPE *pBuffer;
+} Message;
+
+typedef struct EncodeTestContext
+{
+    OMX_HANDLETYPE hComponentEncoder;
+    char sOutputFilePath[64];
+    char sInputFilePath[64];
+    FILE *pInputFile;
+    char sInputFormat[64];
+    char sOutputFormat[64];
+    OMX_U32 nFrameBufferSize;
+    OMX_BUFFERHEADERTYPE *pInputBufferArray[64];
+    OMX_BUFFERHEADERTYPE *pOutputBufferArray[64];
+    int msgid;
+} EncodeTestContext;
+EncodeTestContext *encodeTestContext;
+static OMX_S32 FillInputBuffer(EncodeTestContext *encodeTestContext, OMX_BUFFERHEADERTYPE *pInputBuffer);
+
+static OMX_ERRORTYPE event_handler(
+    OMX_HANDLETYPE hComponent,
+    OMX_PTR pAppData,
+    OMX_EVENTTYPE eEvent,
+    OMX_U32 nData1,
+    OMX_U32 nData2,
+    OMX_PTR pEventData)
+{
+    EncodeTestContext *pEncodeTestContext = (EncodeTestContext *)pAppData;
+
+    switch (eEvent)
+    {
+    case OMX_EventPortSettingsChanged:
+    {
+        OMX_PARAM_PORTDEFINITIONTYPE pOutputPortDefinition;
+        OMX_INIT_STRUCTURE(pOutputPortDefinition);
+        pOutputPortDefinition.nPortIndex = 1;
+        OMX_GetParameter(pEncodeTestContext->hComponentEncoder, OMX_IndexParamPortDefinition, &pOutputPortDefinition);
+        OMX_U32 nOutputBufferSize = pOutputPortDefinition.nBufferSize;
+        OMX_U32 nOutputBufferCount = pOutputPortDefinition.nBufferCountMin;
+        for (int i = 0; i < nOutputBufferCount; i++)
+        {
+            OMX_BUFFERHEADERTYPE *pBuffer = NULL;
+            OMX_AllocateBuffer(hComponent, &pBuffer, 1, NULL, nOutputBufferSize);
+            pEncodeTestContext->pOutputBufferArray[i] = pBuffer;
+            OMX_FillThisBuffer(hComponent, pBuffer);
+        }
+    }
+    break;
+    case OMX_EventBufferFlag:
+    {
+        Message data;
+        data.msg_type = 1;
+        data.msg_flag = -1;
+        if (msgsnd(pEncodeTestContext->msgid, (void *)&data, sizeof(data) - sizeof(data.msg_type), 0) == -1)
+        {
+            fprintf(stderr, "msgsnd failed\n");
+        }
+    }
+    break;
+    default:
+        break;
+    }
+    return OMX_ErrorNone;
+}
+
+static void help()
+{
+    printf("./video_enc_test -i <input file> -o <output file> -w <width> -h <height>"
+           "-c <yuv/nv12> -s <h264/h265>\r\n");
+}
+
+static OMX_ERRORTYPE fill_output_buffer_done_handler(
+    OMX_HANDLETYPE hComponent,
+    OMX_PTR pAppData,
+    OMX_BUFFERHEADERTYPE *pBuffer)
+{
+    EncodeTestContext *pEncodeTestContext = (EncodeTestContext *)pAppData;
+
+    Message data;
+    data.msg_type = 1;
+    if (pBuffer->nFlags & OMX_BUFFERFLAG_EOS == OMX_BUFFERFLAG_EOS)
+    {
+        data.msg_flag = -1;
+    }
+    else
+    {
+        data.msg_flag = 1;
+        data.pBuffer = pBuffer;
+    }
+    if (msgsnd(pEncodeTestContext->msgid, (void *)&data, sizeof(data) - sizeof(data.msg_type), 0) == -1)
+    {
+        fprintf(stderr, "msgsnd failed\n");
+    }
+
+    return OMX_ErrorNone;
+}
+
+static OMX_ERRORTYPE empty_buffer_done_handler(
+    OMX_HANDLETYPE hComponent,
+    OMX_PTR pAppData,
+    OMX_BUFFERHEADERTYPE *pBuffer)
+{
+    EncodeTestContext *pEncodeTestContext = (EncodeTestContext *)pAppData;
+    Message data;
+    data.msg_type = 1;
+    data.msg_flag = 0;
+    data.pBuffer = pBuffer;
+    if (msgsnd(pEncodeTestContext->msgid, (void *)&data, sizeof(data) - sizeof(data.msg_type), 0) == -1)
+    {
+        fprintf(stderr, "msgsnd failed\n");
+    }
+    return OMX_ErrorNone;
+}
+
+static void signal_handle(int sig)
+{
+    printf("[%s,%d]: receive sig=%d \n", __FUNCTION__, __LINE__, sig);
+
+    OMX_FreeHandle(encodeTestContext->hComponentEncoder);
+    OMX_Deinit();
+    exit(0);
+    // Message data;
+    // data.msg_type = 1;
+    // data.msg_flag = -1;
+    // if (msgsnd(encodeTestContext->msgid, (void *)&data, sizeof(data) - sizeof(data.msg_type), 0) == -1)
+    // {
+    //     fprintf(stderr, "msgsnd failed\n");
+    // }
+}
+
+static OMX_S32 FillInputBuffer(EncodeTestContext *encodeTestContext, OMX_BUFFERHEADERTYPE *pInputBuffer)
+{
+    FILE *fp = encodeTestContext->pInputFile;
+    OMX_U32 size = encodeTestContext->nFrameBufferSize;
+    OMX_U32 count;
+
+    count = fread(pInputBuffer->pBuffer, 1, size, fp);
+    if (count < size)
+    {
+        pInputBuffer->nFlags = 0x1;
+        pInputBuffer->nFilledLen = 0;
+        count = 0;
+    }
+    else
+    {
+        pInputBuffer->nFlags = 0x10;
+        pInputBuffer->nFilledLen = size;
+    }
+
+    return count;
+}
+
+int main(int argc, char *argv)
+{
+    printf("=============================\r\n");
+    OMX_S32 error;
+    encodeTestContext = malloc(sizeof(EncodeTestContext));
+    memset(encodeTestContext, 0, sizeof(EncodeTestContext));
+
+    OMX_S32 msgid = -1;
+    msgid = msgget(IPC_PRIVATE, 0666 | IPC_CREAT);
+    if (msgid < 0)
+    {
+        perror("get ipc_id error");
+        return;
+    }
+    encodeTestContext->msgid = msgid;
+    struct option longOpt[] = {
+        {"output", required_argument, NULL, 'o'},
+        {"input", required_argument, NULL, 'f'},
+        {"color format", required_argument, NULL, 'c'},
+        {"stream format", required_argument, NULL, 's'},
+        {"width", required_argument, NULL, 'w'},
+        {"height", required_argument, NULL, 'h'},
+        {NULL, no_argument, NULL, 0},
+    };
+    OMX_S8 *shortOpt = "i:o:f:s:w:h:";
+    OMX_U32 c;
+    OMX_S32 l;
+
+    if (argc == 0)
+    {
+        help();
+        return;
+    }
+    OMX_U32 width = 0;
+    OMX_U32 height = 0;
+    while ((c = getopt_long(argc, argv, shortOpt, longOpt, &l)) != -1)
+    {
+        switch (c)
+        {
+        case 'i':
+            printf("input: %s\r\n", optarg);
+            if (access(optarg, R_OK) != -1)
+            {
+                memcpy(encodeTestContext->sInputFilePath, optarg, strlen(optarg));
+                encodeTestContext->pInputFile = fopen(optarg, "r");
+            }
+            else
+            {
+                printf("input file not exist!\r\n");
+                return;
+            }
+            break;
+        case 'o':
+            printf("output: %s\r\n", optarg);
+            memcpy(encodeTestContext->sOutputFilePath, optarg, strlen(optarg));
+            break;
+        case 'c':
+            printf("color format: %s\r\n", optarg);
+            memcpy(encodeTestContext->sInputFormat, optarg, strlen(optarg));
+            break;
+        case 's':
+            printf("stream format: %s\r\n", optarg);
+            memcpy(encodeTestContext->sOutputFormat, optarg, strlen(optarg));
+            break;
+        case 'w':
+            printf("width: %s\r\n", optarg);
+            width = atoi(optarg);
+            break;
+        case 'h':
+            printf("height: %s\r\n", optarg);
+            height = atoi(optarg);
+            break;
+        default:
+            help();
+            return;
+        }
+    }
+
+    encodeTestContext->nFrameBufferSize = width * height * 3 / 2;
+    if (encodeTestContext->sInputFilePath == NULL ||
+        encodeTestContext->sOutputFilePath == NULL ||
+        encodeTestContext->nFrameBufferSize == 0 ||
+        encodeTestContext->pInputFile == NULL)
+    {
+        help();
+        return;
+    }
+
+    /*omx init*/
+    OMX_HANDLETYPE hComponentEncoder;
+    OMX_CALLBACKTYPE callbacks;
+    int ret = OMX_ErrorNone;
+    signal(SIGINT, signal_handle);
+    printf("init omx\r\n");
+    ret = OMX_Init();
+    if (ret != OMX_ErrorNone)
+    {
+        printf("[%s,%d]: run OMX_Init failed. ret is %d \n", __FUNCTION__, __LINE__, ret);
+        return 1;
+    }
+
+    callbacks.EventHandler = event_handler;
+    callbacks.FillBufferDone = fill_output_buffer_done_handler;
+    callbacks.EmptyBufferDone = empty_buffer_done_handler;
+    printf("get handle %s\r\n", encodeTestContext->sOutputFormat);
+    if (strstr(encodeTestContext->sOutputFormat, "h264") != NULL)
+    {
+        OMX_GetHandle(&hComponentEncoder, "sf.enc.encoder.h264", encodeTestContext, &callbacks);
+    }
+    else if (strstr(encodeTestContext->sOutputFormat, "h265") != NULL)
+    {
+        OMX_GetHandle(&hComponentEncoder, "sf.enc.encoder.h265", encodeTestContext, &callbacks);
+    }
+    if (hComponentEncoder == NULL)
+    {
+        printf("could not get handle\r\n");
+        return 0;
+    }
+    encodeTestContext->hComponentEncoder = hComponentEncoder;
+
+    OMX_PARAM_PORTDEFINITIONTYPE pInputPortDefinition;
+    OMX_INIT_STRUCTURE(pInputPortDefinition);
+    pInputPortDefinition.nPortIndex = 0;
+    OMX_GetParameter(hComponentEncoder, OMX_IndexParamPortDefinition, &pInputPortDefinition);
+    pInputPortDefinition.format.video.nFrameWidth = width;
+    pInputPortDefinition.format.video.nFrameHeight = height;
+    OMX_SetParameter(hComponentEncoder, OMX_IndexParamPortDefinition, &pInputPortDefinition);
+    OMX_GetParameter(hComponentEncoder, OMX_IndexParamPortDefinition, &pInputPortDefinition);
+
+    OMX_PARAM_PORTDEFINITIONTYPE pOutputPortDefinition;
+    OMX_INIT_STRUCTURE(pOutputPortDefinition);
+    pOutputPortDefinition.nPortIndex = 1;
+    OMX_GetParameter(hComponentEncoder, OMX_IndexParamPortDefinition, &pOutputPortDefinition);
+    pOutputPortDefinition.format.video.nFrameWidth = width;
+    pOutputPortDefinition.format.video.nFrameHeight = height;
+    //TODO: input format
+    OMX_SetParameter(hComponentEncoder, OMX_IndexParamPortDefinition, &pOutputPortDefinition);
+
+    /*Alloc input buffer*/
+    OMX_U32 nInputBufferSize = pInputPortDefinition.nBufferSize;
+    OMX_U32 nInputBufferCount = pInputPortDefinition.nBufferCountActual;
+
+    OMX_SendCommand(hComponentEncoder, OMX_CommandStateSet, OMX_StateIdle, NULL);
+
+    for (int i = 0; i < nInputBufferCount; i++)
+    {
+        OMX_BUFFERHEADERTYPE *pBuffer = NULL;
+        OMX_AllocateBuffer(hComponentEncoder, &pBuffer, 0, NULL, nInputBufferSize);
+        encodeTestContext->pInputBufferArray[i] = pBuffer;
+        /*Fill Input Buffer*/
+        FillInputBuffer(encodeTestContext, pBuffer);
+        OMX_EmptyThisBuffer(hComponentEncoder, pBuffer);
+    }
+
+    OMX_SendCommand(hComponentEncoder, OMX_CommandStateSet, OMX_StateExecuting, NULL);
+
+    /*wait until decode finished*/
+    Message data;
+    while (OMX_TRUE)
+    {
+        if (msgrcv(msgid, (void *)&data, BUFSIZ, 0, 0) == -1)
+        {
+            fprintf(stderr, "msgrcv failed with errno: %d\n", errno);
+            goto end;
+        }
+        switch (data.msg_flag)
+        {
+        case 0:
+        {
+            OMX_BUFFERHEADERTYPE *pBuffer = data.pBuffer;
+            FillInputBuffer(encodeTestContext, pBuffer);
+            OMX_EmptyThisBuffer(encodeTestContext->hComponentEncoder, pBuffer);
+        }
+        break;
+        case 1:
+        {
+            OMX_BUFFERHEADERTYPE *pBuffer = data.pBuffer;
+            OMX_STRING sFilePath = encodeTestContext->sOutputFilePath;
+            FILE *fb = fopen(sFilePath, "ab+");
+            fwrite(pBuffer->pBuffer, 1, pBuffer->nFilledLen, fb);
+            fclose(fb);
+            if (pBuffer->nFlags & OMX_BUFFERFLAG_EOS == OMX_BUFFERFLAG_EOS)
+            {
+                goto end;
+            }
+            else
+            {
+                OMX_FillThisBuffer(encodeTestContext->hComponentEncoder, pBuffer);
+            }
+        }
+        break;
+        case 2:
+            break;
+        default:
+            goto end;
+        }
+    }
+
+end:
+    /*free resource*/
+    fclose(encodeTestContext->pInputFile);
+    OMX_FreeHandle(hComponentEncoder);
+    OMX_Deinit();
+}