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;
}
}
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);
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.