Получение ES_OUT_SET_ в cvlc при захвате h264 с использованием V4L2 в C ++ на raspberry-pi с использованием Logitech C920 - PullRequest
0 голосов
/ 23 июня 2019

Как правильно получить поток 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, но я вижу вход камеры в режиме реального времени ...

...