[FFmpeg-devel] Allocating own buffers for each decoded frame

Umar Qureshey umar at janteq.com
Thu Jul 18 03:50:11 CEST 2013


Hi,
I have implemented colorspace conversion in hardware of the i.MX6 SoC.  I pass each frame's buffer to the hardware and it gives me back a separate output buffer which has the converted.  However,  the hardware only works with physical memory.  So I allocate physical memory via a provided driver ioctl, mmap it in my process space, copy the input frame's buffer to this mmap'ed, perform the conversion, and copy the output buffer to mplayer's destination memory.  This seems rather convoluted.  
Is there a way to allow me to allocate the memory myself so I won't have to do these extraneous memory copies?

Code thus far:

static int imx6_yuv420_to_rgb565le(SwsContext *c, uint8_t *src[], int srcStride[],
                           int srcSliceY, int srcSliceH,
                           uint8_t *dst[], int dstStride[])
{
    int isize, osize, ret = 0, i, y, ysize, cbsize, crsize;
    void *inbuf=NULL, *outbuf=NULL, *inbuf_ptr;
    const unsigned char *py, *pu, *pv;
    
    //Clear task struct.
    memset(&c->task, 0, sizeof(c->task));
    //Open the Image Processing Unit.
    c->fd_ipu = open("/dev/mxc_ipu", O_RDWR, 0);
    if (c->fd_ipu < 0) 
    {
        av_log(c, AV_LOG_ERROR, "open ipu dev fail\n");
        return 0;
    }
    
    //1)  Allocate physical memory to allow IPU to DMA in and DMA out.
    //1a) Calculate size of input/output buffers.
    INPUT_WIDTH(c) = c->srcW;
    OUTPUT_WIDTH(c) = c->dstW;
    INPUT_HEIGHT(c) = c->srcH;
    OUTPUT_HEIGHT(c) = c->dstH;
    INPUT_FORMAT(c) = IPU_PIX_FMT_YUV420P;
    OUTPUT_FORMAT(c) = IPU_PIX_FMT_RGB565;
    OUTPUT_ROTATION(c) = 0;
    
    isize = INPUT_PADDR(c) = ((srcStride[0] * srcSliceH) << 1); //ensure input buffer is big enough to hold all planes.
    osize = OUTPUT_PADDR(c) = ((OUTPUT_WIDTH(c) * OUTPUT_HEIGHT(c)) << 1);  //each pixel RGB value is 16 bits wide.
    //1b) Allocate contiguous physical memory for input/output image.
    //    input.paddr and output.paddr contains the amount needed.
    //    These values will be replaced with physical address on success.
    ret = ioctl(c->fd_ipu, IPU_ALLOC, &INPUT_PADDR(c));
    if (ret < 0) 
    {
        av_log(c, AV_LOG_ERROR, "physical memory allocation of input buffer failed: (errno = %d)\n", errno);
        ret = -1;
        goto done;
    }
    ret = ioctl(c->fd_ipu, IPU_ALLOC, &OUTPUT_PADDR(c));
    if (ret < 0) 
    {
        av_log(c, AV_LOG_ERROR, "physical memory allocation of output buffer failed: (errno = %d)\n", errno);
        ret = -2;
        goto done;
    }
    //2) Get the virtual addresses for the physical input/output buffers so we can access them from userland here.
    inbuf = mmap(0, isize, PROT_READ | PROT_WRITE, MAP_SHARED, c->fd_ipu, INPUT_PADDR(c));
    if (!inbuf) 
    {
        av_log(c, AV_LOG_ERROR, "inbuf mmap failed\n");
        ret = -3;
        goto done;
    }
    outbuf = mmap(0, osize, PROT_READ | PROT_WRITE, MAP_SHARED, c->fd_ipu, OUTPUT_PADDR(c));
    if (!outbuf) 
    {
        av_log(c, AV_LOG_ERROR, "outbuf mmap failed\n");
        ret = -4;
        goto done;
    }
    //3) Copy the raw image to the input IPU buffer.
    //temp
    //3a) Copy the Y' plane.
    inbuf_ptr = inbuf;
    for (y=0; y < srcSliceH; ++y)
    {
       py =  src[0] + y * srcStride[0];
       memcpy(inbuf_ptr, py, c->srcW);
       inbuf_ptr += c->srcW;
    }

    //3b) Copy the Cb plane.
    for (y=0; y < (srcSliceH >> 1); ++y)
    {
        pu = src[1] + y * srcStride[1];
        memcpy(inbuf_ptr, pu, c->chrSrcW);
        inbuf_ptr += c->chrSrcW;
    }

    //3c) Copy the Cr plane.
    for (y=0; y < (srcSliceH >> 1); ++y)
    {
        pv = src[2] + y * srcStride[2];
        memcpy(inbuf_ptr, pv, c->chrSrcW);
        inbuf_ptr += c->chrSrcW;
    }

    //4) Perform the colorspace conversion.
    KICK_IPUTASKONE(c->fd_ipu, c);
    
    //5) Copy converted buffer.
    memcpy(dst[0], outbuf, osize);
done:
    if (outbuf)
        munmap(outbuf, osize);
    if (OUTPUT_PADDR(c))
        ioctl(c->fd_ipu, IPU_FREE, &OUTPUT_PADDR(c));
    if (inbuf)
        munmap(inbuf, isize);
    if (INPUT_PADDR(c))
        ioctl(c->fd_ipu, IPU_FREE, &INPUT_PADDR(c));
    if (c->fd_ipu)
        close(c->fd_ipu);
    return srcSliceH;
}




More information about the ffmpeg-devel mailing list