Использование QAbstractVideoSurface

Я хочу сделать приложение для видеоконференций с помощью QT. Я новичок в этом. Буду признателен, если у кого-нибудь есть пример этого.

Теперь я пытаюсь отобразить изображение с камеры на экране, используя подкласс qabstractvideosurface. У кого-нибудь есть идеи, как это сделать?

1 ответ

Решение

QAbstractVideoSurface является интерфейсом между производителем и потребителем видеокадров. Для начала вам нужно реализовать только две функции:

  1. supportPixelFormats, чтобы производитель мог выбрать подходящий формат для QVideoFrame
  2. подарок, который является более общей формулировкой для показа \ отображения этого кадра

Допустим, вы хотите использовать классический QWidget для отображения. В этом случае вы можете использовать QImage рисовать на виджете.

Первый Qt гарантированно нарисовать QImage который является RGB24 (или BGR24) на большинстве платформ. Так

QList<QVideoFrame::PixelFormat> LabelBasedVideoSurface::supportedPixelFormats(
        QAbstractVideoBuffer::HandleType handleType) const
{
    if (handleType == QAbstractVideoBuffer::NoHandle) {
        return QList<QVideoFrame::PixelFormat>()
                << QVideoFrame::Format_RGB24;
    } else {
        return QList<QVideoFrame::PixelFormat>();
    }
}

Теперь, чтобы представить QVideoFrame, вы отображаете его данные в QImage и рисуете QImage для виджета. Для простоты я буду использовать QLabel, что я получаю доступ напрямую (нет сигнала нет слота).

bool LabelBasedVideoSurface::present(const QVideoFrame &frame)
{
    if (notMyFormat(frame.pixelFormat())) {
        setError(IncorrectFormatError);
        return false;
    } else {

        QVideoFrame frametodraw(frame);

        if(!frametodraw.map(QAbstractVideoBuffer::ReadOnly))
        {
           setError(ResourceError);
           return false;
        } 

         //this is a shallow operation. it just refer the frame buffer
         QImage image(
                frametodraw.bits(),
                frametodraw.width(),
                frametodraw.height(),
                frametodraw.bytesPerLine(),
                QImage::Format_RGB444);

        mylabel->resize(image.size());

        //QPixmap::fromImage create a new buffer for the pixmap
        mylabel->setPixmap(QPixmap::fromImage(image));

        //we can release the data
        frametodraw.unmap();

        mylabel->update();

        return true;
    }
}

Этот пример явно не оптимален.

  1. Это не берет деньги на тот факт, что QVideoFrame может храниться в видеопамяти, потому что мы рисуем с использованием растрового изображения.
  2. Преобразование из изображения в растровое изображение является ненужным хитом.

Вы можете написать свой собственный виджет и реализовать paintEvent для лучшей производительности. Кроме того, у вас есть несколько свобод дизайна present() вести себя. Например:

  • Является ли неблокирующая поверхность, то есть рамка уже показана, когда заканчивается. Выше это будет означать использование mylabel->repaint() вместо mylabel->update()
  • Что происходит, когда вы не можете завершить презентацию. Вы можете нарисовать пустую рамку, а не возвращать ошибку, которая может остановить музыку.
Другие вопросы по тегам