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.

Question about using XDM_RESET on DM368 H264 Decoder

When I use Vdec2_control with XDM_RESET on the H264 decoder, how do I know what buffers are freed?  Do I just assume that after the reset, I should go through my table of buffers and mark them as freed?

For some reason I seem to be getting display buffers with the "codec in use" bit stuck after some non-fatal errors.  I'm having a hard time figuring out how to keep the decoder running without running out of display buffers.  It even seems like performing a reset is not changing the decoder to a clean state.  But I'm not sure that it isn't my fault as this time.

John A

  • I put the function handleCodecErrBufs() in DVSDK 4.01. "decode" example,
    and call it every time i get any bit error, even non-fatal. That way works best for me.
    It's been few weeks since i wrote this code, so it's not very fresh in my memory, and it's not finished yet.

     

     if (ret == Dmai_EBITERROR ) {
               // ERR("Dmai_EBITERROR-prime:%d,num:%d:\n",Buffer_getNumBytesUsed(hInBuf),frameNbr);
               bufsSent = handleCodecErrBufs(hVd2, envp->hDisplayInFifo, outArgs.outputID[0], outArgs.freeBufID[0], envp->hDisplayOutFifo, priming);
               continue;
     }

     

     

    static Int handleCodecErrBufs(Vdec2_Handle hVd2, Fifo_Handle hFifo, int outputbufid, int freebufid, Fifo_Handle hDisplayOutFifo, int prime)
    {
        Buffer_Handle hOutBuf, hFreeBuf;
        Int numDisplayBufs = 0;
        int i = 0;
        int minoutbufs = 0;
        //static int first = 1;
    /////////////////////////////////////////////////////////////////////////////////////////////
    int gnumBufs = Vdec2_getMinOutBufs(hVd2) + NUM_DISPLAY_BUFS;
    Vdec2e_Handle hVd =hVd2;
    //printf("displayBufIdx=%d\n",hVd->displayBufIdx);

    for (i=0;i<IVIDDEC2_MAX_IO_BUFFERS;i++)
    {
      hVd->hDisplayBufs[i] = NULL;
    }
    hVd->displayBufIdx = 0;


    for (i = 0; i < gnumBufs; i++)
    {
       hVd->hFreeBufs[i] = BufTab_getBuf(hVd->hOutBufTab,i);
    }
    if (i < IVIDDEC2_MAX_IO_BUFFERS)
    {
        hVd->hFreeBufs[i] = NULL;
    }
    hVd->freeBufIdx=0;

    i=0;

    /////////////////////////
    //Vdec2_flush(hVd2);
    ///////////////////////////////////////////////////////////////////////////////
        VIDDEC2_Status         decStatus;
        XDAS_Int32             status;
        decStatus.data.buf = NULL;
        decStatus.size = sizeof(VIDDEC2_Status);
        VIDDEC2_Handle hDecode = Vdec2_getVisaHandle(hVd2);
        status = VIDDEC2_control(hDecode, XDM_RESET, 0, &decStatus);
        if (status != VIDDEC2_EOK) {
           ERR("XDM_RESET control failed\n");
        }
    /////////////////////////////////////////////////////////////////////////////////


        // Get a buffer for display from the codec
        hOutBuf = Vdec2_getDisplayBuf(hVd2);
           
        while (hOutBuf) {
            if (bCached)
            {
           Memory_cacheWb(Buffer_getUserPtr(hOutBuf),  Buffer_getSize(hOutBuf));
            }
            // Send buffer to display thread
            if (Fifo_put(hFifo, hOutBuf) < 0) {
                ERR("Failed to send buffer to display thread\n");
                return FAILURE;
            }
            numDisplayBufs++;
            // Get another buffer for display from the codec
            hOutBuf = Vdec2_getDisplayBuf(hVd2);
        }

        // Get a buffer to free from the codec
        hFreeBuf = Vdec2_getFreeBuf(hVd2);
        while (hFreeBuf) {
            // The codec is no longer using the buffer
            Buffer_freeUseMask(hFreeBuf, CODEC_FREE);
    #ifdef CorruptFrm
        if (outputbufid==0)
            {
          i = Buffer_getId(hFreeBuf);       
           if (i == (freebufid-1))
               {
            //printf("#######################Freebuf got from decoder after critical error is %d\n",i);//       
            BufferGfx_setFrameType(hFreeBuf,Buffer_Type_GRAPHICS);
            BufferGfx_resetDimensions(hFreeBuf);      
            //Buffer_print(hFreeBuf);
            if (prime)
                    {
                Buffer_freeUseMask(hFreeBuf, DISPLAY_FREE);
            }
            else
                    {     
                  //BufTab_print(hOutBufTab);//   
              if (Fifo_put(hDisplayOutFifo, hFreeBuf) < 0)
                      {
              ERR("Failed to send buffer to display thread\n");
              return FAILURE;
              }
            }
           }
        }
    #endif
            hFreeBuf = Vdec2_getFreeBuf(hVd2);
        }

    //BufTab_freeAll(hBufTab);
        return numDisplayBufs;
    }

     

     

     

    Regards,
    Marko.

  • Thanks Marko,

    You're helping me out again.  I'm using dvsdk 4.0.0.22 and it doesn't have this function.

    John A

  • Hi John,

    Actually that fucntion is not in original DVSDK decode example.
    I took modified decode example from Yashwant Dutt, from : http://e2e.ti.com/support/embedded/f/356/t/56421.aspx  (decoder_dmai.zip),
    but i add that function handleCodecErrBufs(), and  call it only on bit error.
    I'm not sure if it is done properly, but at least i can decode now, without program hang.

     

  • Ah... I just downloaded the latest SDK and didn't see it.  I plan to rewrite it to fit my architecture but at least now I have a good guide.

    John A

  • Basically, i just followed the Yashwant's decode example, and added  new function handleCodecErrBufs.
    You also have to add  a new  DMAI   Vdec2_process2   function  in Vdec2.c.

    Marko.

     

  • Marko Shink said:

    Basically, i just followed the Yashwant's decode example, and added  new function handleCodecErrBufs.
    You also have to add  a new  DMAI   Vdec2_process2   function  in Vdec2.c.

    Marko.

     

    Marko, I don't see a Vdec2_process2 in vdec2.c in either version of the "4" sdk.  Only Vdec2_process, which I'm currently using.

    John A

     

  • It is in Yashwant's   Vdec2.c, and it is called  "Vdec2_process_new"  there.
    Look at :  http://e2e.ti.com/support/embedded/f/356/t/56421.aspx   (decoder_dmai.zip)

    Marko.

     

  • Checking it out now!

  • And here is my version of Vdec2_process_2  in Vdec2.c :


    Int Vdec2_process_2(Vdec2_Handle hVd, Buffer_Handle hInBuf, Buffer_Handle hDstBuf, VIDDEC2_OutArgs *outArgs)
    {
        VIDDEC2_InArgs          inArgs;
        //VIDDEC2_OutArgs         outArgs;
        XDM1_BufDesc            inBufDesc;
        XDM_BufDesc             outBufDesc;
        XDAS_Int32              outBufSizeArray[XDM_MAX_IO_BUFFERS];
        XDAS_Int8              *outBufPtrArray[XDM_MAX_IO_BUFFERS];
        XDAS_Int32              status;
        Int                     bufIdx;
        BufferGfx_Dimensions    dim;
        XDAS_Int8              *inPtr, *dstPtr;
        Int                     ret = Dmai_EOK;
        UInt32                  offset;
        UInt32                  bpp;

        assert(hVd);
        assert(hInBuf);
        assert(hDstBuf);
        assert(Buffer_getUserPtr(hInBuf));
        assert(Buffer_getUserPtr(hDstBuf));
        assert(Buffer_getNumBytesUsed(hInBuf));
        assert(Buffer_getSize(hDstBuf));
        assert(Buffer_getType(hDstBuf) == Buffer_Type_GRAPHICS);

        bpp = ColorSpace_getBpp(BufferGfx_getColorSpace(hDstBuf));
     
        BufferGfx_getDimensions(hDstBuf, &dim);

        offset = (dim.y * dim.lineLength) + (dim.x * (bpp >> 3));
        assert(offset < Buffer_getSize(hDstBuf));

        inPtr  = Buffer_getUserPtr(hInBuf);
        dstPtr = Buffer_getUserPtr(hDstBuf) + offset;

        if (BufferGfx_getColorSpace(hDstBuf) == ColorSpace_YUV420PSEMI) {
            outBufPtrArray[0]       = dstPtr;
            outBufSizeArray[0]      = hVd->minOutBufSize[0];

            outBufPtrArray[1]       = dstPtr + Buffer_getSize(hDstBuf) * 2 / 3;
            outBufSizeArray[1]      = hVd->minOutBufSize[1];
        }
        else if (BufferGfx_getColorSpace(hDstBuf) == ColorSpace_YUV420P) {
            outBufPtrArray[0]       = dstPtr;
            outBufSizeArray[0]      = hVd->minOutBufSize[0];

            outBufPtrArray[1]       = dstPtr + Buffer_getSize(hDstBuf) * 2 / 3;
            outBufSizeArray[1]      = hVd->minOutBufSize[1];

            outBufPtrArray[2]       = dstPtr + Buffer_getSize(hDstBuf) * 5 / 6; 
            outBufSizeArray[2]      = hVd->minOutBufSize[2];
        }
        else if (BufferGfx_getColorSpace(hDstBuf) == ColorSpace_UYVY) {
            outBufPtrArray[0]       = dstPtr;
            outBufSizeArray[0]      = hVd->minOutBufSize[0];
        }
        else {
            Dmai_err0("Unsupported color format of destination buffer\n");
            return Dmai_EINVAL;
        }

        outBufDesc.numBufs          = hVd->minNumOutBufs;
        outBufDesc.bufSizes         = outBufSizeArray;
        outBufDesc.bufs             = outBufPtrArray;

        /* One buffer with encoded data */
        inBufDesc.numBufs           = 1;
        inBufDesc.descs[0].buf      = inPtr;
        inBufDesc.descs[0].bufSize  = Buffer_getNumBytesUsed(hInBuf);

        inArgs.size                 = sizeof(VIDDEC2_InArgs);
        inArgs.numBytes             = Buffer_getNumBytesUsed(hInBuf);
        inArgs.inputID              = GETID(Buffer_getId(hDstBuf));

        outArgs->size                = sizeof(VIDDEC2_OutArgs);

        /* Decode video buffer */
        status = VIDDEC2_process(hVd->hDecode, &inBufDesc, &outBufDesc, &inArgs,
                                 outArgs);

        Buffer_setNumBytesUsed(hInBuf, outArgs->bytesConsumed);

        Dmai_dbg4("VIDDEC2_process() ret %d inId %d inUse %d consumed %d\n",
                  status, Buffer_getId(hDstBuf), outArgs->outBufsInUseFlag,
                  outArgs->bytesConsumed);

        if (status != VIDDEC2_EOK) {
            if (XDM_ISFATALERROR(outArgs->decodedBufs.extendedError)) {
                Dmai_err2("VIDDEC2_process() failed with error (%d ext: 0x%x)\n",
                          (Int)status, (Uns) outArgs->decodedBufs.extendedError);
                return Dmai_EFAIL;
            }
            else {
                Dmai_dbg1("VIDDEC2_process() non-fatal error 0x%x\n",
                          (Uns) outArgs->decodedBufs.extendedError);
                ret = Dmai_EBITERROR;
            }
        }

        /* Prepare buffers for display */
        for (bufIdx = 0;
             bufIdx < IVIDDEC2_MAX_IO_BUFFERS && outArgs->outputID[bufIdx] > 0;
             bufIdx++) {

            hVd->hDisplayBufs[bufIdx] =
                BufTab_getBuf(hVd->hOutBufTab, GETIDX(outArgs->outputID[bufIdx]));

            dim.width = outArgs->displayBufs[bufIdx].frameWidth;
            dim.height = outArgs->displayBufs[bufIdx].frameHeight;
            dim.lineLength = outArgs->displayBufs[bufIdx].framePitch;

            /* Is there an offset to where we are supposed to start displaying? */
            offset = outArgs->displayBufs[bufIdx].bufDesc[0].buf -
                     Buffer_getUserPtr(hVd->hDisplayBufs[bufIdx]);

            dim.y = offset / dim.lineLength;
            dim.x = offset - ((dim.y * dim.lineLength) >> (bpp >> 4));

            Buffer_setNumBytesUsed(hVd->hDisplayBufs[bufIdx],
                                   Vdec2_getOutBufSize(hVd));
            BufferGfx_setFrameType(hVd->hDisplayBufs[bufIdx],
                                   outArgs->displayBufs[bufIdx].frameType);

            if (BufferGfx_setDimensions(hVd->hDisplayBufs[bufIdx], &dim) < 0) {
                Dmai_err0("Frame does not fit in allocated buffer\n");
                return Dmai_EFAIL;
            }
        }

        /* Null terminate the list of display buffers */
        if (bufIdx < IVIDDEC2_MAX_IO_BUFFERS) {
            hVd->hDisplayBufs[bufIdx] = NULL;
        }

        hVd->displayBufIdx = 0;

        /* Prepare buffers to be freed */
        for (bufIdx = 0;
             bufIdx < IVIDDEC2_MAX_IO_BUFFERS && outArgs->freeBufID[bufIdx] > 0;
             bufIdx++) {

            hVd->hFreeBufs[bufIdx] =
                BufTab_getBuf(hVd->hOutBufTab, GETIDX(outArgs->freeBufID[bufIdx]));
        }

        /* Null terminate the list of free buffers */
        if (bufIdx < IVIDDEC2_MAX_IO_BUFFERS) {
            hVd->hFreeBufs[bufIdx] = NULL;
        }

        hVd->freeBufIdx = 0;

        /* Was this just the first field of an interlaced frame? */
        if (outArgs->outBufsInUseFlag) {
            ret = Dmai_EFIRSTFIELD;
        }

        return ret;
    }

  • Marko,

    So the main different is that the new function is using an VIDDEC2_OutArgs that's supplied by the application?

    I noticed that the version in the zip file has a correction for the location of the chroma data.  I haven't yet figured out why it's needed, but I see that you didn't put it in your version of the code.

    John A

  • John,

    Yes, it think the point is to get VIDDEC2_OutArgs in your application, to know which buffers to free.
    About chroma data location, i didn't pay attention, but my decoder seems to work fine without that.
    Right now i don't have time to check that, since i have another urgent work.

    Marko.