diff --git a/wcap_encoder.h b/wcap_encoder.h index 7511af1..4d59526 100644 --- a/wcap_encoder.h +++ b/wcap_encoder.h @@ -398,6 +398,8 @@ BOOL Encoder_Start(Encoder* Encoder, ID3D11Device* Device, LPWSTR FileName, cons HR(IMFMediaType_SetGUID(Type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)); HR(IMFMediaType_SetGUID(Type, &MF_MT_SUBTYPE, Codec)); HR(IMFMediaType_SetUINT32(Type, &MF_MT_MPEG2_PROFILE, Profile)); + HR(IMFMediaType_SetUINT32(Type, &MF_MT_VIDEO_CHROMA_SITING, MFVideoChromaSubsampling_MPEG2)); + HR(IMFMediaType_SetUINT32(Type, &MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_Wide)); HR(IMFMediaType_SetUINT32(Type, &MF_MT_VIDEO_PRIMARIES, IsHD ? MFVideoPrimaries_BT709 : MFVideoPrimaries_SMPTE170M)); HR(IMFMediaType_SetUINT32(Type, &MF_MT_YUV_MATRIX, IsHD ? MFVideoTransferMatrix_BT709 : MFVideoTransferMatrix_BT601)); HR(IMFMediaType_SetUINT32(Type, &MF_MT_TRANSFER_FUNCTION, MFVideoPrimaries_BT709)); @@ -422,9 +424,6 @@ BOOL Encoder_Start(Encoder* Encoder, ID3D11Device* Device, LPWSTR FileName, cons HR(MFCreateMediaType(&Type)); HR(IMFMediaType_SetGUID(Type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)); HR(IMFMediaType_SetGUID(Type, &MF_MT_SUBTYPE, MediaFormatYUV)); - HR(IMFMediaType_SetUINT32(Type, &MF_MT_VIDEO_PRIMARIES, IsHD ? MFVideoPrimaries_BT709 : MFVideoPrimaries_SMPTE170M)); - HR(IMFMediaType_SetUINT32(Type, &MF_MT_YUV_MATRIX, IsHD ? MFVideoTransferMatrix_BT709 : MFVideoTransferMatrix_BT601)); - HR(IMFMediaType_SetUINT32(Type, &MF_MT_TRANSFER_FUNCTION, MFVideoPrimaries_BT709)); HR(IMFMediaType_SetUINT32(Type, &MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive)); HR(IMFMediaType_SetUINT64(Type, &MF_MT_FRAME_RATE, MFT64(Config->FramerateNum, Config->FramerateDen))); HR(IMFMediaType_SetUINT64(Type, &MF_MT_FRAME_SIZE, MFT64(OutputWidth, OutputHeight))); @@ -572,7 +571,8 @@ BOOL Encoder_Start(Encoder* Encoder, ID3D11Device* Device, LPWSTR FileName, cons // yuv converter { - YuvConvert_Create(&Encoder->Convert, Device, Encoder->Resize.OutputTexture, OutputWidth, OutputHeight, IsHD, Config->Config->ImprovedColorConversion); + YuvColorSpace ColorSpace = IsHD ? YuvColorSpace_BT709 : YuvColorSpace_BT601; + YuvConvert_Create(&Encoder->Convert, Device, Encoder->Resize.OutputTexture, OutputWidth, OutputHeight, ColorSpace, Config->Config->ImprovedColorConversion); UINT32 Size; HR(MFCalculateImageSize(MediaFormatYUV, OutputWidth, OutputHeight, &Size)); @@ -753,6 +753,7 @@ BOOL Encoder_NewFrame(Encoder* Encoder, ID3D11Texture2D* Texture, RECT Rect, UIN // convert to YUV YuvConvert_Dispatch(&Encoder->Convert, Context, &Encoder->ConvertOutput[Index]); + ID3D11DeviceContext_Flush(Context); ID3D11Multithread_Leave(Encoder->Multithread); // setup input time & duration diff --git a/wcap_yuv_convert.h b/wcap_yuv_convert.h index 455aea1..1273dcc 100644 --- a/wcap_yuv_convert.h +++ b/wcap_yuv_convert.h @@ -28,10 +28,18 @@ typedef struct } YuvConvert; +typedef enum +{ + YuvColorSpace_BT601, + YuvColorSpace_BT709, + YuvColorSpace_BT2020, +} +YuvColorSpace; + static void YuvConvertOutput_Create(YuvConvertOutput* Output, ID3D11Device* Device, uint32_t Width, uint32_t Height, DXGI_FORMAT Format); static void YuvConvertOutput_Release(YuvConvertOutput* Output); -static void YuvConvert_Create(YuvConvert* Convert, ID3D11Device* Device, ID3D11Texture2D* InputTexture, uint32_t Width, uint32_t Height, bool IsHD, bool ImprovedConversion); +static void YuvConvert_Create(YuvConvert* Convert, ID3D11Device* Device, ID3D11Texture2D* InputTexture, uint32_t Width, uint32_t Height, YuvColorSpace ColorSpace, bool ImprovedConversion); static void YuvConvert_Release(YuvConvert* Convert); static void YuvConvert_Dispatch(YuvConvert* Convert, ID3D11DeviceContext* Context, YuvConvertOutput* Output); @@ -96,7 +104,7 @@ void YuvConvertOutput_Release(YuvConvertOutput* Output) ID3D11ShaderResourceView_Release(Output->ViewInUV); } -void YuvConvert_Create(YuvConvert* Convert, ID3D11Device* Device, ID3D11Texture2D* InputTexture, uint32_t Width, uint32_t Height, bool IsHD, bool ImprovedConversion) +void YuvConvert_Create(YuvConvert* Convert, ID3D11Device* Device, ID3D11Texture2D* InputTexture, uint32_t Width, uint32_t Height, YuvColorSpace ColorSpace, bool ImprovedConversion) { Assert(Width % 2 == 0 && Height % 2 == 0); @@ -108,8 +116,21 @@ void YuvConvert_Create(YuvConvert* Convert, ID3D11Device* Device, ID3D11Texture2 }; ID3D11Device_CreateShaderResourceView(Device, (ID3D11Resource*)InputTexture, &InputViewDesc, &Convert->InputView); + // https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.2020_conversion + static const float BT2020[6][4] = + { + // RGB to YUV + { +0.26270f, +0.678000f, +0.0593000f }, + { -0.13963f, -0.360370f, +0.5000000f }, + { +0.50000f, -0.459786f, -0.0402143f }, + // YUV to RGB + { 1.f, +0.000000f, +1.474600f }, + { 1.f, -0.164553f, -0.571353f }, + { 1.f, +1.881400f, +0.000000f }, + }; + // https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.709_conversion - static const float BT709[7][4] = + static const float BT709[6][4] = { // RGB to YUV { +0.2126f, +0.7152f, +0.0722f }, @@ -120,8 +141,9 @@ void YuvConvert_Create(YuvConvert* Convert, ID3D11Device* Device, ID3D11Texture2 { 1.f, -0.1873f, -0.4681f }, { 1.f, +1.8556f, +0.0000f }, }; + // https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion - static const float BT601[7][4] = + static const float BT601[6][4] = { // RGB to YUV { +0.299000f, +0.587000f, +0.114000f }, @@ -133,16 +155,25 @@ void YuvConvert_Create(YuvConvert* Convert, ID3D11Device* Device, ID3D11Texture2 { 1.f, +1.772000f, +0.000000f }, }; + const float (*ConvertMatrix)[4]; + switch (ColorSpace) + { + case YuvColorSpace_BT601: ConvertMatrix = BT601; break; + case YuvColorSpace_BT709: ConvertMatrix = BT709; break; + case YuvColorSpace_BT2020: ConvertMatrix = BT2020; break; + default: Assert(false); + } + D3D11_BUFFER_DESC ConstantBufferDesc = { - .ByteWidth = IsHD ? sizeof(BT709) : sizeof(BT601), + .ByteWidth = 6 * 4 * sizeof(float), .Usage = D3D11_USAGE_IMMUTABLE, .BindFlags = D3D11_BIND_CONSTANT_BUFFER, }; D3D11_SUBRESOURCE_DATA ConstantBufferData = { - .pSysMem = IsHD ? BT709 : BT601, + .pSysMem = ConvertMatrix, }; ID3D11Device_CreateBuffer(Device, &ConstantBufferDesc, &ConstantBufferData, &Convert->ConstantBuffer);