diff options
Diffstat (limited to 'general/SimpleMediaSource/MediaSource/SimpleFrameGenerator.cpp')
| -rw-r--r-- | general/SimpleMediaSource/MediaSource/SimpleFrameGenerator.cpp | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/general/SimpleMediaSource/MediaSource/SimpleFrameGenerator.cpp b/general/SimpleMediaSource/MediaSource/SimpleFrameGenerator.cpp new file mode 100644 index 00000000..6adafb44 --- /dev/null +++ b/general/SimpleMediaSource/MediaSource/SimpleFrameGenerator.cpp @@ -0,0 +1,146 @@ +// +// Copyright (C) Microsoft Corporation. All rights reserved. +// +#include "pch.h" + +HRESULT SimpleFrameGenerator::Initialize(_In_ IMFMediaType* pMediaType) +{ + RETURN_HR_IF_NULL(E_INVALIDARG, pMediaType); + + RETURN_IF_FAILED(pMediaType->GetGUID(MF_MT_SUBTYPE, &m_subType)); + if (m_subType != MFVideoFormat_RGB32 && m_subType != MFVideoFormat_NV12) + { + RETURN_HR_MSG(MF_E_UNSUPPORTED_FORMAT, "Unsupported format: %s", winrt::to_hstring(m_subType).data()); + } + MFGetAttributeSize(pMediaType, MF_MT_FRAME_SIZE, &m_width, &m_height); + + return S_OK; +} + +/*: + Writes to a buffer representing a 2D image. + Writes a different constant to each line based on row number and current time. + Assumes top down image, no negative stride and pBuf points to the begnning of the buffer of length len. + Param: + pBuf - pointer to beginning of buffer + pitch - line length in bytes + len - length of buffer in bytes +*/ +HRESULT SimpleFrameGenerator::CreateFrame( + _Inout_updates_bytes_(len) BYTE* pBuf, + _In_ DWORD len, + _In_ LONG pitch, + _In_ ULONG rgbMask) +{ + if (m_subType == MFVideoFormat_RGB32) + { + DEBUG_MSG(L"RGB32 frames %s\n", winrt::to_hstring(MFVideoFormat_RGB32).data()); + + RETURN_IF_FAILED(_CreateRGB32Frame(pBuf, len, pitch, m_width, m_height, rgbMask)); + } + else if(m_subType == MFVideoFormat_NV12) + { + DEBUG_MSG(L"NV12 frames %s \n", winrt::to_hstring(MFVideoFormat_NV12).data()); + + DWORD frameBuffLen = m_width * m_height * 4; + wil::unique_cotaskmem_ptr<BYTE[]> spBuff = wil::make_unique_cotaskmem_nothrow<BYTE[]>(frameBuffLen); + RETURN_IF_NULL_ALLOC(spBuff.get()); + + RETURN_IF_FAILED(_CreateRGB32Frame(spBuff.get(), frameBuffLen, m_width * 4, m_width, m_height, rgbMask)); + RETURN_IF_FAILED(RGB32ToNV12Frame(spBuff.get(), frameBuffLen, m_width * 4, m_width, m_height, pBuf, len, pitch)); + } + else + { + return MF_E_UNSUPPORTED_FORMAT; + } + + return S_OK; +} + +////////////////////////////////////////////////// +// private + +HRESULT SimpleFrameGenerator::_CreateRGB32Frame( + _Inout_updates_bytes_(len) BYTE* pBuf, + _In_ DWORD len, + _In_ LONG pitch, + _In_ DWORD width, + _In_ DWORD height, + _In_ ULONG rgbMask ) +{ + RETURN_HR_IF_NULL(E_INVALIDARG, pBuf); + + LONGLONG curSysTimeInS = MFGetSystemTime() / (MFTIME)10000000; + int offset = curSysTimeInS % height; + + for (unsigned int r = 0; r < height; r++) + { + uint32_t* p = (uint32_t*)(pBuf + (r * pitch)); + for (unsigned int c = 0; c < width; c++) + { + BYTE gray = (BYTE)r + offset; + *p = ((uint32_t)gray << 16 | (uint32_t)gray << 8 | (uint32_t)gray) & rgbMask; + p++; + } + } + + return S_OK; +} + +////////////////////////////////////////////////// +// pixelFormatConverter + +void SimpleFrameGenerator::RGB24ToYUY2(int R, int G, int B, BYTE* pY, BYTE* pU, BYTE* pV) +{ + *pY = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16; + *pU = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128; + *pV = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128; +} + +void SimpleFrameGenerator::RGB24ToY(int R, int G, int B, BYTE* pY) +{ + *pY = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16; +} + +void SimpleFrameGenerator::RGB32ToNV12(BYTE RGB1[8], BYTE RGB2[8], BYTE* pY1, BYTE* pY2, BYTE* pUV) +{ + RGB24ToYUY2(RGB1[2], RGB1[1], RGB1[0], pY1, pUV, pUV + 1); + RGB24ToY(RGB1[6], RGB1[5], RGB1[4], pY1 + 1); + RGB24ToYUY2(RGB2[2], RGB2[1], RGB2[0], pY2, pUV, pUV + 1); + RGB24ToY(RGB2[6], RGB2[5], RGB2[4], pY2 + 1); +}; + +////////////////////////////////////////////////// +// FrameFormatConverter + +HRESULT SimpleFrameGenerator::RGB32ToNV12Frame(_Inout_updates_bytes_(len) BYTE* pbBuff, ULONG cbBuff, long stride, UINT width, UINT height, BYTE* pbBuffOut, ULONG cbBuffOut, long strideOut) +{ + do + { + RETURN_HR_IF(E_UNEXPECTED, width * 4 * height > cbBuff); + RETURN_HR_IF(E_UNEXPECTED, width * 1.5 * height > cbBuffOut); + RETURN_HR_IF_NULL(E_INVALIDARG, pbBuff); + + RETURN_HR_IF_NULL(E_INVALIDARG, pbBuffOut); + for (DWORD h = 0; h < height - 1; h += 2) + { + BYTE* pRGB1 = h * stride + pbBuff; + BYTE* pRGB2 = (h + 1) * stride + pbBuff; + BYTE* pY1 = h * strideOut + pbBuffOut; + BYTE* pY2 = (h + 1) * strideOut + pbBuffOut; + BYTE* pUV = (h / 2 + height) * strideOut + pbBuffOut; + + for (DWORD w = 0; w < width; w += 2) + { + RGB32ToNV12(pRGB1, pRGB2, pY1, pY2, pUV); + pRGB1 += 8; + pRGB2 += 8; + pY1 += 2; + pY2 += 2; + pUV += 2; + } + } + } while (FALSE); + + return S_OK; +} |
