Отображение на экране с помощью QAbstractVideoSurface

Я пытаюсь отобразить изображение с камеры на экране, используя подкласс QAbstractVideoSurface, и у меня нет в этом опыта.

Буду признателен, если кто-нибудь объяснит, как это сделать.


person lionlinekz    schedule 07.10.2014    source источник
comment
Хороший вопрос должен указывать на некоторый уровень исследования... Например, пытались ли вы искать какую-либо связанную документацию? В том виде, в каком он сформулирован, вопрос кажется очень открытым.   -  person Vikas Gupta    schedule 07.10.2014
comment
да, уже месяц мучаюсь. Я использовал видоискатель камеры, который отображает только то, что видит камера. Чтобы получить видеокадры, я, вероятно, должен использовать метод, упомянутый выше. Но в Интернете не хватает примеров, которые я мог бы попробовать. спасибо за ваш комментарий, это был мой первый вопрос, поэтому, пожалуйста, не будьте слишком строги   -  person lionlinekz    schedule 07.10.2014
comment
@lionlinekz вы боретесь с реализацией подкласса или с тем, как использовать объект VideoSurface?   -  person UmNyobe    schedule 07.10.2014
comment
насколько я понимаю, для получения кадров нужен субласс. Что мне непонятно, так это отображение видео на экране.   -  person lionlinekz    schedule 07.10.2014


Ответы (1)


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

  1. supportedPixelFormats, чтобы производитель мог выбрать подходящий формат для 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()
  • Что происходит, когда вы не можете завершить презентацию. Вы можете захотеть нарисовать пустой кадр, а не возвращать ошибку, которая может остановить музыку.
person UmNyobe    schedule 07.10.2014
comment
большое спасибо, это мне очень помогло! Однако изображение, отображаемое на дисплее, зелено-пурпурное, есть предложения, как это исправить? - person lionlinekz; 08.10.2014
comment
QVideoFrame::Format_RGB24 может быть QVideoFrame::Format_BGR24. Поиграйте с различными форматами rgb, чтобы они соответствовали вашему источнику. - person UmNyobe; 08.10.2014
comment
Что будет вызывать present()? Я добавил этот класс в свой QtMediaPlayer, но QtMediaPlayer никогда не будет вызывать present(). - person Guerlando OCs; 13.02.2019