简体   繁体   中英

Saving a QImage from a memory buffer

Here is basically what I'm doing :

I have a video stream (YUV format). Each frame is extracted into a buffer ( frameBytes ). Later, this buffer is used to do the YUV->RGB conversion, then transfered in an IplImage . The IplImage is then transfered into a cv::Mat and displayed in an OpenGL context. Everything works fine.

What I would like to do is bypass the IplImage and cv::Mat section to directly work with the frameBytes buffer in OpenGL and do the conversion in the shaders.

This explaination is just for the context, since the problem I'm having is simpler.

To see if I can work with the buffer earlier, I try to copy it with memcpy and then save it in a QImage then in a file.

Here is my code for this part :

unsigned char *mycopy = new unsigned char[1920*1080*3];
memcpy(mycopy, frameBytes, sizeof(1920*1080*3));
QImage *img = new QImage(mycopy, 1920, 1080, QImage::Format_RGB888);
img->save("image.jpg",0,-1);

frameBytes contains the YUV data from the video stream. I know it's YUV and I'm trying to create a QImage with RGB888 format but since QImage doesn't support the format, I didn't make the conversion there, I thought it would still save an image but with the wrong colors so I don't care for the moment (Maybe this assumption is wrong ?).

Problem is, the image saved is black.

Just for more information, here is an example where I use frameBytes for the YUV->RGB conversion.

void DeckLinkCaptureDelegate::convertFrameToOpenCV(void* frameBytes, IplImage * m_RGB){
    if(!m_RGB)  m_RGB = cvCreateImage(cvSize(1920, 1080), IPL_DEPTH_8U, 3);


    unsigned char* pData = (unsigned char *) frameBytes;


    for(int i = 0, j=0; i < 1920 * 1080 * 3; i+=6, j+=4)
    {

        unsigned char u = pData[j];
        unsigned char y = pData[j+1];
        unsigned char v = pData[j+2];

        //fprintf(stderr, "%d\n", v);
        m_RGB->imageData[i+2] = 1.0*y + 8 + 1.402*(v-128);               // r
        m_RGB->imageData[i+1] = 1.0*y - 0.34413*(u-128) - 0.71414*(v-128);   // g
        m_RGB->imageData[i] = 1.0*y + 1.772*(u-128) + 0;                            // b

        y = pData[j+3];
        m_RGB->imageData[i+5] = 1.0*y + 8 + 1.402*(v-128);               // r
        m_RGB->imageData[i+4] = 1.0*y - 0.34413*(u-128) - 0.71414*(v-128);   // g
        m_RGB->imageData[i+3] = 1.0*y + 1.772*(u-128) + 0;
    }


}

Fixing the bug

You didn't copy all the data to your new buffer:

unsigned char *mycopy = new unsigned char[1920*1080*3];
memcpy(mycopy, frameBytes, sizeof(1920*1080*3));

That sizeof in there means that you're only copying an int -sized block, rather than 6MB. It looks like an accidental holdover from using a static array? Replace it with

const size_t bufsize = 1920*1080*3;
auto *mycopy = new unsigned char[bufsize];
memcpy(mycopy, frameBytes, bufsize);

A simpler approach

Alternatively, instead of doing the memory allocation yourself (and being responsible for delete[] ing it after the QImage is destructed), you could copy the image instead:

const unsigned char *bytes = frameBytes;
QImage img = QImage(bytes, 1920, 1080, QImage::Format_RGB888).copy();

The way this works is that we create a temporary QImage using frameBytes as its source (we pass it as pointer to const to insist it's read-only). We then copy() the whole of it to a new QImage , throwing away the temporary. The copy() does something similar to your code above, but we're now saved from having to do the calculations, eliminating some of the consequent potential for error.

Note also that I prefer to pass QImage by value. Although this might seem inefficient, most (copyable) Qt types are designed as reference-counted copy-on-write structures, and can be safely used this way, eliminating another class of errors (memory management). This is true of Qt's collection types, too, and very useful.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM