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.

AM57x VPE Change V4L2 Format

Hello,

I am trying to change the output format of the VPE without closing the handle to the VPE. I am using the 04/2016 release of the Linux Processor SDK for the AM57XX EVM.

My goal is to do the following:

Open VPE -> Configure VPE -> Stream On -> Queue NV12 Frame -> VPE -> Deqeue NV12 Frame -> Stream Off -> Reconfigure VPE ->  Stream On -> Queue NV12 Frame -> VPE -> Deqeue  RGB24 -> Stream Off -> Cleanup

I've modified the vpetest.c main function but it always fails on the second call to allocBuffers at the "VIDIOC_S_FMT" ioctl call ( after describeFormat("rgb24") ). 

The application prints:

Cant set color format
: Device or resource busy

The linux console complains:

vpe 489d0000.vpe: queue busy

When I look in the driver source, I see that it still thinks the queue is busy:

if (vb2_is_busy(vq)) {
		vpe_err(ctx->dev, "queue busy\n");
		return -EBUSY;
}

/**
 * vb2_is_busy() - return busy status of the queue
 * @q:          videobuf queue
 *
 * This function checks if queue has any buffers allocated.
 */
static inline bool vb2_is_busy(struct vb2_queue *q)
{
        return (q->num_buffers > 0);
}

How can I change the format of the V4L2 Driver without closing the VPE and re-opening it? Thank you for any support.

Here is my modified code for vpetest.c:

int main ( int	argc, char	*argv[]) {

    int	i, ret = 0;

    int	srcHeight  = 0, dstHeight = 0;
    int	srcWidth   = 0, dstWidth  = 0;
    int	srcSize    = 0, dstSize   = 0, srcSize_uv = 0, dstSize_uv = 0;
    int	srcFourcc  = 0, dstFourcc = 0;
    int	src_coplanar = 0, dst_coplanar = 0;
    enum v4l2_colorspace	src_colorspace, dst_colorspace;

    void	*srcBuffers[1];
    void	*dstBuffers[1];
    void	*srcBuffers_uv[1];
    void	*dstBuffers_uv[1];
    int	src_numbuf = 1;
    int	dst_numbuf = 1;
    int	num_frames = 20;
    int	dequeued_frames = 0;
    int	interlace = 0;
    int	translen = 3;
    struct	v4l2_control ctrl;
    struct	v4l2_crop crop;
    int field;
    off_t file_size;

    // Open input file in read only mode
    fin		= open ("/input.nv12", O_RDONLY);
    srcWidth	= 800;
    srcHeight	= 480;
    describeFormat ("nv12", srcWidth, srcHeight, &srcSize, &srcFourcc, &src_coplanar, &src_colorspace);

    // Open output file in write mode Create the file if not present
    fout		= open ("/output.nv12", O_WRONLY | O_CREAT | O_TRUNC, 777);
    dstWidth	= 800;
    dstHeight	= 480;
    describeFormat ("nv12", dstWidth, dstHeight, &dstSize, &dstFourcc, &dst_coplanar, &dst_colorspace);

    // no interlace
    interlace = 0;

    // Calculate number of frames
    num_frames = 1;

    // Debug
    printf ("Input  @ %d = %d x %d , %d\nOutput @ %d = %d x %d , %d\n",
        fin,  srcWidth, srcHeight, srcFourcc,
        fout, dstWidth, dstHeight, dstFourcc);

    /*************************************
        Files are ready Now
    *************************************/

    // Open VPE
    fd = open("/dev/video0",O_RDWR);
    if(fd < 0) {
        pexit("Cant open /device\n");
    }

    // Init device
    memset(&ctrl, 0, sizeof(ctrl));
    ctrl.id = V4L2_CID_TRANS_NUM_BUFS;
    ctrl.value = translen;
    ret = ioctl(fd, VIDIOC_S_CTRL, &ctrl);
    if (ret < 0)
        pexit("ioctl");

    // Allocate buffers for input
    ret = allocBuffers (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, srcWidth,
        srcHeight, src_coplanar, src_colorspace, &srcSize, &srcSize_uv,
        srcFourcc, srcBuffers, srcBuffers_uv, &src_numbuf, interlace,
        crop);
    if(ret < 0) {
        pexit("Cant Allocate buffurs for OUTPUT device\n");
    }

    // Allocate buffers for output
    ret = allocBuffers (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, dstWidth,
        dstHeight, dst_coplanar, dst_colorspace, &dstSize, &dstSize_uv,
        dstFourcc, dstBuffers, dstBuffers_uv, &dst_numbuf, interlace,
        crop);
    if(ret < 0) {
        pexit("Cant Allocate buffurs for CAPTURE device\n");
    }

    //	Queue All empty buffers	(Available to capture in)
    ret = queueAllBuffers (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, dst_numbuf);
    if(ret < 0) {
        pexit("Error queueing buffers for CAPTURE device\n");
    }

    // Debug
    printf ("Input  Buffers = %d each of size %d\nOutput Buffers = %d each of size %d\n",
        src_numbuf, srcSize, dst_numbuf, dstSize);

    /*************************************
        Driver is ready Now
    *************************************/

    //	Read  into the OUTPUT  buffers from fin file
    field = V4L2_FIELD_TOP;
    for (i = 0; i < src_numbuf; i++) {
        do_read("Y plane", fin, srcBuffers[i], srcSize);
        if (src_coplanar)
            do_read("UV plane", fin, srcBuffers_uv[i], srcSize_uv);

        queue(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, i, field, srcSize, srcSize_uv);
        if (field == V4L2_FIELD_TOP)
            field = V4L2_FIELD_BOTTOM;
        else
            field = V4L2_FIELD_TOP;
    }

    /*************************************
        Data is ready Now
    *************************************/

    // Turn on streaming
    streamON (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
    streamON (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);

    // Convert the frame
    fprintf(stderr,"Number frames: %d\n",num_frames);
    while (num_frames) {
        struct v4l2_buffer buf;
        struct v4l2_plane buf_planes[2];
        int last = num_frames == 1 ? 1 : 0;

        dequeue(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, &buf, buf_planes);
        printf("dequeued source buffer with index %d\n", buf.index);

        if (!last) {
            do_read ("Y plane", fin, srcBuffers[buf.index], srcSize);
            if (src_coplanar)
                do_read ("UV plane", fin, srcBuffers_uv[buf.index], srcSize_uv);

            queue(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, buf.index, field, srcSize, srcSize_uv);
            if (field == V4L2_FIELD_TOP)
                field = V4L2_FIELD_BOTTOM;
            else
                field = V4L2_FIELD_TOP;
        }

        dequeue(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, &buf, buf_planes);
        printf("dequeued dest buffer with index %d\n", buf.index);
        printf("dequed_frames %d\n", ++dequeued_frames);

        do_write("Y plane", fout, dstBuffers[buf.index], dstSize);
        if (dst_coplanar)
            do_write("UV plane", fout, dstBuffers_uv[buf.index], dstSize_uv);

        if (!last)
            queue(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, buf.index, V4L2_FIELD_NONE, dstSize, dstSize_uv);

        num_frames--;

        printf("frames left %d\n", num_frames);
    }

    //	Driver cleanup
    streamOFF (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
    streamOFF (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);

    releaseBuffers (srcBuffers, src_numbuf, srcSize);
    releaseBuffers (dstBuffers, dst_numbuf, dstSize);

    if (src_coplanar)
        releaseBuffers (srcBuffers_uv, src_numbuf, srcSize_uv);
    if (dst_coplanar)
        releaseBuffers (dstBuffers_uv, dst_numbuf, dstSize_uv);

    // Open output file in write mode Create the file if not present
    fout = open ("/test2.nv12", O_WRONLY | O_CREAT | O_TRUNC, 777);
    describeFormat ("rgb24", dstWidth, dstHeight, &dstSize, &dstFourcc, &dst_coplanar, &dst_colorspace);

    // Allocate input buffers
    ret = allocBuffers (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, srcWidth,
        srcHeight, src_coplanar, src_colorspace, &srcSize, &srcSize_uv,
        srcFourcc, srcBuffers, srcBuffers_uv, &src_numbuf, interlace,
        crop);
    if(ret < 0) {
        pexit("Cant Allocate buffurs for OUTPUT device\n");
    }

    // Allocate output buffers
    ret = allocBuffers (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, dstWidth,
        dstHeight, dst_coplanar, dst_colorspace, &dstSize, &dstSize_uv,
        dstFourcc, dstBuffers, dstBuffers_uv, &dst_numbuf, interlace,
        crop);
    if(ret < 0) {
        pexit("Cant Allocate buffurs for CAPTURE device\n");
    }

    //	Queue All empty buffers	(Available to capture in)
    ret = queueAllBuffers (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, dst_numbuf);
    if(ret < 0) {
        pexit("Error queueing buffers for CAPTURE device\n");
    }

    // Read in the data
    field = V4L2_FIELD_TOP;
    for (i = 0; i < src_numbuf; i++) {
        do_read("Y plane", fin, srcBuffers[i], srcSize);
        if (src_coplanar)
            do_read("UV plane", fin, srcBuffers_uv[i], srcSize_uv);

        queue(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, i, field, srcSize, srcSize_uv);
        if (field == V4L2_FIELD_TOP)
            field = V4L2_FIELD_BOTTOM;
        else
            field = V4L2_FIELD_TOP;
    }

    // Enable streaming
    streamON (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
    streamON (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);

    // Convert the frames
    num_frames = 1;
    while (num_frames) {
        struct v4l2_buffer buf;
        struct v4l2_plane buf_planes[2];
        int last = num_frames == 1 ? 1 : 0;

        dequeue(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, &buf, buf_planes);
        printf("dequeued source buffer with index %d\n", buf.index);

        if (!last) {
            do_read ("Y plane", fin, srcBuffers[buf.index], srcSize);
            if (src_coplanar)
                do_read ("UV plane", fin, srcBuffers_uv[buf.index], srcSize_uv);

            queue(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, buf.index, field, srcSize, srcSize_uv);
            if (field == V4L2_FIELD_TOP)
                field = V4L2_FIELD_BOTTOM;
            else
                field = V4L2_FIELD_TOP;
        }

        dequeue(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, &buf, buf_planes);
        printf("dequeued dest buffer with index %d\n", buf.index);
        printf("dequed_frames %d\n", ++dequeued_frames);

        do_write("Y plane", fout, dstBuffers[buf.index], dstSize);
        if (dst_coplanar)
            do_write("UV plane", fout, dstBuffers_uv[buf.index], dstSize_uv);

        if (!last)
            queue(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, buf.index, V4L2_FIELD_NONE, dstSize, dstSize_uv);

        num_frames--;

        printf("frames left %d\n", num_frames);
    }

    //	Driver cleanup
    streamOFF (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
    streamOFF (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);

    releaseBuffers (srcBuffers, src_numbuf, srcSize);
    releaseBuffers (dstBuffers, dst_numbuf, dstSize);

    if (src_coplanar)
        releaseBuffers (srcBuffers_uv, src_numbuf, srcSize_uv);
    if (dst_coplanar)
        releaseBuffers (dstBuffers_uv, dst_numbuf, dstSize_uv);

    close(fin);
    close(fout);
    close(fd);

    return 0;

}

  • Hello,

    You could check this e2e thread:
    e2e.ti.com/.../1804261

    Hope this helps.

    BR
    Margarita
  • Hi Margarita,

    Thanks for the information.

    It seems that we have to close the VPE  file descriptor  and re-open it to use different sized V4L2 buffers with VIDIOC_REQBUF. This post details the m2m limitation on that:

    http://linux-media.vger.kernel.narkive.com/0T4I2YJr/question-about-set-format-call-check-for-vb2-is-busy

    When you request the buffers they will be allocated based on the current format.
    Changing the format later will mean a change in buffer size, but once the buffers
    are allocated that is locked in place. It's generally a bad idea to, say, increase
    the image size and then watch how DMA overwrites your memory :-)
    
    This is not strictly speaking a v4l limitation, but a limitation of almost all
    hardware. It is possible to allow format changes after reqbufs is called, but
    that generally requires that the buffers all have the maximum possible size
    which wastes a lot of memory. And in addition you would have to have some sort
    of metadata as part of the captured frame so you know the actual size of the
    image stored in the buffer.
    
    None of the drivers in the kernel support this, BTW.