Как правильно получить поток H264 с веб-камеры Logitech C920, используя V4L2 в Raspberry-pi?
У меня есть веб-камера Logitech C920 и Raspberry-pi 3, модель B +.
Эта веб-камера имеет аппаратный кодек h264.Я обращаюсь к нему с помощью V4L2 c ++.
Я начал кодировать, создав некоторую оболочку для основных функций V4L2.
Думаю, проблема в реализации захвата.
Я попытался захватить кадры и распечатать на стандартный вывод и передать результат в cvlc.
Он замораживает изображение с камеры с более высоким FPS (24,30), но отлично работает с более низким FPS (5).
Некоторые методы:
void Device::setNumberOfInputBuffers(int count){
v4l2_requestbuffers bufrequest;
memset(&bufrequest, 0, sizeof(bufrequest));
bufrequest.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufrequest.memory = V4L2_MEMORY_MMAP;
bufrequest.count = count;
if(ioctl(fd, VIDIOC_REQBUFS, &bufrequest) < 0){
fprintf(stderr,"VIDIOC_REQBUFS: %s\n",strerror(errno));
exit(-1);
}
}
v4l2_buffer Device::getBufferInformationFromDevice(int bufferIndex) {
v4l2_buffer bufferinfo;
memset(&bufferinfo, 0, sizeof(bufferinfo));
bufferinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufferinfo.memory = V4L2_MEMORY_MMAP;
bufferinfo.index = bufferIndex;
if(ioctl(fd, VIDIOC_QUERYBUF, &bufferinfo) < 0){
fprintf(stderr,"VIDIOC_QUERYBUF ( bufferindex: %i): %s\n",bufferIndex,strerror(errno));
exit(-1);
}
return bufferinfo;
}
void* Device::getBufferPointer(const v4l2_buffer &bufferinfo) {
void* buffer_ptr = mmap(
NULL,
bufferinfo.length,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
bufferinfo.m.offset
);
if(buffer_ptr == MAP_FAILED){
fprintf(stderr,"mmap error.\n");
exit(-1);
}
return buffer_ptr;
}
void Device::queueBuffer(int bufferindex, v4l2_buffer *bufferinfo) {
memset(bufferinfo, 0, sizeof(v4l2_buffer));
bufferinfo->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufferinfo->memory = V4L2_MEMORY_MMAP;
bufferinfo->index = bufferindex;
if(ioctl(fd, VIDIOC_QBUF, bufferinfo) < 0){
fprintf(stderr,"VIDIOC_QBUF: %s\n",strerror(errno));
exit(-1);
}
}
void Device::dequeueBuffer(v4l2_buffer *bufferinfo){
memset(bufferinfo, 0, sizeof(v4l2_buffer));
bufferinfo->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufferinfo->memory = V4L2_MEMORY_MMAP;
if(ioctl(fd, VIDIOC_DQBUF, bufferinfo) < 0){
fprintf(stderr,"VIDIOC_DQBUF: %s\n",strerror(errno));
exit(-1);
}
}
main.cpp:
const int BUFFER_COUNT = 16; // max 32
device.setNumberOfInputBuffers(BUFFER_COUNT);
v4l2_buffer bufferInfo[BUFFER_COUNT];
void* bufferPtr[BUFFER_COUNT];
for(int i=0;i<BUFFER_COUNT;i++) {
bufferInfo[i] = device.getBufferInformationFromDevice(i);
bufferPtr[i] = device.getBufferPointer(bufferInfo[i]);
memset(bufferPtr[i], 0, bufferInfo[i].length);
device.queueBuffer(i, &bufferInfo[i]);
}
//main loop
device.streamON();
int fd_stdout = fileno(stdout);
v4l2_buffer bufferQueue;
while (!exit_requested){
device.dequeueBuffer(&bufferQueue);
//output to stdout
if (bufferQueue.bytesused > 0)
write(fd_stdout,bufferPtr[bufferQueue.index],bufferQueue.bytesused);
device.queueBuffer(bufferQueue.index, &bufferQueue);
}
device.streamOFF();
Когда я компилирую проект и запускаю, индекс приращения буфера в порядке.
Когда я выполняю команду ниже, я получаю правильный результат.
cvlc v4l2:///dev/video0:chroma=h264:width=320:height=240 --demux h264
Когда я выполняю команду ниже (с конвейером к cvlc)
./rpi-video | cvlc - --demux h264
Тогда я получаю ошибку посленесколько секунд:
[73900520] main input error: ES_OUT_SET_(GROUP_)PCR is called too late (pts_delay increased to 461 ms)
полный источник находится по этой ссылке
Еще один тест, который я сделал
Я прочитал вгде-то, что VLC не аппаратно ускоряется в RaspberryPi.
Поэтому я попытался найти другой способ визуализации кодировки, которую я прочитал изamera.
Я нашел это omxplayer .
Основная проблема этого плеера в том, что он не работает со стандартным вводом данных ... но я запустил его с помощью mkfifo каккод ниже показывает:
mkfifo h264.fifo
./rpi-video > h264.fifo & omxplayer --adev hdmi h264.fifo --video_queue 1 --threshold 1
Это не решает проблему с cvlc, но я вижу вход камеры в режиме реального времени ...