0

The task is to copy a frame from a QVideoFrame, and possibly do something to that Image and displaying the manipulated Image in QML.

...

m_lastFrame = QImage(videoFrame.width(), videoFrame.height(), QImage::Format_ARGB32);
memcpy(m_lastFrame.bits(), videoFrame.bits(),videoFrame.mappedBytes());

...

The above code causes a crash, since m_lastFrame is short of 32 bytes(3686400 vs 3686432) videoFrame.mappedBytes() reports 3686432 bytes. What am I doing wrong here? Or how should I calculate the size of m_lastFrame().

The code is running on Mac OSx 10.9.5 Qt 5.1.1.

Some additional code:

... if( videoFrame.map(QAbstractVideoBuffer::ReadOnly) ){

    m_lastFrame = QImage(videoFrame.width(),videoFrame.height(),QImage::Format_ARGB32);
    memcpy(m_lastFrame.bits(), videoFrame.bits(),videoFrame.mappedBytes() - 32);

    ...

} ...

  • Have you called `videoFrame.map(QAbstractVideoBuffer::ReadOnly)` and checked the return value? Are you certain that the video frame contains ARGB32 data? – njahnke Dec 04 '14 at 16:15
  • Are you successfully mapping (with a call to `map()`) the contents of the video frame to system memory before calling `videoFrame.bits()` ? In that case I think your problem should be solved by properly converting from the pixel format to the image format. – mhcuervo Dec 04 '14 at 16:21
  • Yes @njahnke. I am calling map() according to the above
    – Peter Winzell Dec 05 '14 at 10:42
  • Ok, @mhcuervo. Thank you both for your helpful comments I checked the format and it is using the right format. I will run this code on a pc and see what the result is. – Peter Winzell Dec 05 '14 at 11:09
  • Tested on Windows 8 with Qt 5.3.2. 3686400bytes is returned from both functions. Thus, seems to be a problem on the MAC. However, other issues were found on the PC the frame returned is upside down, and the RGB32 Image just renders a white frame. Converting to ARGB_32 and the image is rendered. Next step will be to take some logs to investigate actual pixel values. The idea is to use this on several platforms, so far the Qt fw don't seem to deliver a good cross-platform functionality. – Peter Winzell Dec 11 '14 at 13:17

2 Answers2

1

Since that doesn't always work, see also comment at convert QVideoFrame to QImage , i.e.

QImage Camera::imageFromVideoFrame(const QVideoFrame& buffer) const
{
    QImage img;
    QVideoFrame frame(buffer);  // make a copy we can call map (non-const) on
    frame.map(QAbstractVideoBuffer::ReadOnly);
    QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(
                frame.pixelFormat());
    // BUT the frame.pixelFormat() is QVideoFrame::Format_Jpeg, and this is
    // mapped to QImage::Format_Invalid by
    // QVideoFrame::imageFormatFromPixelFormat
    if (imageFormat != QImage::Format_Invalid) {
        img = QImage(frame.bits(),
                     frame.width(),
                     frame.height(),
                     // frame.bytesPerLine(),
                     imageFormat);
    } else {
        // e.g. JPEG
        int nbytes = frame.mappedBytes();
        img = QImage::fromData(frame.bits(), nbytes);
    }
    frame.unmap();
    return img;
}
Community
  • 1
  • 1
Rudolf Cardinal
  • 738
  • 8
  • 11
0

You can try creating a QImage by first mapping the QVideoFrame onto a QAbstractVideoBuffer in the following way :

bool CameraFrameGrabber::present(const QVideoFrame &frame)
{
Q_UNUSED(frame);
if (frame.isValid()) {
    QVideoFrame cloneFrame(frame);
    cloneFrame.map(QAbstractVideoBuffer::ReadOnly);
    const QImage image(cloneFrame.bits(),
                       cloneFrame.width(),
                       cloneFrame.height(),
                      QVideoFrame::imageFormatFromPixelFormat(cloneFrame .pixelFormat()));


    emit frameAvailable(image);
    qDebug()<<cloneFrame.mappedBytes();
    cloneFrame.unmap();
    return true;
}

If you want QImage in any other format just change the last parameter during creating the image, to the whichever format you like :

QImage::Format_xxx ;

instead of

QVideoFrame::imageFormatFromPixelFormat(cloneFrame .pixelFormat()));

Alok
  • 163
  • 1
  • 14
  • 1
    You cannot just specify a format you like. It has to be the format of the data you provide, hence `QVideoFrame::imageFormatFromPixelFormat` is required. – Filip Hazubski Jul 13 '17 at 08:34