This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

The omx_h264enc encoder can not produce sps/pps when encode yuv file of nv12

Hi,all!

       I use the ics 4.0 and openmax  on the omap4. the encoder is omx_h264enc .  the command is "gst-launch -v filesrc location=/mnt/ext_sdcard/nv12.yuv ! videoparse width=1280 height=720 ! omx_h264enc ! filesink location=/mnt/sdcard/test1.264 --gst-debug=omx:5". I find  the test1.264 file which produce by omx_h264enc  donot contain  the sps/pps!   when  i  read the videoeditor  source code ,i find  the videoeditor add sps/pps  by itself  but not by openmax . Can the omx_h264enc produce sps/pps when it encode yuv file?

Thank you!

  • Aaron,

    If it is not giving sps and pps the encoder may not be configured properly. Have you tested the same pipeline on another release where it is working fine?

    Since the encoder only takes strided NV12 data as input you may also want to try out the following transformation before feeding into the encoder. The stride is 4096.

    stridetransform ! "video/x-raw-yuv-strided, format=(fourcc)NV12, width=1280, height=720, rowstride=4096, framerate=30/1"

    Regards,

    Chintan

  • Another 2 possibilities or checks are:

    1. Can you do a buffer dump at OMX_FillBufferDone to check if SPS+PPS are being send from video encoder, you can dump only first 32 bytes that must be enough to see SPS+PPS and initial headers for first IFrame. This to discard failed areas or isolate the issue to one area.

    2. If you are using a full pipe line to encode-decode process and then to a check, if encoder is generating the SPS+PPS they are stored in GST decoder in a variable like codec data, for what I know, I don't have much data about your actual GST, it is required to read this variable when decoding process is started and send it before sending the first Iframe.

  • Hi,Manuel !

        I  have save the buffer at PROXY_FillBufferDone  (omx_proxy_common.c) , RPC_SKEL_FillBufferDone (omx_rpc_skel.c)  and    RPC_CallbackThread (omx_rpc.c) ,  the three 264 files  are all right ,  the sps+pps at the beginning of the 264 file. but the file saved by filesink  dose  not  consist  the  sps+pps  at   the beginnig  of  the  264  file.  I  can not  go deep into  the caller of RPC_CallbackThread,  i  can  not  find  which  function will consume the buffer or transfer  it  to  the  other  function .

    the code RPC_CallbackThread  is  below:

    void *RPC_CallbackThread(void *data)
    {
        OMX_PTR pBuffer = NULL;
        RPC_OMX_CONTEXT *pRPCCtx = (RPC_OMX_CONTEXT *) data;
        fd_set readfds;
        OMX_S32 maxfd = 0, status = 0;
        OMX_U32 nFxnIdx = 0, nPacketSize = RPC_PACKET_SIZE, nPos = 0;
        RPC_OMX_ERRORTYPE eRPCError = RPC_OMX_ErrorNone;
        TIMM_OSAL_ERRORTYPE eError = TIMM_OSAL_ERR_NONE;
        OMX_COMPONENTTYPE *hComp = NULL;
        PROXY_COMPONENT_PRIVATE *pCompPrv = NULL;
            OMX_PTR pBuff = pBufferError;
        DOMX_DEBUG("Enter %s(%d)--%s\n",__FILE__,__LINE__,__FUNCTION__);
        maxfd =
            (pRPCCtx->fd_killcb >
            pRPCCtx->fd_omx ? pRPCCtx->fd_killcb : pRPCCtx->fd_omx) + 1;
        ftmp3 = open("/mnt/sdcard/RPC_CallbackThread.264",O_RDWR|O_CREAT|O_APPEND);
        while (1)
        {
            FD_ZERO(&readfds);
            FD_SET(pRPCCtx->fd_omx, &readfds);
            FD_SET(pRPCCtx->fd_killcb, &readfds);

            DOMX_DEBUG("Waiting for messages from remote core");
            status = select(maxfd, &readfds, NULL, NULL, NULL);
            RPC_assert(status > 0, RPC_OMX_ErrorUndefined,
                "select failed");

            if (FD_ISSET(pRPCCtx->fd_killcb, &readfds))
            {
                DOMX_DEBUG("Recd. kill message - exiting the thread");
                break;
            }

            if (FD_ISSET(pRPCCtx->fd_omx, &readfds))
            {
                DOMX_DEBUG("Recd. omx message");
                RPC_getPacket(nPacketSize, pBuffer);
                status = read(pRPCCtx->fd_omx, pBuffer, nPacketSize);
                if(status < 0)
                {
                    if(errno == ENXIO)
                    {
                for(nFxnIdx = 0; nFxnIdx < RPC_OMX_MAX_FUNCTION_LIST; nFxnIdx++)
                {
                ((struct omx_packet *) pBufferError)->result = OMX_ErrorHardware;
                TIMM_OSAL_WriteToPipe(pRPCCtx->pMsgPipe[nFxnIdx], &pBuff, RPC_MSG_SIZE_FOR_PIPE, TIMM_OSAL_SUSPEND);
                if(eError != TIMM_OSAL_ERR_NONE)
                    DOMX_ERROR("Write to pipe failed");
                }
                        /*Indicate fatal error and exit*/
                        RPC_assert(0, RPC_OMX_ErrorHardware,
                        "Remote processor fatal error");
                    }
                    else
                    {
                        RPC_assert(0, RPC_OMX_ErrorUndefined,
                        "read failed");
                    }
                }

                nPos = 0;
                nFxnIdx = ((struct omx_packet *) pBuffer)->fxn_idx;
                /*Indices from static table will have bit 31 set */
                if (nFxnIdx & 0x80000000)
                    nFxnIdx &= 0x0FFFFFFF;
                RPC_assert(nFxnIdx < RPC_OMX_MAX_FUNCTION_LIST,
                    RPC_OMX_ErrorUndefined,
                    "Bad function index recd");
                DOMX_DEBUG("%s(%d)--%s nFxnIdx=%d\n",__FILE__,__LINE__,__FUNCTION__,nFxnIdx);
                switch (nFxnIdx)
                {
                case RPC_OMX_FXN_IDX_EVENTHANDLER:
                    RPC_SKEL_EventHandler(((struct omx_packet *)
                        pBuffer)->data);
                    RPC_freePacket(pBuffer);
                    pBuffer = NULL;
                    break;
                case RPC_OMX_FXN_IDX_EMPTYBUFFERDONE:
                    RPC_SKEL_EmptyBufferDone(((struct omx_packet *)
                        pBuffer)->data);
                    RPC_freePacket(pBuffer);
                    pBuffer = NULL;
                    break;
                case RPC_OMX_FXN_IDX_FILLBUFFERDONE:
                    DOMX_DEBUG("%s(%d)--%s RPC_OMX_FXN_IDX_FILLBUFFERDONE\n",__FILE__,__LINE__,__FUNCTION__);
                    RPC_SKEL_FillBufferDone(((struct omx_packet *)
                        pBuffer)->data);
    /////////////////////////////////////////////////////////////////
                    {
                        OMX_COMPONENTTYPE *pHandle = NULL;
                        PROXY_COMPONENT_PRIVATE *pCompPrv = NULL;
                        OMX_U32 bufferHdr;
                        OMX_U8 *pMsgBody = ((struct omx_packet *)pBuffer)->data;
                        RPC_GETFIELDVALUE(pMsgBody, nPos, hComp, OMX_HANDLETYPE);
                        pHandle = (OMX_COMPONENTTYPE *) hComp;
                        pCompPrv = (PROXY_COMPONENT_PRIVATE *) pHandle->pComponentPrivate;
                        OMX_BUFFERHEADERTYPE *pBufHdr = NULL;
                        RPC_GETFIELDVALUE(pMsgBody, nPos, bufferHdr, OMX_U32);
                        int count;
                        for (count = 0; count < pCompPrv->nTotalBuffers; ++count)
                        {
                            if (pCompPrv->tBufList[count].pBufHeaderRemote ==
                                    bufferHdr)
                            {
                                pBufHdr = pCompPrv->tBufList[count].pBufHeader;
                                DOMX_DEBUG("%s(%d)--%s pBufHdr->nFilledLen = %d\n",__FILE__,__LINE__,__FUNCTION__,pBufHdr->nFilledLen);
                                write(ftmp3,pBufHdr->pBuffer,pBufHdr->nFilledLen);
                                break;
                            }
                        }
                    }
    ///////////////////////////////////////////////////////////
                    RPC_freePacket(pBuffer);
                    pBuffer = NULL;
                    break;
                default:
                    eError =
                        TIMM_OSAL_WriteToPipe(pRPCCtx->
                        pMsgPipe[nFxnIdx], &pBuffer,
                        RPC_MSG_SIZE_FOR_PIPE, TIMM_OSAL_SUSPEND);
                    RPC_assert(eError == TIMM_OSAL_ERR_NONE,
                        RPC_OMX_ErrorUndefined,
                        "Write to pipe failed");
                    break;
                }
            }
    EXIT:
            if (eRPCError != RPC_OMX_ErrorNone)
            {
                //AD TODO: Send error CB to client and then go back in loop to wait for killfd
                if (pBuffer != NULL)
                {
                    RPC_freePacket(pBuffer);
                    pBuffer = NULL;
                }
                /*Report all hardware errors as fatal and exit from listener thread*/
                if (eRPCError == RPC_OMX_ErrorHardware)
                {
                    /*Implicit detail: pAppData is proxy component handle updated during
                      RPC_GetHandle*/
                    hComp = (OMX_COMPONENTTYPE *) pRPCCtx->pAppData;
                    if(hComp != NULL)
                    {
                        pCompPrv = (PROXY_COMPONENT_PRIVATE *) hComp->pComponentPrivate;
                        /*Indicate fatal error. Users are expected to cleanup the OMX instance
                        to ensure all resources are cleaned up.*/
                        pCompPrv->proxyEventHandler(hComp, pCompPrv->pILAppData, OMX_EventError,
                                                    OMX_ErrorHardware, 0, NULL);
                    }
                    break;
                }
            }
        }
        close(ftmp3);
        DOMX_DEBUG("Exit %s(%d)--%s\n",__FILE__,__LINE__,__FUNCTION__);
            return (void*)0;
    }

    Does anybody have some idea? 

    thanks in advance.

    Br,

    Aaron  Pope

  • Aaron;

    If you are getting SPS+PPS in PROXY_FillBufferDone then going to check to RPC_CallbackThread it means moving to Ducati side, function is OMX_FillBufferDone that is used to return filled buffers to Client IL, your next step is to check at Client IL side where Callbacks are defined in GST-OpenMax.

    from PROXY_FillBufferDone buffer goes to the component using the callbacks, that where set when OMX_GetHandle() was called in OMX_ComponentInit().

    ./4AI.1.4/mydroid/hardware/ti/domx/domx/omx_proxy_common/src/omx_proxy_common.c

    OMX_ERRORTYPE PROXY_FillBufferDone(OMX_HANDLETYPE hComponent,
        OMX_U32 remoteBufHdr, OMX_U32 nfilledLen, OMX_U32 nOffset, OMX_U32 nFlags,
        OMX_TICKS nTimeStamp, OMX_HANDLETYPE hMarkTargetComponent,
        OMX_PTR pMarkData)


        if (eError == OMX_ErrorNone)
        {
            pCompPrv->tCBFunc.FillBufferDone(hComponent,
                pCompPrv->pILAppData, pBufHdr);
        } else if (pCompPrv)
        {
            pCompPrv->tCBFunc.EventHandler(hComponent,
                pCompPrv->pILAppData, OMX_EventError, eError, 0, NULL);
        }

    for reference,

    Value that is set from Client IL using OMX_GetHandle() that calls OMX_SetCallBacks() after calling OMX_ComponentInit() for each component, it goes to

    ./4AI.1.4/mydroid/hardware/ti/domx/domx/omx_proxy_common/src/omx_proxy_common.c

    static OMX_ERRORTYPE PROXY_SetCallbacks(OMX_HANDLETYPE hComponent,
        OMX_CALLBACKTYPE * pCallBacks, OMX_PTR pAppData)

    by doing a quick function names search in GST-OpenMax

    that means from GST-OpenMax

    ./gst/gst-openmax/omx/gstomx_core.c

    when callbacks are set,

    static OMX_CALLBACKTYPE callbacks = { EventHandler, EmptyBufferDone, FillBufferDone };

    void
    g_omx_core_init (GOmxCore *core)
    {

    static OMX_CALLBACKTYPE callbacks = { EventHandler, EmptyBufferDone, FillBufferDone };

        core->omx_error = core->imp->sym_table.get_handle (&core->omx_handle,
                                                           (char *) component_name,
                                                           core,
                                                           &callbacks);

    next buffer dump must be done from here

    static OMX_ERRORTYPE
    FillBufferDone (OMX_HANDLETYPE omx_handle,
                    OMX_PTR app_data,
                    OMX_BUFFERHEADERTYPE *omx_buffer)

  • Hi,Manuel

          Thank you for suggest  !  I have  dump  the buffer in  the  static OMX_ERRORTYPE   FillBufferDone (OMX_HANDLETYPE omx_handle, OMX_PTR app_data, OMX_BUFFERHEADERTYPE *omx_buffer)   function  and  the 264  file  is  right  .  so  i  think  this  means  the encoder  is successful . The next  step  i  should  do  is dump  the buffer  when  the encoder  send   to  filesink.  The omx_h264enc  is  inherit  from   basefilter   ,but  the  basefilter  have  three  function  for  buffer  transfer  , push_buffer    pad_chain   and  out_loop  .  which  one  will  play  a role in this  program?

    Thank you very much!

    Br.

    yangliming

  • Aaron;

    I remember that for GST-GOO/libgoo the video decoder used to store the SPP+PPS (codec data) into a variable and in integration with OpenMax IL this variable was not being sent to OMX video decoder, GST developers at that time took care of the issue and fixed it by sending this variable in the first buffer before first Iframe. I can imagine that GST-OpenMax works similar for encoder where first buffers that comes from OMX is parsed and codec data stored in a variable.

    In your case this variable for encoder must be storing the codec data and passing it to decoder but it could not be send to OMX again like described that happened for GST-GOO/libgoo, you could need to check at what point this information is getting lost in your environment.

    I know GST-OpenMax and GST-GOO/libgoo are different, unsuccessfully I've been reading some portions of code looking to find this type variable in GST-OpenMax you need to find what is happening with the codec data or if someone else in this forum could answer it.

    I wait this information about codec data could provide some light to your issue.