summaryrefslogtreecommitdiff
path: root/general/SimpleMediaSource/MediaSource/SimpleMediaStream.cpp
diff options
context:
space:
mode:
authorSanjeev Reddy <[email protected]>2019-02-06 13:12:11 -0800
committerGitHub <[email protected]>2019-02-06 13:12:11 -0800
commit27302e1d522bc16e1cc18232602f7eca1b79db0f (patch)
tree1035100a803e4e52abbda93288091bb50f4f5073 /general/SimpleMediaSource/MediaSource/SimpleMediaStream.cpp
parent46da8a0d4f0de180dd15b6ca088e095b5e2c0b96 (diff)
parent39d39e7485faddf601d51c897863ff2f876e391e (diff)
Merge pull request #1 from Microsoft/master
Updating to latest
Diffstat (limited to 'general/SimpleMediaSource/MediaSource/SimpleMediaStream.cpp')
-rw-r--r--general/SimpleMediaSource/MediaSource/SimpleMediaStream.cpp391
1 files changed, 391 insertions, 0 deletions
diff --git a/general/SimpleMediaSource/MediaSource/SimpleMediaStream.cpp b/general/SimpleMediaSource/MediaSource/SimpleMediaStream.cpp
new file mode 100644
index 00000000..7685b12e
--- /dev/null
+++ b/general/SimpleMediaSource/MediaSource/SimpleMediaStream.cpp
@@ -0,0 +1,391 @@
+#include "stdafx.h"
+
+#define NUM_IMAGE_ROWS 240
+#define NUM_IMAGE_COLS 320
+#define BYTES_PER_PIXEL 4
+#define IMAGE_BUFFER_SIZE_BYTES (NUM_IMAGE_ROWS * NUM_IMAGE_COLS * BYTES_PER_PIXEL)
+#define IMAGE_ROW_SIZE_BYTES (NUM_IMAGE_COLS * BYTES_PER_PIXEL)
+
+HRESULT
+SimpleMediaStream::RuntimeClassInitialize(
+ _In_ SimpleMediaSource *pSource
+ )
+{
+ HRESULT hr = S_OK;
+ ComPtr<IMFMediaTypeHandler> spTypeHandler;
+ ComPtr<IMFAttributes> attrs;
+
+ if (nullptr == pSource)
+ {
+ return E_INVALIDARG;
+ }
+ RETURN_IF_FAILED (pSource->QueryInterface(IID_PPV_ARGS(&_parent)));
+
+ // Initialize media type and set the video output media type.
+ RETURN_IF_FAILED (MFCreateMediaType(&_spMediaType));
+ _spMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
+ _spMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32);
+ _spMediaType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
+ _spMediaType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
+ MFSetAttributeSize(_spMediaType.Get(), MF_MT_FRAME_SIZE, NUM_IMAGE_COLS, NUM_IMAGE_ROWS);
+ MFSetAttributeRatio(_spMediaType.Get(), MF_MT_FRAME_RATE, 30, 1);
+ MFSetAttributeRatio(_spMediaType.Get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
+
+ RETURN_IF_FAILED (MFCreateAttributes(&_spAttributes, 10));
+ RETURN_IF_FAILED (this->_SetStreamAttributes(_spAttributes.Get()));
+ RETURN_IF_FAILED (MFCreateEventQueue(&_spEventQueue));
+
+ // Initialize stream descriptors
+ RETURN_IF_FAILED (MFCreateStreamDescriptor(0, 1, _spMediaType.GetAddressOf(), &_spStreamDesc));
+
+ RETURN_IF_FAILED (_spStreamDesc->GetMediaTypeHandler(&spTypeHandler));
+ RETURN_IF_FAILED (spTypeHandler->SetCurrentMediaType(_spMediaType.Get()));
+ RETURN_IF_FAILED (this->_SetStreamDescriptorAttributes(_spStreamDesc.Get()));
+
+ return hr;
+}
+
+// IMFMediaEventGenerator
+IFACEMETHODIMP
+SimpleMediaStream::BeginGetEvent(
+ _In_ IMFAsyncCallback *pCallback,
+ _In_ IUnknown *punkState
+ )
+{
+ HRESULT hr = S_OK;
+ auto lock = _critSec.Lock();
+
+ RETURN_IF_FAILED (_CheckShutdownRequiresLock());
+ RETURN_IF_FAILED (_spEventQueue->BeginGetEvent(pCallback, punkState));
+
+ return hr;
+}
+
+IFACEMETHODIMP
+SimpleMediaStream::EndGetEvent(
+ _In_ IMFAsyncResult *pResult,
+ _COM_Outptr_ IMFMediaEvent **ppEvent
+ )
+{
+ HRESULT hr = S_OK;
+ auto lock = _critSec.Lock();
+
+ RETURN_IF_FAILED (_CheckShutdownRequiresLock());
+ RETURN_IF_FAILED (_spEventQueue->EndGetEvent(pResult, ppEvent));
+
+ return hr;
+}
+
+IFACEMETHODIMP
+SimpleMediaStream::GetEvent(
+ DWORD dwFlags,
+ _COM_Outptr_ IMFMediaEvent **ppEvent
+ )
+{
+ // NOTE:
+ // GetEvent can block indefinitely, so we don't hold the lock.
+ // This requires some juggling with the event queue pointer.
+
+ HRESULT hr = S_OK;
+
+ ComPtr<IMFMediaEventQueue> spQueue;
+
+ {
+ auto lock = _critSec.Lock();
+
+ RETURN_IF_FAILED (_CheckShutdownRequiresLock());
+ spQueue = _spEventQueue;
+ }
+
+ // Now get the event.
+ RETURN_IF_FAILED (_spEventQueue->GetEvent(dwFlags, ppEvent));
+
+ return hr;
+}
+
+IFACEMETHODIMP
+SimpleMediaStream::QueueEvent(
+ MediaEventType eventType,
+ REFGUID guidExtendedType,
+ HRESULT hrStatus,
+ _In_opt_ PROPVARIANT const *pvValue
+ )
+{
+ HRESULT hr = S_OK;
+ auto lock = _critSec.Lock();
+
+ RETURN_IF_FAILED (_CheckShutdownRequiresLock());
+ RETURN_IF_FAILED (_spEventQueue->QueueEventParamVar(eventType, guidExtendedType, hrStatus, pvValue));
+
+ return hr;
+}
+
+// IMFMediaStream
+IFACEMETHODIMP
+SimpleMediaStream::GetMediaSource(
+ _COM_Outptr_ IMFMediaSource **ppMediaSource
+ )
+{
+ HRESULT hr = S_OK;
+ auto lock = _critSec.Lock();
+
+ if (ppMediaSource == nullptr)
+ {
+ return E_POINTER;
+ }
+ *ppMediaSource = nullptr;
+
+ RETURN_IF_FAILED (_CheckShutdownRequiresLock());
+
+ *ppMediaSource = _parent.Get();
+ (*ppMediaSource)->AddRef();
+
+ return hr;
+}
+
+IFACEMETHODIMP
+SimpleMediaStream::GetStreamDescriptor(
+ _COM_Outptr_ IMFStreamDescriptor **ppStreamDescriptor
+ )
+{
+ HRESULT hr = S_OK;
+ auto lock = _critSec.Lock();
+
+ if (ppStreamDescriptor == nullptr)
+ {
+ return E_POINTER;
+ }
+ *ppStreamDescriptor = nullptr;
+
+ RETURN_IF_FAILED (_CheckShutdownRequiresLock());
+
+ if (_spStreamDesc != nullptr)
+ {
+ *ppStreamDescriptor = _spStreamDesc.Get();
+ (*ppStreamDescriptor)->AddRef();
+ }
+ else
+ {
+ return E_UNEXPECTED;
+ }
+
+ return hr;
+}
+
+/*
+ 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
+WriteSampleData(
+ _Inout_updates_bytes_(len) BYTE *pBuf,
+ _In_ LONG pitch,
+ _In_ DWORD len
+ )
+{
+ if (pBuf == nullptr)
+ {
+ return E_INVALIDARG;
+ }
+
+ const int NUM_ROWS = len / abs(pitch);
+
+ LONGLONG curSysTimeInS = MFGetSystemTime() / (MFTIME)10000000;
+ int offset = curSysTimeInS % NUM_ROWS;
+
+ for (int r = 0; r < NUM_ROWS; r++)
+ {
+ int grayColor = r + offset;
+ memset(pBuf + (pitch * r), (BYTE)(grayColor % NUM_ROWS), pitch);
+ }
+
+ return S_OK;
+}
+
+IFACEMETHODIMP
+SimpleMediaStream::RequestSample(
+ _In_ IUnknown *pToken
+ )
+{
+ HRESULT hr = S_OK;
+ auto lock = _critSec.Lock();
+ ComPtr<IMFSample> sample;
+ ComPtr<IMFMediaBuffer> outputBuffer;
+ LONG pitch = IMAGE_ROW_SIZE_BYTES;
+ BYTE *bufferStart = nullptr; // not used
+ DWORD bufferLength = 0;
+ BYTE *pbuf = nullptr;
+ ComPtr<IMF2DBuffer2> buffer2D;
+
+ RETURN_IF_FAILED (_CheckShutdownRequiresLock());
+ RETURN_IF_FAILED (MFCreateSample(&sample));
+ RETURN_IF_FAILED (MFCreate2DMediaBuffer(NUM_IMAGE_COLS,
+ NUM_IMAGE_ROWS,
+ D3DFMT_X8R8G8B8,
+ false,
+ &outputBuffer));
+ RETURN_IF_FAILED (outputBuffer.As(&buffer2D));
+ RETURN_IF_FAILED (buffer2D->Lock2DSize(MF2DBuffer_LockFlags_Write,
+ &pbuf,
+ &pitch,
+ &bufferStart,
+ &bufferLength));
+ RETURN_IF_FAILED (WriteSampleData(pbuf, pitch, bufferLength));
+ RETURN_IF_FAILED (buffer2D->Unlock2D());
+ RETURN_IF_FAILED (sample->AddBuffer(outputBuffer.Get()));
+ RETURN_IF_FAILED (sample->SetSampleTime(MFGetSystemTime()));
+ RETURN_IF_FAILED (sample->SetSampleDuration(333333));
+ if (pToken != nullptr)
+ {
+ RETURN_IF_FAILED (sample->SetUnknown(MFSampleExtension_Token, pToken));
+ }
+ RETURN_IF_FAILED (_spEventQueue->QueueEventParamUnk(MEMediaSample,
+ GUID_NULL,
+ S_OK,
+ sample.Get()));
+
+ return hr;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// IMFMediaStream2
+IFACEMETHODIMP
+SimpleMediaStream::SetStreamState(
+ MF_STREAM_STATE state
+ )
+{
+ HRESULT hr = S_OK;
+ auto lock = _critSec.Lock();
+ bool runningState = false;
+
+ RETURN_IF_FAILED (_CheckShutdownRequiresLock());
+
+ switch (state)
+ {
+ case MF_STREAM_STATE_PAUSED:
+ goto done; // because not supported
+ case MF_STREAM_STATE_RUNNING:
+ runningState = true;
+ break;
+ case MF_STREAM_STATE_STOPPED:
+ runningState = false;
+ break;
+ default:
+ hr = MF_E_INVALID_STATE_TRANSITION;
+ break;
+ }
+
+ _isSelected = runningState;
+
+done:
+ return hr;
+}
+
+IFACEMETHODIMP
+SimpleMediaStream::GetStreamState(
+ _Out_ MF_STREAM_STATE *pState
+ )
+{
+ HRESULT hr = S_OK;
+ auto lock = _critSec.Lock();
+ BOOLEAN pauseState = false;
+
+ RETURN_IF_FAILED (_CheckShutdownRequiresLock());
+
+ if (SUCCEEDED(hr))
+ {
+ *pState = (_isSelected ? MF_STREAM_STATE_RUNNING : MF_STREAM_STATE_STOPPED);
+ }
+
+ return hr;
+}
+
+HRESULT
+SimpleMediaStream::Shutdown(
+ )
+{
+ HRESULT hr = S_OK;
+ auto lock = _critSec.Lock();
+
+ _isShutdown = true;
+ _parent.Reset();
+
+ if (_spEventQueue != nullptr)
+ {
+ hr = _spEventQueue->Shutdown();
+ _spEventQueue.Reset();
+ }
+
+ _spAttributes.Reset();
+ _spMediaType.Reset();
+ _spStreamDesc.Reset();
+
+ _isSelected = false;
+
+ return hr;
+}
+
+HRESULT
+SimpleMediaStream::_CheckShutdownRequiresLock(
+ )
+{
+ if (_isShutdown)
+ {
+ return MF_E_SHUTDOWN;
+ }
+
+ if (_spEventQueue == nullptr)
+ {
+ return E_UNEXPECTED;
+
+ }
+ return S_OK;
+}
+
+HRESULT
+SimpleMediaStream::_SetStreamAttributes(
+ _In_ IMFAttributes *pAttributeStore
+ )
+{
+ HRESULT hr = S_OK;
+
+ if (nullptr == pAttributeStore)
+ {
+ return E_INVALIDARG;
+ }
+
+ RETURN_IF_FAILED (pAttributeStore->SetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, PINNAME_VIDEO_CAPTURE));
+ RETURN_IF_FAILED (pAttributeStore->SetUINT32(MF_DEVICESTREAM_STREAM_ID, STREAMINDEX));
+ RETURN_IF_FAILED (pAttributeStore->SetUINT32(MF_DEVICESTREAM_FRAMESERVER_SHARED, 1));
+ RETURN_IF_FAILED (pAttributeStore->SetUINT32(MF_DEVICESTREAM_ATTRIBUTE_FRAMESOURCE_TYPES, _MFFrameSourceTypes::MFFrameSourceTypes_Color));
+
+ return hr;
+}
+
+HRESULT
+SimpleMediaStream::_SetStreamDescriptorAttributes(
+ _In_ IMFAttributes *pAttributeStore
+ )
+{
+ HRESULT hr = S_OK;
+
+ if (nullptr == pAttributeStore)
+ {
+ return E_INVALIDARG;
+ }
+
+ RETURN_IF_FAILED (pAttributeStore->SetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, PINNAME_VIDEO_CAPTURE));
+ RETURN_IF_FAILED (pAttributeStore->SetUINT32(MF_DEVICESTREAM_STREAM_ID, STREAMINDEX));
+ RETURN_IF_FAILED (pAttributeStore->SetUINT32(MF_DEVICESTREAM_FRAMESERVER_SHARED, 1));
+ RETURN_IF_FAILED (pAttributeStore->SetUINT32(MF_DEVICESTREAM_ATTRIBUTE_FRAMESOURCE_TYPES, _MFFrameSourceTypes::MFFrameSourceTypes_Color));
+
+ return hr;
+}
+