Как бы я назначил несколько MMAP из одного файлового дескриптора? - PullRequest
3 голосов
/ 09 июня 2011

Итак, для моего проекта на последний год я использую Video4Linux2, чтобы извлекать изображения YUV420 с камеры, анализировать их до x264 (который использует эти изображения изначально), а затем отправлять закодированный поток через Live555 на RTP / RTCPсовместимый видеоплеер на клиенте по беспроводной сети.Все это я пытаюсь сделать в режиме реального времени, поэтому будет алгоритм управления, но это не является предметом этого вопроса.Все это, за исключением Live555, пишется на C. В настоящее время я близок к завершению кодирования видео, но хочу улучшить производительность.

По меньшей мере, я столкнулся с проблемой... Я пытаюсь избежать указателей пространства пользователя для V4L2 и использовать mmap ().Я кодирую видео, но так как это YUV420, я malloc'ing новую память для хранения плоскостей Y ', U и V в трех различных переменных для x264 для чтения.Я хотел бы сохранить эти переменные как указатели на часть памяти mmap.

Однако устройство V4L2 имеет один дескриптор файла для буферизованного потока, и мне нужно разделить поток на три mmap 'переменные ed, соответствующие стандарту YUV420, вот так ...

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);

Мой код находится в репозитории панели запуска здесь (для дополнительной информации): http://bazaar.launchpad.net/~alex-stevens/+junk/spyPanda/files (Редакция 11)

И формат YUV420 хорошо виден из этой иллюстрации в вики: http://en.wikipedia.org/wiki/File:Yuv420.svg (я хочу разделить байты Y, U и V на каждый mmap'edпамять)

Кто-нибудь хочет объяснить способ преобразования трех переменных памяти в один дескриптор файла или почему я ошибся?Или даже намекнуть на лучшую идею для разбора буфера YUV420 на x264?: P

Ура!^^

Ответы [ 2 ]

3 голосов
/ 09 июня 2011

Нет необходимости в трех отдельных mmap с. Просто mmap один раз, затем вычислите базовый указатель для каждой плоскости относительно базового указателя всей карты.

Редактировать: Вам нужно что-то вроде этого:

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;
1 голос
/ 09 июня 2011

Если я понял, что вы хотите: вы не можете превратить последовательную память mmap в «uninterleave» в отдельные указатели.Вы должны отобразить один блок памяти и вручную вычислить соответствующее смещение в буфере?

(Но: абсолютно НЕТ ПРИЧИНЫ, чтобы не иметь возможность отображать один и тот же fd несколько раз. Вы никогда не говорили, что пошло не так.)

...