Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How would I assign multiple MMAP's from single file descriptor?

So, for my final year project, I'm using Video4Linux2 to pull YUV420 images from a camera, parse them through to x264 (which uses these images natively), and then send the encoded stream via Live555 to an RTP/RTCP compliant video player on a client over a wireless network. All of this I'm trying to do in real-time, so there'll be a control algorithm, but that's not the scope of this question. All of this - except Live555 - is being written in C. Currently, I'm near the end of encoding the video, but want to improve performance.

To say the least, I've hit a snag... I'm trying to avoid User Space Pointers for V4L2 and use mmap(). I'm encoding video, but since it's YUV420, I've been malloc'ing new memory to hold the Y', U and V planes in three different variables for x264 to read upon. I would like to keep these variables as pointers to an mmap'ed piece of memory.

However, the V4L2 device has one single file descriptor for the buffered stream, and I need to split the stream into three mmap'ed variables adhering to the YUV420 standard, like so...

buffers[n_buffers].y_plane = mmap(NULL, (2 * width * height) / 3,
                                    PROT_READ | PROT_WRITE, MAP_SHARED,
                                    fd, buf.m.offset);
buffers[n_buffers].u_plane = mmap(NULL, width * height / 6,
                                    PROT_READ | PROT_WRITE, MAP_SHARED,
                                    fd, buf.m.offset +
                                    ((2 * width * height) / 3 + 1) /
                                    sysconf(_SC_PAGE_SIZE));
buffers[n_buffers].v_plane = mmap(NULL, width * height / 6,
                                    PROT_READ | PROT_WRITE, MAP_SHARED,
                                    fd, buf.m.offset +
                                    ((2 * width * height) / 3 + 
                                    width * height / 6 + 1) / 
                                    sysconf(_SC_PAGE_SIZE));

Where "width" and "height" is the resolution of the video (eg. 640x480).

From what I understand... MMAP seeks through a file, kind of like this (pseudoish-code):

fd = v4l2_open(...);
lseek(fd, buf.m.offset + (2 * width * height) / 3);
read(fd, buffers[n_buffers].u_plane, width * height / 6);

My code is located in a Launchpad Repo here (for more background): http://bazaar.launchpad.net/~alex-stevens/+junk/spyPanda/files (Revision 11)

And the YUV420 format can be seen clearly from this Wiki illustration: http://en.wikipedia.org/wiki/File:Yuv420.svg (I essentially want to split up the Y, U, and V bytes into each mmap'ed memory)

Anyone care to explain a way to mmap three variables to memory from the one file descriptor, or why I went wrong? Or even hint at a better idea to parse the YUV420 buffer to x264? :P

Cheers! ^^

like image 571
Alex Stevens Avatar asked Jan 18 '26 09:01

Alex Stevens


1 Answers

There is no need for three separate mmaps. Simply mmap once, then compute the base pointer for each plane relative to the base pointer of the whole map.

Edit: You need something like this:

unsigned char *y = mmap(...); /* map total size of all 3 planes */
unsigned char *u = y + y_height*y_bytes_per_line;
unsigned char *v = u + u_height*u_bytes_per_line;
like image 153
R.. GitHub STOP HELPING ICE Avatar answered Jan 20 '26 02:01

R.. GitHub STOP HELPING ICE



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!