C++ MediaFoundation&x2B;VP8+;颜色格式

C++ MediaFoundation&x2B;VP8+;颜色格式,c++,winapi,yuv,vp8,libvpx,C++,Winapi,Yuv,Vp8,Libvpx,我的最终目标是为我的虚拟课堂应用程序添加视频支持。我的方法是: 使用Media Foundation捕获帧 使用VP8编码 用UDP传输 在接收站点解码 在窗口中显示帧 第一个问题是我的网络摄像头支持的颜色编码。网络摄像头媒体类型仅包含MFVideoFormat_NV12。我的第一次调试尝试将接收图像保存为位图,以便我可以测试它是否正确捕获(已删除错误处理): HRESULT CAP::StartRecord(HWND hh,CComPtr src) { MFCreateSourceRead

我的最终目标是为我的虚拟课堂应用程序添加视频支持。我的方法是:

  • 使用Media Foundation捕获帧
  • 使用VP8编码
  • 用UDP传输
  • 在接收站点解码
  • 在窗口中显示帧
第一个问题是我的网络摄像头支持的颜色编码。网络摄像头媒体类型仅包含MFVideoFormat_NV12。我的第一次调试尝试将接收图像保存为位图,以便我可以测试它是否正确捕获(已删除错误处理):

HRESULT CAP::StartRecord(HWND hh,CComPtr src)
{
MFCreateSourceReaderFromMediaSource(src、0和sr);
货币基金组织;
sr->GetCurrentMediaType(MF\u源\u读卡器\u第一\u视频\u流和fmt);
LogMediaType(fmt);//显示:MFVideoFormat\u NV12
自动[wi,he]=宽度高度(fmt);
对于(;;)
{
DWORD streamIndex=0,flags=0;
LONGLONG llTimeStamp=0;
CComPtr样本;
hr=sr->ReadSample(MF\u SOURCE\u READER\u FIRST\u VIDEO\u STREAM,0、&streamIndex、&flags、&llTimeStamp、&pSample);
如果(失败(小时))
打破
如果(!pSample)
继续;
商业银行;
示例->转换到连续缓冲区(&bu);
SaveSampleNV12(bu、wi、he);
}
...
}
SaveSampleNV12使用源代码将NV12转换为RGB,然后:

void SaveSampleNV12(CComPtr<IMFMediaBuffer> mm, int width32, int height32)
{
    DWORD le = 0;
    mm->GetCurrentLength(&le);
    BYTE *pDatad = NULL;
    auto hr = mm->Lock(&pDatad, NULL, NULL);

    vector<char> rgb(1000000);
    NV12ToRGB((BYTE*)rgb.data(), pDatad, width32, height32);
    mm->Unlock();


    HANDLE file;
    BITMAPFILEHEADER fileHeader;
    BITMAPINFOHEADER fileInfo;
    DWORD write = 0;

    auto df = L"r:\\f.bmp";
    file = CreateFile(df.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);  //Sets up the new bmp to be written to

    int bits = 24;
    fileHeader.bfType = 19778;                                                                    //Sets our type to BM or bmp
    fileHeader.bfSize = sizeof(fileHeader.bfOffBits) + sizeof(RGBTRIPLE);                                                //Sets the size equal to the size of the header struct
    fileHeader.bfReserved1 = 0;                                                                    //sets the reserves to 0
    fileHeader.bfReserved2 = 0;
    fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);                    //Sets offbits equal to the size of file and info header

    fileInfo.biSize = sizeof(BITMAPINFOHEADER);
    fileInfo.biWidth = width32;
    fileInfo.biHeight = height32;
    fileInfo.biPlanes = 1;
    fileInfo.biBitCount = bits;
    fileInfo.biCompression = BI_RGB;
    fileInfo.biSizeImage = width32 * height32 * (bits / 8);
    fileInfo.biXPelsPerMeter = 0;// 2400;
    fileInfo.biYPelsPerMeter = 0;// 2400;
    fileInfo.biClrImportant = 0;
    fileInfo.biClrUsed = 0;

    WriteFile(file, &fileHeader, sizeof(fileHeader), &write, NULL);
    WriteFile(file, &fileInfo, sizeof(fileInfo), &write, NULL);

    unsigned char* ptrIn = (unsigned char*)rgb.data();
    int rgbs = width32 * height32 * (bits / 8);
    vector<char> d2(rgbs);
    unsigned char* ptrOut = (unsigned char*)d2.data();
    for (int i = 0; i < (width32*height32) / 2; ++i)
    {
        int y0 = ptrIn[0];
        int u0 = ptrIn[1];
        int y1 = ptrIn[2];
        int v0 = ptrIn[3];
        ptrIn += 4;
        int c = y0 - 16;
        int d = u0 - 128;
        int e = v0 - 128;
        int bb = clip((298 * c + 516 * d + 128) >> 8); // blue
        int gg = clip((298 * c - 100 * d - 208 * e + 128) >> 8); // green
        int rr = clip((298 * c + 409 * e + 128) >> 8); // red

        ptrOut[0] = bb;
        ptrOut[1] = gg;
        ptrOut[2] = rr;

        c = y1 - 16;
        ptrOut[3] = clip((298 * c + 516 * d + 128) >> 8); // blue
        ptrOut[4] = clip((298 * c - 100 * d - 208 * e + 128) >> 8); // green
        ptrOut[5] = clip((298 * c + 409 * e + 128) >> 8); // red
        ptrOut += 6;
    }

    unsigned char* cc = (unsigned char*)d2.data();
    WriteFile(file, cc, rgbs, &write, NULL);
    CloseHandle(file);
}
void SaveSampleNV12(立方毫米,整数宽32,整数高32)
{
DWORD-le=0;
mm->GetCurrentLength(&le);
字节*pDatad=NULL;
自动hr=mm->锁定(&pDatad,NULL,NULL);
矢量rgb(1000000);
NV12ToRGB((字节*)rgb.data(),pDatad,宽度32,高度32);
mm->Unlock();
处理文件;
BITMAPFILEHEADER文件头;
BitMapInfo头文件信息;
DWORD write=0;
自动df=L“r:\\f.bmp”;
file=CreateFile(df.c_str(),GENERIC_WRITE,0,NULL,CREATE_ALWAYS,file_ATTRIBUTE_NORMAL,NULL);//设置要写入的新bmp
整数位=24;
fileHeader.bfType=19778;//将我们的类型设置为BM或bmp
fileHeader.bfSize=sizeof(fileHeader.bfOffBits)+sizeof(RGBTRIPLE);//将大小设置为等于header结构的大小
fileHeader.bfreeserved1=0;//将保留设置为0
fileHeader.bfReserved2=0;
fileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BitMapInfo头);//设置等于文件和信息头大小的offbits
fileInfo.biSize=sizeof(BitMapInfo标头);
fileInfo.biWidth=width32;
fileInfo.biHeight=高度32;
fileInfo.biPlanes=1;
fileInfo.biBitCount=位;
fileInfo.biCompression=BI_RGB;
fileInfo.biSizeImage=宽度32*高度32*(位/8);
fileInfo.biXPelsPerMeter=0;//2400;
fileInfo.biYPelsPerMeter=0;//2400;
fileInfo.biclr=0;
fileInfo.biClrUsed=0;
WriteFile(文件,&fileHeader,sizeof(fileHeader),&write,NULL);
WriteFile(文件,&fileInfo,sizeof(fileInfo),&write,NULL);
unsigned char*ptrIn=(unsigned char*)rgb.data();
int rgbs=宽度32*高度32*(位/8);
矢量d2(rgbs);
unsigned char*ptrOut=(unsigned char*)d2.data();
对于(整数i=0;i<(宽32*高32)/2;++i)
{
int y0=ptrIn[0];
int-u0=ptrIn[1];
int y1=ptrIn[2];
int v0=ptrIn[3];
ptrIn+=4;
int c=y0-16;
int d=u0-128;
int e=v0-128;
int bb=clip((298*c+516*d+128)>>8);//蓝色
int gg=clip((298*c-100*d-208*e+128)>>8);//绿色
int rr=clip((298*c+409*e+128)>>8);//红色
ptrOut[0]=bb;
ptrOut[1]=gg;
ptrOut[2]=rr;
c=y1-16;
ptrOut[3]=剪辑((298*c+516*d+128)>>8);//蓝色
ptrOut[4]=clip((298*c-100*d-208*e+128)>>8);//绿色
ptrOut[5]=剪辑((298*c+409*e+128)>>8);//红色
ptrOut+=6;
}
unsigned char*cc=(unsigned char*)d2.data();
WriteFile(文件、抄送、rgbs和写入,NULL);
关闭句柄(文件);
}
这将返回一个奇怪的充满粉红色的图像。我做错了什么

非常感谢。

解决方案是用于在各种颜色空间之间转换。

解决方案是用于在各种颜色空间之间转换

void SaveSampleNV12(CComPtr<IMFMediaBuffer> mm, int width32, int height32)
{
    DWORD le = 0;
    mm->GetCurrentLength(&le);
    BYTE *pDatad = NULL;
    auto hr = mm->Lock(&pDatad, NULL, NULL);

    vector<char> rgb(1000000);
    NV12ToRGB((BYTE*)rgb.data(), pDatad, width32, height32);
    mm->Unlock();


    HANDLE file;
    BITMAPFILEHEADER fileHeader;
    BITMAPINFOHEADER fileInfo;
    DWORD write = 0;

    auto df = L"r:\\f.bmp";
    file = CreateFile(df.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);  //Sets up the new bmp to be written to

    int bits = 24;
    fileHeader.bfType = 19778;                                                                    //Sets our type to BM or bmp
    fileHeader.bfSize = sizeof(fileHeader.bfOffBits) + sizeof(RGBTRIPLE);                                                //Sets the size equal to the size of the header struct
    fileHeader.bfReserved1 = 0;                                                                    //sets the reserves to 0
    fileHeader.bfReserved2 = 0;
    fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);                    //Sets offbits equal to the size of file and info header

    fileInfo.biSize = sizeof(BITMAPINFOHEADER);
    fileInfo.biWidth = width32;
    fileInfo.biHeight = height32;
    fileInfo.biPlanes = 1;
    fileInfo.biBitCount = bits;
    fileInfo.biCompression = BI_RGB;
    fileInfo.biSizeImage = width32 * height32 * (bits / 8);
    fileInfo.biXPelsPerMeter = 0;// 2400;
    fileInfo.biYPelsPerMeter = 0;// 2400;
    fileInfo.biClrImportant = 0;
    fileInfo.biClrUsed = 0;

    WriteFile(file, &fileHeader, sizeof(fileHeader), &write, NULL);
    WriteFile(file, &fileInfo, sizeof(fileInfo), &write, NULL);

    unsigned char* ptrIn = (unsigned char*)rgb.data();
    int rgbs = width32 * height32 * (bits / 8);
    vector<char> d2(rgbs);
    unsigned char* ptrOut = (unsigned char*)d2.data();
    for (int i = 0; i < (width32*height32) / 2; ++i)
    {
        int y0 = ptrIn[0];
        int u0 = ptrIn[1];
        int y1 = ptrIn[2];
        int v0 = ptrIn[3];
        ptrIn += 4;
        int c = y0 - 16;
        int d = u0 - 128;
        int e = v0 - 128;
        int bb = clip((298 * c + 516 * d + 128) >> 8); // blue
        int gg = clip((298 * c - 100 * d - 208 * e + 128) >> 8); // green
        int rr = clip((298 * c + 409 * e + 128) >> 8); // red

        ptrOut[0] = bb;
        ptrOut[1] = gg;
        ptrOut[2] = rr;

        c = y1 - 16;
        ptrOut[3] = clip((298 * c + 516 * d + 128) >> 8); // blue
        ptrOut[4] = clip((298 * c - 100 * d - 208 * e + 128) >> 8); // green
        ptrOut[5] = clip((298 * c + 409 * e + 128) >> 8); // red
        ptrOut += 6;
    }

    unsigned char* cc = (unsigned char*)d2.data();
    WriteFile(file, cc, rgbs, &write, NULL);
    CloseHandle(file);
}