【问题标题】:Convert QVideoFrame straight to QPixmap将 QVideoFrame 直接转换为 QPixmap
【发布时间】:2014-11-15 11:30:44
【问题描述】:

我使用QVideoProbe 访问相机帧。我的平台是安卓。 我已将每个相机帧转换为QImage,然后像素映射并显示在QLabel 上。 我的问题是这个过程很慢。 帧显示非常缓慢。 我可以将QVideoFrame 直接转换为QPixmap 或其他更快的方式来显示相机帧吗? 这是我的代码:

    QCamera *camera = new QCamera(this);

    camera->setCaptureMode(QCamera::CaptureViewfinder);

    QVideoProbe *videoProbe = new QVideoProbe(this);

    bool ret = videoProbe->setSource(camera);
    qDebug() <<"videoProbe->setSource(camera):" << ret;

    if (ret) {
          connect(videoProbe, SIGNAL(videoFrameProbed(const QVideoFrame &)),
                this, SLOT(present(const QVideoFrame &)));

    }

    camera->start();
...
...


bool MainWindow::present(const QVideoFrame &frame)
{
    qDebug() <<"counter:" << ++counter;

    QVideoFrame cloneFrame(frame);
    if(cloneFrame.map(QAbstractVideoBuffer::ReadOnly))
    {
        QImage img(
                cloneFrame.size(), QImage::Format_ARGB32);
                qt_convert_NV21_to_ARGB32(cloneFrame.bits(),
                (quint32 *)img.bits(),
                cloneFrame.width(),
                cloneFrame.height());

        label->setPixmap(QPixmap::fromImage(img));

        cloneFrame.unmap();
    }

    return true;
}

【问题讨论】:

  • 图片的分辨率是多少?你是在安卓上做的吗?
  • 感谢您的回复。是的,我在安卓上做。 img 大小为:QSize(640, 480)
  • 我使用了 QPainter 并通过了 QImage / OPixmap 并使用了painter.drawImage 和painter.drawPixmap。但是在 QPainter 中静止的相机帧显示非常缓慢。
  • 我没有使用Qt的实现,而是使用andrechen/yuv2rgb将NV12转换为QImage。但是,转换仍然使用大量 CPU,并且对于实时流式传输来说不够快。
  • 认为您需要视频播放器小部件而不是 QLabel。

标签: android qt camera qpixmap


【解决方案1】:

1. 要将视频帧转换为 QImage,我使用 qt 内部方法:

//Somewhere before using
extern QImage qt_imageFromVideoFrame(const QVideoFrame &f);
    ...
//using
QImage imgbuf=qt_imageFromVideoFrame(frame);
  1. 您需要跳过一些帧,只显示一些。它将允许您以最大可能的速度处理流。我用以下代码做到这一点:

    void MyVideoHandler::videoFrameProbed(const QVideoFrame &frame)
    {
        if(!started)
            return;
        if(!frameProcessor)
            return;
        if(m_isBusy)
        {
            //qDebug() << "Video frame dropped";
            return;
        }
        m_isBusy = true;
        qDebug() << "videoFrameProbed";
        QMetaObject::invokeMethod(frameProcessor, "processFrame", Qt::QueuedConnection,
            Q_ARG(QVideoFrame, frame),
            Q_ARG(bool, param1),
            Q_ARG(bool, param2),
            Q_ARG(bool, param3),
            Q_ARG(bool, param4));
        //qDebug() << "processFrame invoked";
    }
    

我通过 invokeMethod 调用它只是因为 frameProcessor 存在于不同的线程中,但这不是你的情况,因为你需要在 UI 线程中显示它。另一方面,你可以在线程中转换为 QImage(或 QPixmap)然后将结果发送到 UI 线程。所以这里是如何做到这一点的代码:

frameProcessor=new MyVideoFrameProcessor();
frameProcessor->moveToThread(&videoStreamThread);

啊,我也必须说 MyVideoFrameProcessor 在完成处理时生成事件,而 MyVideoHandler 将 m_isBusy 切换为 false。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-01
    • 2017-12-14
    • 1970-01-01
    相关资源
    最近更新 更多