使 QGraphicsVideoItem 填充 QWidget
Make QGraphicsVideoItem Fill QWidget
我的目标是创建一个简单的视频播放器 QWidget
,允许一些重叠的图形(考虑字幕或类似内容)。
我从天真的方法开始,即使用 QVideoWidget
和另一组 QWidget
在顶部(我的叠加层)。不幸的是,这不起作用,因为 Qt 不允许具有透明背景的小部件呈现在视频之上。背景显示为黑色而不是实际视频。
下一个想法是使用 QGraphicsScene
等。这应该允许这种合成,所以我创建了一个像这样的简单设置:
// The widget we will use as viewport
auto viewport= new QWidget();
//Set an easily recognizable bg color for debugging
palette.setColor(QPalette::Window, Qt::green);
viewport->setPalette(palette);
viewport->setAutoFillBackground(true);
// Our scene
auto mScene=new QGraphicsScene(this);
// The video
auto mVideoItem = new QGraphicsVideoItem();
mVideoItem->setPos(0,0);
myVideoSource.setVideoOutput(mVideoItem); // ... not shown: setting up of the video source
mScene->addItem(mVideoItem);
// Yellow line starting at 0,0 for debugging
auto line=new QGraphicsLineItem (0,0,100,100);
line->setPos(0,0);
line->setPen(QPen(Qt::yellow, 2));
mScene->addItem(line);
// A Text string
auto text=new QGraphicsTextItem("Its Wednesday my dudes", mVideoItem);
text->setPos(10, 10);
// Our view
mView=new QGraphicsView;
mView->setScene(mScene);
mView->setViewport(viewport);
viewport->show()
现在这看起来很有希望,因为我可以看到合成作品;线条和文字完美地呈现在视频之上。但是,视频位于小部件中看似随机的位置。 (见截图)
至此我已经尝试了所有可以想到的和不可思议的组合
mVideoItem->setSize();
mVideoItem->setOffset();
mScene->setSceneRect();
mView->fitInView();
mView->ensureVisible();
mView->centerOn()
尝试用视频项目填充视口小部件,但似乎完全不符合逻辑。它没有将内容居中,而是以违反逻辑的方式在屏幕上飞来飞去,我已经放弃了。我将我的代码放在视口小部件的 resizeEvent 中,并使用视口小部件的 size() 作为基础。
所以我的问题是; 如何在调整大小时用视频项目填充视口小部件?
我认为 QGraphicsVideoItem
不适合这项任务。
您可以实施 QAbstractVideoSurface
来接收 QVideoFrame
并将它们提供给 QWidget
,然后将它们转换为 QImage
,然后在 paintEvent
中缩放和绘制它们.由于您控制 paintEvent
,您可以在视频上绘制任何内容,并免费获得“填充视口”功能。
要点:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Surface surface;
Widget widget(surface);
widget.show();
QMediaPlayer player;
player.setVideoOutput(&surface);
player.setMedia(QMediaContent(QUrl("path/to/media")));
player.play();
return a.exec();
}
bool Surface::present(const QVideoFrame &frame)
{
mFrame = frame;
emit frameReceived();
return true;
}
Widget::Widget(Surface &surface, QWidget *parent)
: QWidget{parent}, mSurface(surface)
{
connect(&mSurface,SIGNAL(frameReceived()),this,SLOT(update()));
}
void Widget::paintEvent(QPaintEvent *event)
{
QVideoFrame frame = mSurface.frame();
if (frame.map(QAbstractVideoBuffer::ReadOnly)) {
QPainter painter(this);
int imageWidth = mSurface.imageSize().width();
int imageHeight = mSurface.imageSize().height();
auto image = QImage(frame.bits(),
imageWidth,
imageHeight,
mSurface.imageFormat());
double scale1 = (double) width() / imageWidth;
double scale2 = (double) height() / imageHeight;
double scale = std::min(scale1, scale2);
QTransform transform;
transform.translate(width() / 2.0, height() / 2.0);
transform.scale(scale, scale);
transform.translate(-imageWidth / 2.0, -imageHeight / 2.0);
painter.setTransform(transform);
painter.drawImage(QPoint(0,0), image);
painter.setTransform(QTransform());
painter.setFont(QFont("Arial", 20));
int fontHeight = painter.fontMetrics().height();
int ypos = height() - (height() - imageHeight * scale) / 2 - fontHeight;
QRectF textRect(QPoint(0, ypos), QSize(width(), fontHeight));
QTextOption opt(Qt::AlignCenter);
painter.setPen(Qt::blue);
painter.drawText(textRect, "Subtitles sample", opt);
frame.unmap();
}
}
完整来源:draw-over-video
基于 Qt 的 customvideosurface example。
我的目标是创建一个简单的视频播放器 QWidget
,允许一些重叠的图形(考虑字幕或类似内容)。
我从天真的方法开始,即使用 QVideoWidget
和另一组 QWidget
在顶部(我的叠加层)。不幸的是,这不起作用,因为 Qt 不允许具有透明背景的小部件呈现在视频之上。背景显示为黑色而不是实际视频。
下一个想法是使用 QGraphicsScene
等。这应该允许这种合成,所以我创建了一个像这样的简单设置:
// The widget we will use as viewport
auto viewport= new QWidget();
//Set an easily recognizable bg color for debugging
palette.setColor(QPalette::Window, Qt::green);
viewport->setPalette(palette);
viewport->setAutoFillBackground(true);
// Our scene
auto mScene=new QGraphicsScene(this);
// The video
auto mVideoItem = new QGraphicsVideoItem();
mVideoItem->setPos(0,0);
myVideoSource.setVideoOutput(mVideoItem); // ... not shown: setting up of the video source
mScene->addItem(mVideoItem);
// Yellow line starting at 0,0 for debugging
auto line=new QGraphicsLineItem (0,0,100,100);
line->setPos(0,0);
line->setPen(QPen(Qt::yellow, 2));
mScene->addItem(line);
// A Text string
auto text=new QGraphicsTextItem("Its Wednesday my dudes", mVideoItem);
text->setPos(10, 10);
// Our view
mView=new QGraphicsView;
mView->setScene(mScene);
mView->setViewport(viewport);
viewport->show()
现在这看起来很有希望,因为我可以看到合成作品;线条和文字完美地呈现在视频之上。但是,视频位于小部件中看似随机的位置。 (见截图)
至此我已经尝试了所有可以想到的和不可思议的组合
mVideoItem->setSize();
mVideoItem->setOffset();
mScene->setSceneRect();
mView->fitInView();
mView->ensureVisible();
mView->centerOn()
尝试用视频项目填充视口小部件,但似乎完全不符合逻辑。它没有将内容居中,而是以违反逻辑的方式在屏幕上飞来飞去,我已经放弃了。我将我的代码放在视口小部件的 resizeEvent 中,并使用视口小部件的 size() 作为基础。
所以我的问题是; 如何在调整大小时用视频项目填充视口小部件?
我认为 QGraphicsVideoItem
不适合这项任务。
您可以实施 QAbstractVideoSurface
来接收 QVideoFrame
并将它们提供给 QWidget
,然后将它们转换为 QImage
,然后在 paintEvent
中缩放和绘制它们.由于您控制 paintEvent
,您可以在视频上绘制任何内容,并免费获得“填充视口”功能。
要点:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Surface surface;
Widget widget(surface);
widget.show();
QMediaPlayer player;
player.setVideoOutput(&surface);
player.setMedia(QMediaContent(QUrl("path/to/media")));
player.play();
return a.exec();
}
bool Surface::present(const QVideoFrame &frame)
{
mFrame = frame;
emit frameReceived();
return true;
}
Widget::Widget(Surface &surface, QWidget *parent)
: QWidget{parent}, mSurface(surface)
{
connect(&mSurface,SIGNAL(frameReceived()),this,SLOT(update()));
}
void Widget::paintEvent(QPaintEvent *event)
{
QVideoFrame frame = mSurface.frame();
if (frame.map(QAbstractVideoBuffer::ReadOnly)) {
QPainter painter(this);
int imageWidth = mSurface.imageSize().width();
int imageHeight = mSurface.imageSize().height();
auto image = QImage(frame.bits(),
imageWidth,
imageHeight,
mSurface.imageFormat());
double scale1 = (double) width() / imageWidth;
double scale2 = (double) height() / imageHeight;
double scale = std::min(scale1, scale2);
QTransform transform;
transform.translate(width() / 2.0, height() / 2.0);
transform.scale(scale, scale);
transform.translate(-imageWidth / 2.0, -imageHeight / 2.0);
painter.setTransform(transform);
painter.drawImage(QPoint(0,0), image);
painter.setTransform(QTransform());
painter.setFont(QFont("Arial", 20));
int fontHeight = painter.fontMetrics().height();
int ypos = height() - (height() - imageHeight * scale) / 2 - fontHeight;
QRectF textRect(QPoint(0, ypos), QSize(width(), fontHeight));
QTextOption opt(Qt::AlignCenter);
painter.setPen(Qt::blue);
painter.drawText(textRect, "Subtitles sample", opt);
frame.unmap();
}
}
完整来源:draw-over-video
基于 Qt 的 customvideosurface example。