Отображение видео с альфа-каналом с использованием qt - PullRequest
0 голосов
/ 27 января 2020

Мне нужно отобразить видео в кодировке RGBA (то есть видео с прозрачным фоном), используя qt. Идея состоит в том, чтобы объединить видео в реальном времени. Я обычно использую libmpv, но он не позволяет рендерить прозрачный фон видео. Я пытаюсь использовать QMediaPlayer со следующим кодом:

 QMainWindow w;
 w.resize(1920,1080);
 QVideoWidget videoWidget(&w);
 videoWidget.move(0,100);
 videoWidget.resize(1920,1080);
 QMediaPlayer *player = new QMediaPlayer(&w);
 w.resize(w.size());
 player->setMedia( QUrl::fromLocalFile(PATH+"video2.mov") );
 player->setVideoOutput(&videoWidget);
 w.show();
 player->play();

Это успешно загружает видео (которое является MOV-видео RGBA), но заполняет виджет видео черным фоном, где он должен быть прозрачным, таким образом покрывая любой элемент за видеоплеером.

Есть ли способ фактически загрузить прозрачное видео, используя QVideoPlayer / QVideoWidget? Если нет, есть ли эффективная альтернатива (я бы не стал использовать решение более низкого уровня, такое как opencv).

Большое спасибо,

Фред

1 Ответ

0 голосов
/ 14 февраля 2020

вот решение, которое я наконец нашел:

Подкласс QAbstractVideoSurface:

class alphaVideoDrawer : public QAbstractVideoSurface
{
    Q_OBJECT
public:
    alphaVideoDrawer(QLabel *displayLbl);
private:
    QLabel *displayLbl;

protected:
    bool present(const QVideoFrame &frame);

    QList<QVideoFrame::PixelFormat> supportedPixelFormats(
            QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const
    {
        Q_UNUSED(handleType);
        return QList<QVideoFrame::PixelFormat>() << QVideoFrame::Format_ARGB32;
    }
};

Поверхность получит преобразование кадра и отправит его в qlabel, который отображает видео.

alphaVideoDrawer::alphaVideoDrawer(QLabel *displayLbl):displayLbl(displayLbl)
{
}

extern QImage qt_imageFromVideoFrame(const QVideoFrame &f);


bool alphaVideoDrawer::present(const QVideoFrame &frame)
{
    QImage image = qt_imageFromVideoFrame(frame);
    displayLbl->setPixmap(QPixmap::fromImage(image));
    return true;
}

Затем мы подклассируем QLabel, который будет нашим видеовыходом:

class alphaVideo : public QLabel
{
    Q_OBJECT
public:
    alphaVideo(QLabel *parent = nullptr);

private:
    alphaVideoDrawer *videoDrawer;
    QMediaPlayer *videoPlayer;
    QMediaPlaylist *playlist;
};

Он загружает кассету и проигрыватель и начинает воспроизведение / рендеринг видео:

    alphaVideo::alphaVideo(QLabel *parent): QLabel(parent)
{
    setStyleSheet("QLabel { background-color : transparent; }");
    videoDrawer = new alphaVideoDrawer(this);
    videoPlayer = new QMediaPlayer(this);
    playlist = new QmediaPlaylist();
    videoPlayer->setPlaylist(playlist);
    videoPlayer->setVideoOutput(videoDrawer);
    playlist->addMedia( Qurl::fromLocalFile(“your RGBA video file.mp4”) );
    videoPlayer->play();
}
...