Wednesday, October 3, 2012

Video to Texture Streaming (Part 3) - i.MX6 processor

Hi There Again, sorry for this long time without posting anything, I have being running out of time to deal with cool stuffs (unfortunately), but I have something nice to share.
Continuing with the video to texture streaming with the i.MX6 processors, we saw so far how to decode the video file, now we need to write the data fast as possible into the GPU buffer in order to get a good frame rate of our texture even when using high resolution media.

In order to do that, we have an API that will make our job easier as possible, and the main functions of this API are:

1 - GL_API GL_APIENTRY glTexDirectVIV (GLenum Target, GLsizei Width, GLsizei Height, GLenum Format, GLvoid **Pixels);

2 - GL_API GL_APIENTRY glTexDirectVIVMAP (GLenum Target, GLsizei Width, GLsizei Height, GLenum Format, GLvoid **Logical, Const GLuint *Physical);

3 - GL_API GL_APIENTRY glTexDirectInvalidateVIV (GLenum Target);

what are all those parameters ???

Answer:
1 - Target, Width, Height and Format have the same meaning with glTexImage2D. Width alighment by 16 pixels is required. Example:
Target: GL_TEXTURE_2D Width: 640 Height: 480 Format: GL_VIV_YV12, GL_VIV_NV12, GL_VIV_YUY2, GL_VIV_UYVY, GL_VIV_NV21

2 - Pixels (first function) is the pointer created by the driver, which means that any data you write using this pointer you are going to write directly to the GPU buffer.

3 - Logical (MAP function), is a pointer to the logical address of the application-defined buffer to the texture.

4 - Physical (MAP function), is a pointer to the physial address of the application-defined buffer to the texture, of ~0 if no physical address has been provided.

Alright, we have all the parameters and its description, so, how do we use these functions?

First of all, we need to declare our pointers and then call the function and let the driver allocate memory to us:

GLvoid *pTexel;

The second step is to use the API and get our pointer pointing to the GPU buffer:

glTexDirectVIV (GL_TEXTURE_2D, width, height, GL_VIV_YV12, &pTexel);
GLint error = glGetError ();
if (error != GL_NO_ERROR)
{
     printf ("\nError, glTexDirectVIV 0x%08x\n", error)
}

This function should be called just once in your code! (this was my mistake for a long time.....)

Now, somewhere in your code (in a loop function), you can use the following code to write the data:

glBindTexture (GL_TEXTURE_2D, texture);
memmove (pTexel, my_texture_data, w * h * 3/2);
glTexDirectInvalidateVIV (GL_TEXTURE_2D);

This is not fully optmized yet, if you check this post, you are going to see that we are already performing a memmove to copy the frame data into our global buffer. You can play with this code and remove one of these memmoves.

Also, the Gstreamer code is capturing the frame in RGB format, and you will need YUV format, you can change the caps format to:

// RGB
//gst_element_link_filtered (pFfConv, __videosink, gst_caps_new_simple ("video/x-raw-rgb","bpp",G_TYPE_INT,16, NULL));

// YUV12
gst_element_link_filtered (pFfConv, __videosink, gst_caps_new_simple ("video/x-raw-yuv", "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('Y', 'V', '1', '2'), NULL));

The full application can be downlodaded here.

EOF !