I try to create video AVI format from ID3D11Texture2D by using OpenCV.
Step 1
I transform texture into QByteArray and get QImage
Step 2
Then JPG format I save in QBuffer and create new QByteArray
Step 3
By using the QByteArray I get cv::Mat that serves as a frame for VideoWriter
Here is the solid script that creates video:
D3D11_MAPPED_SUBRESOURCE* resource = new D3D11_MAPPED_SUBRESOURCE;
UINT subresource = D3D11CalcSubresource(0, 0, 0);
lImmediateContext->Map(texture, subresource, D3D11_MAP_READ_WRITE, 0, resource);
EImgByteFormat fmt = BF_R8G8B8A8;
if (desc.Format == DXGI_FORMAT_B8G8R8A8_UNORM ||
desc.Format == DXGI_FORMAT_B8G8R8X8_UNORM ||
desc.Format == DXGI_FORMAT_B8G8R8A8_TYPELESS ||
desc.Format == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB ||
desc.Format == DXGI_FORMAT_B8G8R8X8_TYPELESS ||
desc.Format == DXGI_FORMAT_B8G8R8X8_UNORM_SRGB)
{
fmt = BF_B8G8R8A8;
}
QByteArray rawData = PackImageData(fmt, (char*)resource->pData, desc.Height, desc.Width);
uint32_t rows = *(uint32_t*)(rawData.data() + 1);
uint32_t columns = *(uint32_t*)(rawData.data() + 1 + 4);
QImage screenshot = RawDataToQImage(fmt, rawData.data() + 1 + 4 + 4, rows, columns);
QByteArray arr;
QBuffer buffer(&arr);
buffer.open(QIODevice::WriteOnly);
screenshot.save(&buffer, "JPG");
buffer.close();
Mat frame = imdecode(std::vector<uchar>(arr.begin(), arr.end()), 1);
VideoWriter oVideoWriter("TestVideo.avi", VideoWriter::fourcc('M', 'J', 'P', 'G'), frames_per_second, frame_size, true);
oVideoWriter << frame;
oVideoWriter.release();
I want to skip step 1 and step 2 and promptly transform texture into cv::Mat, but I am not exactly sure how to get it.
Here is an example of the script:
char* buffer = new char[desc.Width * desc.Height * 4];
char* mappedData = static_cast<char*>(resource->pData);
memcpy(buffer, mappedData, desc.Width * desc.Height * 4);
// OpenCV IplImage Convertion
IplImage* frame = cvCreateImageHeader(cvSize(desc.Width, desc.Height), IPL_DEPTH_8U, 4);
frame->imageData = (char*)buffer;
frame->imageDataOrigin = frame->imageData;
Mat mat = cvarrToMat(frame, true);
imshow("Frame", mat);
VideoWriter oVideoWriter("TestVideo.avi", VideoWriter::fourcc('M', 'J', 'P', 'G'), frames_per_second, frame_size, true);
oVideoWriter << mat;
oVideoWriter.release();
Or is it possible to directly get cv :: Mat from the texture:
Mat frame(desc.Height, desc.Width, CV_8U, resource->pData, (int)resource->RowPitch)
cv::directx::convertFromD3D11Texture2D(texture, frame)