Использование QAbstractVideoSurface
Я хочу сделать приложение для видеоконференций с помощью QT. Я новичок в этом. Буду признателен, если у кого-нибудь есть пример этого.
Теперь я пытаюсь отобразить изображение с камеры на экране, используя подкласс qabstractvideosurface. У кого-нибудь есть идеи, как это сделать?
1 ответ
QAbstractVideoSurface
является интерфейсом между производителем и потребителем видеокадров. Для начала вам нужно реализовать только две функции:
- supportPixelFormats, чтобы производитель мог выбрать подходящий формат для
QVideoFrame
- подарок, который является более общей формулировкой для показа \ отображения этого кадра
Допустим, вы хотите использовать классический 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;
}
}
Этот пример явно не оптимален.
- Это не берет деньги на тот факт, что
QVideoFrame
может храниться в видеопамяти, потому что мы рисуем с использованием растрового изображения. - Преобразование из изображения в растровое изображение является ненужным хитом.
Вы можете написать свой собственный виджет и реализовать paintEvent для лучшей производительности. Кроме того, у вас есть несколько свобод дизайна present()
вести себя. Например:
- Является ли неблокирующая поверхность, то есть рамка уже показана, когда заканчивается. Выше это будет означать использование
mylabel->repaint()
вместоmylabel->update()
- Что происходит, когда вы не можете завершить презентацию. Вы можете нарисовать пустую рамку, а не возвращать ошибку, которая может остановить музыку.