如何从单个文件描述符分配多个 MMAP?
因此,对于我最后一年的项目,我使用 Video4Linux2 从摄像机中提取 YUV420 图像,将它们解析为 x264(本机使用这些图像),然后通过 Live555 将编码流发送到兼容 RTP/RTCP 的视频播放器通过无线网络在客户端上。所有这些我都试图实时完成,所以会有一个控制算法,但这不是这个问题的范围。所有这些(除了 Live555)都是用 C 编写的。目前,我的视频编码已接近尾声,但希望提高性能。
至少可以说,我遇到了障碍......我试图避免 V4L2 的用户空间指针并使用 mmap()。我正在编码视频,但由于它是 YUV420,我一直在分配新内存以将 Y'、U 和 V 平面保存在三个不同的变量中,以供 x264 读取。我想将这些变量保留为指向映射内存的指针。
然而,V4L2 设备有一个用于缓冲流的文件描述符,我需要将流分成三个符合 YUV420 标准的 mmap 变量,就像这样......
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));
其中“宽度”和“高度”是分辨率视频的大小(例如 640x480)。
据我了解... MMAP 寻找一个文件,有点像这样(伪代码):
fd = v4l2_open(...);
lseek(fd, buf.m.offset + (2 * width * height) / 3);
read(fd, buffers[n_buffers].u_plane, width * height / 6);
我的代码位于此处的 Launchpad Repo 中(了解更多背景): http://bazaar.launchpad.net/~alex-stevens/+junk /spyPanda/files(修订版11)
并且从这个Wiki插图中可以清楚地看到YUV420格式:http://en.wikipedia.org/wiki/File:Yuv420.svg (我本质上是想将 Y、U 和 V 字节分割到每个 mmap 的内存中)
有人愿意解释一种将三个变量从一个文件描述符映射到内存的方法,或者为什么我出错了?或者甚至暗示将 YUV420 缓冲区解析为 x264 的更好主意? :P
干杯! ^^
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! ^^
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不需要三个单独的
mmap
。只需mmap
一次,然后计算每个平面相对于整个映射的基指针的基指针。编辑:你需要这样的东西:
There is no need for three separate
mmap
s. Simplymmap
once, then compute the base pointer for each plane relative to the base pointer of the whole map.Edit: You need something like this:
如果我明白你想要什么:你不能将 mmap 'uninterleave' 顺序内存变成单独的指针。您必须映射单个内存块并手动计算缓冲区内的适当偏移量?
(但是:绝对没有理由不能多次映射同一个 fd。你从来没有说过出了什么问题。)
If I understood what you want: you can't make mmap 'uninterleave' sequential memory into separate pointers. You have to mmap a single memory block and manually calculate the appropriate offset within the buffer?
(But: there's absolutely NO REASON for not being able to mmap the same fd several times. You never said what went wrong.)