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.

H.264 Encoder test on DM8168

Hi,

I want to test the max channels that H.264 encoder could support on DM8168. I use fileread->encode->filewrite data flow. I met some strange situation. When the channels are beyond 13, the encoder channels could be created successfully. But the last a few channels(channel number larger than 13) do not process any data. The following is the console output messages.

 
 [m3video]      113889: HDVICP-ID:0
 [m3video] All percentage figures are based off totalElapsedTime
 [m3video]               totalAcquire2wait :1 %
 [m3video]               totalWait2Isr :21 %
 [m3video]               totalIsr2Done :0 %
 [m3video]               totalWait2Done :21 %
 [m3video]               totalDone2Release :0 %
 [m3video]               totalAcquire2Release :23 %
 [m3video]               totalAcq2acqDelay :76 %
 [m3video]               totalElapsedTime in msec :   10166
 [m3video]               numAccessCnt:     950
 [m3video]              IVA-FPS :      95
 [m3video]              Average time spent per frame in microsec:    2247
 [m3video]      113889: HDVICP-ID:1
 [m3video] All percentage figures are based off totalElapsedTime
 [m3video]               totalAcquire2wait :1 %
 [m3video]               totalWait2Isr :21 %
 [m3video]               totalIsr2Done :0 %
 [m3video]               totalWait2Done :21 %
 [m3video]               totalDone2Release :0 %
 [m3video]               totalAcquire2Release :24 %
 [m3video]               totalAcq2acqDelay :75 %
 [m3video]               totalElapsedTime in msec :   10165
 [m3video]               numAccessCnt:     950
 [m3video]              IVA-FPS :      95
 [m3video]              Average time spent per frame in microsec:    2247
 [m3video]      113890: HDVICP-ID:2
 [m3video] All percentage figures are based off totalElapsedTime
 [m3video]               totalAcquire2wait :0 %
 [m3video]               totalWait2Isr :17 %
 [m3video]               totalIsr2Done :0 %
 [m3video]               totalWait2Done :17 %
 [m3video]               totalDone2Release :0 %
 [m3video]               totalAcquire2Release :20 %
 [m3video]               totalAcq2acqDelay :79 %
 [m3video]               totalElapsedTime in msec :   10163
 [m3video]               numAccessCnt:     760
 [m3video]              IVA-FPS :      76
 [m3video]              Average time spent per frame in microsec:    2273
 [m3video] 
 [m3video]  *** ENCODE Statistics ***
 [m3video] 
 [m3video]  Elasped Time           : 9 secs
 [m3video] 
 [m3video] 
 [m3video]  CH  | In Recv In Skip In User  Out Latency 
 [m3video]  Num | FPS     FPS     Skip FPS FPS Min / Max
 [m3video]  --------------------------------------------
 [m3video]    0 |      20       0        0  20   4 /   5
 [m3video]    1 |      20       0        0  20   4 /   5
 [m3video]    2 |      20       0        0  20   4 /   5
 [m3video]    3 |      20       0        0  20  12 /  13
 [m3video]    4 |      20       0        0  20  12 /  14
 [m3video]    5 |      20       0        0  20  11 /  12
 [m3video]    6 |      20       0        0  20  12 /  13
 [m3video]    7 |      20       0        0  20  12 /  14
 [m3video]    8 |      20       0        0  20  11 /  12
 [m3video]    9 |      20       0        0  20  12 /  13
 [m3video]   10 |      20       0        0  20  12 /  14
 [m3video]   11 |      20       0        0  20  11 /  12
 [m3video]   12 |      20       0        0  20  12 /  13
 [m3video]   13 |      20       0        0  20  12 /  14
 [m3video]   14 |       0       0        0   0 255 /   0
 [m3video]   15 |       0       0        0   0 255 /   0
 [m3video] 
 [m3video] Multi Channel Encode Average Submit Batch Size
 [m3video] Max Submit Batch Size : 24
 [m3video] IVAHD_0 Average Batch Size : 2
 [m3video] IVAHD_0 Max achieved Batch Size : 4
 [m3video] IVAHD_1 Average Batch Size : 2
 [m3video] IVAHD_1 Max achieved Batch Size : 4
 [m3video] IVAHD_2 Average Batch Size : 2
 [m3video] IVAHD_2 Max achieved Batch Size : 3
 [m3video] 
 [m3video] Multi Channel Encode Batch break Stats
 [m3video] Total Number of Batches created: 372
 [m3video] All numbers are based off total number of Batches created
 [m3video]       Batch breaks due to batch sizeexceeding limit: 0 %
 [m3video]       Batch breaks due to ReqObj Que being empty: 100 %
 [m3video]       Batch breaks due to changed resolution class: 0 %
 [m3video]       Batch breaks due to interlace and progressivecontent mix: 0 %
 [m3video]       Batch breaks due to channel repeat: 0 %
 [m3video]       Batch breaks due to different codec: 0 %
 [m3video] Total Number of Batches created: 372
 [m3video] All numbers are based off total number of Batches created
 [m3video]       Batch breaks due to batch sizeexceeding limit: 0 %
 [m3video]       Batch breaks due to ReqObj Que being empty: 100 %
 [m3video]       Batch breaks due to changed resolution class: 0 %
 [m3video]       Batch breaks due to interlace and progressivecontent mix: 0 %
 [m3video]       Batch breaks due to channel repeat: 0 %
 [m3video]       Batch breaks due to different codec: 0 %
 [m3video] Total Number of Batches created: 372
 [m3video] All numbers are based off total number of Batches created
 [m3video]       Batch breaks due to batch sizeexceeding limit: 0 %
 [m3video]       Batch breaks due to ReqObj Que being empty: 100 %
 [m3video]       Batch breaks due to changed resolution class: 0 %
 [m3video]       Batch breaks due to interlace and progressivecontent mix: 0 %
 [m3video]       Batch breaks due to channel repeat: 0 %
 [m3video]       Batch breaks due to different codec: 0 %

I don't know why. In my codes, I read yuv data from input file and use DMA to copy the data to other input buffers of the encoder. The codes are attached in the end.

Could someone know the reason? Thanks in advance! Appreciate for your reply!

1460.code.zip

 

  • Could someone help me with the problem?

  • The log indicates encLink is not receiving frames for channels 12 and above. It looks like issue with your app logic in feeding yuv frames.Check you are actually doing Venc_putFullVideoFrames for channel 12 and above and print bufList->frames[].channelNum to confirm you are feeding yuv frames for channels greater than 12

  • Hi Badri,

         Thanks for your reply! The following is the codes which feed YUV data to encoder. I check the bufList.numFrames after Venc_getEmptyVideoFrames() function and the result is always 13 when the CH_NUM>=13.  I find in ti_media_common_def.h there is a macro #define VIDEO_FRAMEBUF_MAX 16. And it is said that the numFrames in VIDEO_FRAMEBUF_LIST_S should be smaller than VIDEO_FRAMEBUF_MAX. I don't quite understand why the numFrames is no more than 13. It seems that it shall be 16 at least.


    if (bufList.numFrames)
    while (FALSE == gReadYUVConfig.thrExit)
    {
    status = Venc_getEmptyVideoFrames(&bufList,0);
    OSA_assert(0 == status);
    printf("%d\n", bufList.numFrames);

    {
    IpcFramesFreeFrameBuf(&bufList,frmObj, CH_NUM);
    }
    else
    printf("get empty video frames failed\n");

    IpcFramesFillBufInfo(&bufList,frmObj, CH_NUM);
    if(bufList.numFrames)
    {

    fread((unsigned char *)(bufList.frames[0].addr[0][0]), 1, gReadYUVConfig.width * gReadYUVConfig.height,
    gReadYUVConfig.fin[bufList.frames[0].channelNum]);
    fread((unsigned char *)(bufList.frames[0].addr[0][1]), 1, gReadYUVConfig.width * gReadYUVConfig.height * 0.5,
    gReadYUVConfig.fin[bufList.frames[0].channelNum]);

    if(feof(gReadYUVConfig.fin[bufList.frames[0].channelNum]))
    {
    fseek(gReadYUVConfig.fin[bufList.frames[0].channelNum], 0, SEEK_SET);
    }
    copy2D_Y.srcPhysAddr = (unsigned long)(bufList.frames[0].phyAddr[0][0]);
    copy2D_UV.srcPhysAddr = (unsigned long)(bufList.frames[0].phyAddr[0][0] + FRWIDTH*FRHEIGHT);
    for(i=1;i<CH_NUM;i++)
    {
    //copy Y component
    copy2D_Y.dstPhysAddr = (unsigned long)(bufList.frames[i].phyAddr[0][0]);
    OSA_dmaCopy2D(&dmaHndl, &copy2D_Y, 1);
    //copy UV component
    copy2D_UV.dstPhysAddr = (unsigned long)(bufList.frames[i].phyAddr[0][0] + FRWIDTH*FRHEIGHT);
    OSA_dmaCopy2D(&dmaHndl, &copy2D_UV, 1);

    }
    status = Venc_putFullVideoFrames(&bufList);
    OSA_assert(0 == status);
    }
    OSA_waitMsecs(33);
    }

  • Hi Badri,

    I notice that there is a param named numBufPerCh[ENC_LINK_MAX_BUF_ALLOC_POOLS] in EncLink_CreateParams. In the DVRRDK demo usecase it is set as 

          encPrm.numBufPerCh[0] = 4

    but the ENC_LINK_MAX_BUF_ALLOC_POOLS is 7. I don't know if it affects.

  • Hi Badri,

    Could you see my reply? I still could not solve this problem? I check the ipcFrameOutLink API and find the following codes which get the Frame Buffer from queue. I think it is because the OSA_queGet() function does not return success.

    for (idx = 0; idx < VIDFRAME_MAX_FRAME_BUFS; idx++)
    {
         status = OSA_queGet(&pObj->emptyFrameBufQue,
                                          (Int32 *) & pFrame,
                                          OSA_TIMEOUT_NONE);
         if (status != OSA_SOK)
              break;
         IpcFramesOutLink_copyFrameInfoEmptyFrame(pObj,
                                                                              pFrame,
                                                                              &pFrameBufList->frames[idx]);
         IpcFramesOutLink_putListElemInFreeQ(pObj,  (SystemIpcFrames_ListElem *)pFrame);
    }

     

  • Invoke Vsys_printBufferStatistics() and examine the buffer stats of encoder (last few channels). This will give some clue.

    Issue could be that app would have fed few YUV frames initially and those never got processed at encoder and hence no further buffers available to app.  

  • Hi Sivagamy,

        Thanks for your reply! The Vsys_printBufferStatistics() function could just output the following info about encode link.

          [m3video]  *** Encode Statistics ***
          [m3video]   23443: ENC: Rcvd from prev = 1890, Returned to prev = 1890
          [m3video]  ENC Out  BitBuf Q Status
          [m3video] Empty Q 0 -> count 96, wrPtr 66, rdPtr 354
          [m3video] Full Q -> count 0, wrPtr 354, rdPtr 354

        I could not get some useful info from that. I check the ipcLink.h and find that there is no CMD to get ipcFrameOut/In Link's buffer statics. For the returned buffers from Venc_getEmptyVideoFrames() function, it is 13 at the first time. So the app could not feed input data to all the channels of encoder.

        Could you give any further advise?  

     

     

  • Hi Sivagamy,

       I change the input video resolution from 704x576 to 352x288 and now all the 16 channels work fine. It seems that there is some resources lack for higher resolution. Could you help me to find out what it is?

  • To debug this issue pls do the following:

    1. Simply your app logic in demo_venc.c . It is needlessly complex. Have simple flow as below:

        a) Create an array of frameObj which represents free TYV frames.

       b) In each frameObj have a refCount (already present) and channelList (add newly for debug)

       c) For IpcFramesFillBufInfo() don't take any parameter such as numFrames.Have simple logic as below:

           1.Loop thru list of all frameObj. Find one with refCount of 0.

           2. For _all_ channels populate bufList->frames info using the _same_ frameObj YUV pointer .

           3. Increment refCount by numChannels and populate channelList array with all channel numbers from 0 to 15.

          4. Read YUV contents from file.

          5. There is no need to have separate frameOb for each channel and there is no need to DMA from frameObj of channel 0 to other channels.

       d) WHen freeing YUV buffers decrement reference count and remove the freed channel from channelList array

    2) Rerun test after above app logic fix.From channelLIst check which channels are not freed in frameObj and confirm if channel 12 - 15 are sent for encoding but not freed.

    3) Once you have confirmed it is really channel 12 - 15 that are not freed do the following:

        a) In /dvr_rdk/mcfw/src_bios6/links_common/ipcFramesIn/ipcFramesInLink_tsk.c add link cmd to print stats. You can refer ipcFramesOut link for reference. Print the following:

                               pObj->stats.recvCount,
                               pObj->stats.freeCount,
                               pObj->stats.droppedCount

        b) /dvr_rdk/mcfw/src_bios6/links_m3video/iva_enc/encLink_common.c print following stats in function

          Int32 EncLink_printBufferStatus (EncLink_Obj * pObj)

           Utils_queGetQueuedCount(pChObj->inQue) for all channel (0 - 16)

    If you find inQue count for channel 12 - 15 non-zero but these channels are not being encoded we will have to debug further by putting additional debug code. Pls do above changes and provide logs to enable further debug.

  • Hi Badri,

    Sorry to reply you so late! Do you mean that the frameObj is not fixed to one channel but could be assigned to any channel freely?

    Badri Narayanan said:
    3. Increment refCount by numChannels and populate channelList array with all channel numbers from 0 to 15.

    I don't quite understand how to set refCount and channelList array of each frameObj. As each frameObj is assigned to one frame in bufList->frames, should the refCount be 0 or 1? What is the channelList array used for? is it used for record which channel is associated with the frameObj currently?

  • Badri Narayanan said:
    a) Create an array of frameObj which represents free TYV frames.

    Should the frameObj array be more than the encode channels? And how to calculate the array size from the channel numbers?

  • You have a set of YUV buffers (frameObj). You are filling the buffer by reading a frame from a file and then sending the same frame to all the encode channels. For this you need a reference count to know when the YUV buffer is free. The reference count will be decremented each time a channel frees the YUV buffer. When reference count is 0 , YUV buffer can be returned to free pool. The channelList is an array and will hold list of channels that have not freed the buffer yet.

  • Hi Badri,

    How could I feed all the encode channels with the same frame? The data process logic is as follows:

    1. Venc_getEmptyVideoFrames(&bufList,0)

    2. IpcFramesFillBufInfo(&bufList,frmObj)

    3. Fill the buffers in bufList with YUV data

    4. Venc_putFullVideoFrames(&bufList)

    After step 1, I think each buffer in bufList is associated with each channel. So we should fill the buffers with different YUV frames and send the bufList to the encoder. 

  • Hi Badri,

    I change my code logic as what you said and now the program runs successfully. I aslo change the 

    #define VIDEO_FRAMEBUF_MAX             (48)//16

    #define VIDFRAME_MAX_FRAME_BUFS  (48)//16

    in ti_media_common_def.h and vidframe.h, and now I could create upto 48 channels of encoder. The modified codes is attached in the end.

    But in practical, each channel will have different input data, should I define much more frameObj? 

    #define maxframeObjNum  10
    #define MAX_CH          48
    
    Int32 frameObjIndex = -1;
    typedef struct 
    {
        Ptr        bufVirt;
        UInt32     bufPhy;
        UInt32     refCnt;
        UInt32     maxWidth;
        UInt32     maxHeight;
        UInt32     curWidth;
        UInt32     curHeight;
        UInt32     numCh;
    	Uint32     channelList[MAX_CH];
    } VdecVenc_IpcFramesBufObj;
    
    
    
    Void IpcFramesFillBufInfo(VIDEO_FRAMEBUF_LIST_S *bufList,
                              VdecVenc_IpcFramesBufObj  frameObj[])
    {
        Int i,j;
        frameObjIndex = (frameObjIndex+1)%maxframeObjNum;
    	for(i = 0; i < maxframeObjNum; i++)
    	{
    		if (frameObj[frameObjIndex].refCnt == 0)
            {	
    			for(j=0; j<bufList->numFrames; j++)
    			{
    				// Send the same buffer to all enabled channels
    				bufList->frames[j].addr[0][0] =  frameObj[frameObjIndex].bufVirt;
    				bufList->frames[j].phyAddr[0][0] = (Ptr)frameObj[frameObjIndex].bufPhy;
    				bufList->frames[j].addr[0][1] =  frameObj[frameObjIndex].bufVirt + 
    				                                 frameObj[frameObjIndex].curWidth * frameObj[frameObjIndex].curHeight;
    				bufList->frames[j].phyAddr[0][1] = (Ptr)frameObj[frameObjIndex].bufPhy + 
    				                                   frameObj[frameObjIndex].curWidth * frameObj[frameObjIndex].curHeight;
    				bufList->frames[j].frameWidth =  frameObj[frameObjIndex].curWidth;
    				bufList->frames[j].frameHeight =  frameObj[frameObjIndex].curHeight;
    				bufList->frames[j].fid = VIDEO_FID_TYPE_FRAME;
    				bufList->frames[j].channelNum = j;
    				bufList->frames[j].framePitch[0] = frameObj[frameObjIndex].curWidth;
    				bufList->frames[j].framePitch[1] = frameObj[frameObjIndex].curWidth;
    				bufList->frames[j].framePitch[2] = 0;
    				bufList->frames[j].timeStamp  = 0;
    				
    				frameObj[frameObjIndex].refCnt++;
    				frameObj[frameObjIndex].channelList[j] = 1;
    			}
    			break;
            }
            frameObjIndex = (frameObjIndex+1)%maxframeObjNum;	
    	}
    }
    
    Void  IpcFramesInitFrame(VdecVenc_IpcFramesBufObj *frameObj,
    						 Vsys_AllocBufInfo        *bufInfo,
    						 UInt32                   maxWidth,
                             UInt32                   maxHeight)
    {
        int i;
    	frameObj->bufPhy  = (UInt32)bufInfo->physAddr;
        frameObj->bufVirt = bufInfo->virtAddr;
        frameObj->maxWidth = maxWidth;
        frameObj->maxHeight = maxHeight;
        frameObj->curWidth = maxWidth;
        frameObj->curHeight = maxHeight;
        frameObj->numCh     = 1;
        frameObj->refCnt    = 0;
    	for(i=0;i<MAX_CH;i++)
    		frameObj->channelList[i] = 0;
    }
    
    Void   IpcFramesFreeFrameBuf(VIDEO_FRAMEBUF_LIST_S *bufList,
    						     VdecVenc_IpcFramesBufObj      frameObj[])
    {
        Int i,j;
        for (i = 0; i < bufList->numFrames; i++)
        {
            for (j = 0; j < maxframeObjNum; j++)
            {
                if (frameObj[j].bufPhy ==(UInt32)bufList->frames[i].phyAddr[0][0])
                {
    				OSA_assert(frameObj[j].refCnt > 0); 
                    frameObj[j].refCnt--;//decrement reference count
    				frameObj[j].channelList[i] = 0;//remove the freed channel from channelList
                }    
            }
        }
    }
    
    void *FramesRdSendFxn(Void * prm)
    {
    	UInt32 resId;
    	VIDEO_FRAMEBUF_LIST_S bufList;
    	Int status;
    	int i = 0;
    	int count = 0;
    
    	OSA_semWait(&gReadYUVConfig.thrStartSem,OSA_TIMEOUT_FOREVER);
    
    	while (FALSE == gReadYUVConfig.thrExit)
    	{
    	    status =  Venc_getEmptyVideoFrames(&bufList,0);
        	OSA_assert(0 == status);
        	
        	//printf("%d\n", bufList.numFrames);
    		if (bufList.numFrames)
    	    {
    			IpcFramesFreeFrameBuf(&bufList,frmObj);
    	    }
    	    else
    		{
    			bufList.numFrames = CH_NUM;
    	        printf("get empty video frames failed\n");
    		}
    
    		IpcFramesFillBufInfo(&bufList,frmObj);
    
    		if(bufList.numFrames)
    		{
    			//read YUV pic from input file
    			fread((unsigned char *)(bufList.frames[0].addr[0][0]), 1, gReadYUVConfig.width * gReadYUVConfig.height, 
    			        gReadYUVConfig.fin[bufList.frames[0].channelNum]);
    			fread((unsigned char *)(bufList.frames[0].addr[0][1]), 1, gReadYUVConfig.width * gReadYUVConfig.height * 0.5, 
    			        gReadYUVConfig.fin[bufList.frames[0].channelNum]);
    			if(feof(gReadYUVConfig.fin[bufList.frames[0].channelNum]))
    			{
    				fseek(gReadYUVConfig.fin[bufList.frames[0].channelNum], 0, SEEK_SET);
    			}
    			status = Venc_putFullVideoFrames(&bufList);
    			OSA_assert(0 == status);
    		}
    		else
    		    printf("fill buffer info failed\n");
    
            OSA_waitMsecs(33);
        }
    }