summaryrefslogtreecommitdiff
path: root/general/SimpleMediaSource/MediaSource/SimpleFrameGenerator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'general/SimpleMediaSource/MediaSource/SimpleFrameGenerator.cpp')
-rw-r--r--general/SimpleMediaSource/MediaSource/SimpleFrameGenerator.cpp146
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;
+}