// CFlickerLogo.cpp : Implementation of CDmoVideoWatermarkApp and DLL registration.
/**
** Copyright (C) 2005 EnjoyView Inc., all rights reserved.
** Your View, Our Passion. Just Enjoy It!
**
** http://spaces.msn.com/members/jemylu
**
**/
/*************************************************************************/
#include "stdafx.h"
#include "DmoVideoWatermark.h"
#define FIX_LOCK_NAME
#include <dmo.h>
#include <limits.h> // _I64_MAX
#include <crtdbg.h>
#include <dmoimpl.h>
#include <uuids.h> // DirectShow media type guids
#include <amvideo.h> // VIDEOINFOHEADER definition
#include "CFlickerLogo.h"
#define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
/////////////////////////////////////////////////////////////////////////////
//
/*
STDMETHODIMP CFlickerLogo::InterfaceSupportsErrorInfo(REFIID riid)
{
static const IID* arr[] =
{
&IID_IFlickerLogo,
};
for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
{
if (InlineIsEqualGUID(*arr[i],riid))
return S_OK;
}
return S_FALSE;
}*/
CFlickerLogo::CFlickerLogo()
{
mUnkMarshaler = NULL;
mInputFrame = NULL;
mFrameTime = 0;
mFrameDuration = 0;
mIsInputInited = FALSE;
mImageWidth = 0;
mImageHeight = 0;
mImageStride = 0;
mLogoStride = 0;
mFrameCount = 0;
}
CFlickerLogo::~CFlickerLogo()
{
SAFE_RELEASE(mInputFrame);
}
HRESULT CFlickerLogo::FinalConstruct()
{
return CoCreateFreeThreadedMarshaler(GetControllingUnknown(),
&mUnkMarshaler.p);
}
void CFlickerLogo::FinalRelease()
{
// Make sure we clean up
FreeStreamingResources();
mUnkMarshaler.Release();
}
// Helper - compares media types - ignoring the advisory fields
bool CFlickerLogo::TypesMatch(const DMO_MEDIA_TYPE *pmt1,
const DMO_MEDIA_TYPE *pmt2)
{
if (pmt1->majortype == pmt2->majortype &&
pmt1->subtype == pmt2->subtype &&
pmt1->lSampleSize == pmt2->lSampleSize &&
pmt1->formattype == pmt2->formattype &&
pmt1->cbFormat == pmt2->cbFormat &&
0 == memcmp(pmt1->pbFormat, pmt2->pbFormat, pmt1->cbFormat))
{
return true;
}
else
{
return false;
}
}
// --- IMediaObjectImpl methods ---
HRESULT CFlickerLogo::InternalGetInputStreamInfo(DWORD dwInputStreamIndex,
DWORD *pdwFlags)
{
// We can process data on any boundary
*pdwFlags = 0;
return S_OK;
}
HRESULT CFlickerLogo::InternalGetOutputStreamInfo(DWORD dwOutputStreamIndex,
DWORD *pdwFlags)
{
// We output single frames
*pdwFlags = DMO_OUTPUT_STREAMF_WHOLE_SAMPLES |
DMO_OUTPUT_STREAMF_SINGLE_SAMPLE_PER_BUFFER |
DMO_OUTPUT_STREAMF_FIXED_SAMPLE_SIZE;
return S_OK;
}
// RGB Video supported only
HRESULT CFlickerLogo::InternalCheckInputType(DWORD dwInputStreamIndex,
const DMO_MEDIA_TYPE *pmt)
{
// Check if the type is already set
// and if so reject any type that's not identical
if (InputTypeSet(dwInputStreamIndex))
{
if (!TypesMatch(pmt, InputType(dwInputStreamIndex)))
{
return DMO_E_INVALIDTYPE;
}
else
{
return S_OK;
}
}
// We accept MEDIATYPE_Video
if (pmt->majortype == MEDIATYPE_Video && pmt->pbFormat != NULL)
{
return S_OK;
}
return DMO_E_INVALIDTYPE;
}
HRESULT CFlickerLogo::InternalCheckOutputType(DWORD dwOutputStreamIndex,
const DMO_MEDIA_TYPE *pmt)
{
// Check if the type is already set
// and if so reject any type that's not identical
if (OutputTypeSet(dwOutputStreamIndex))
{
if (!TypesMatch(pmt, OutputType(dwOutputStreamIndex)))
{
return DMO_E_INVALIDTYPE;
}
else
{
return S_OK;
}
}
// Input mediatype should be set first
// And we specify input and output use the same media type
if (InputTypeSet(0))
{
if (!TypesMatch(pmt, InputType(0)))
{
return DMO_E_INVALIDTYPE;
}
else
{
return S_OK;
}
}
return DMO_E_INVALIDTYPE;
}
HRESULT CFlickerLogo::InternalGetInputType(DWORD dwInputStreamIndex,
DWORD dwTypeIndex,
DMO_MEDIA_TYPE *pmt)
{
// No types to all indices for dwTypeIndex are out of range
return DMO_E_NO_MORE_ITEMS;
}
HRESULT CFlickerLogo::InternalGetOutputType(DWORD dwOutputStreamIndex,
DWORD dwTypeIndex,
DMO_MEDIA_TYPE *pmt)
{
if (!InputTypeSet(0)) // Input media type must be set first
{
return DMO_E_TYPE_NOT_SET;
}
if (dwTypeIndex != 0)
{
return DMO_E_NO_MORE_ITEMS;
}
// If GetOutputType()'s pmt parameter is NULL, return S_OK if the type exists.
// Return DMO_E_NO_MORE_ITEMS if the type does not exists. See the
// documentation for IMediaObject::GetOutputType() for more information.
if (pmt != NULL)
{
HRESULT hr = MoCopyMediaType(pmt, InputType(0));
if (FAILED(hr))
{
return hr;
}
}
return S_OK;
}
HRESULT CFlickerLogo::InternalGetInputSizeInfo(DWORD dwInputStreamIndex,
DWORD *pcbSize,
DWORD *pcbMaxLookahead,
DWORD *pcbAlignment)
{
*pcbSize = 1;
*pcbMaxLookahead = 0;
*pcbAlignment = 1;
return S_OK;
}
HRESULT CFlickerLogo::InternalGetOutputSizeInfo(DWORD dwOutputStreamIndex,
DWORD *pcbSize,
DWORD *pcbAlignment)
{
*pcbAlignment = 1;
*pcbSize = OutputType(0)->lSampleSize;
return S_OK;
}
HRESULT CFlickerLogo::InternalGetInputMaxLatency(DWORD dwInputStreamIndex,
REFERENCE_TIME *prtMaxLatency)
{
return E_NOTIMPL;
}
HRESULT CFlickerLogo::InternalSetInputMaxLatency(DWORD dwInputStreamIndex,
REFERENCE_TIME rtMaxLatency)
{
return E_NOTIMPL;
}
HRESULT CFlickerLogo::InternalFlush()
{
InternalDiscontinuity(0);
return S_OK;
}
HRESULT CFlickerLogo::InternalDiscontinuity(DWORD dwInputStreamIndex)
{
SAFE_RELEASE(mInputFrame);
mFrameCount = 0;
return S_OK;
}
HRESULT CFlickerLogo::InternalAllocateStreamingResources()
{
// Reinitialize variables
InternalDiscontinuity(0);
mIsInputInited = FALSE;
return S_OK;
}
HRESULT CFlickerLogo::InternalFreeStreamingResources()
{
return S_OK;
}
HRESULT CFlickerLogo::InternalProcessInput(DWORD dwInputStreamIndex,
IMediaBuffer *pBuffer,
DWORD dwFlags,
REFERENCE_TIME rtTimestamp,
REFERENCE_TIME rtTimelength)
{
if (!mIsInputInited)
{
mIsInputInited = TRUE;
VIDEOINFOHEADER * pvi = (VIDEOINFOHEADER *) InputType(0)->pbFormat;
mImageWidth = pvi->bmiHeader.biWidth;
mImageHeight = pvi->bmiHeader.biHeight;
mImageStride = (pvi->bmiHeader.biWidth * pvi->bmiHeader.biBitCount / 8 + 3) & ~3;
mLogoStride = cLogoWidth * pvi->bmiHeader.biBitCount / 8;
}
BYTE * pData;
DWORD dataLength = 0;
HRESULT hr = pBuffer->GetBufferAndLength(&pData, &dataLength);
if (FAILED(hr))
{
return hr;
}
// Do watermark overlay here >>>
pBuffer->AddRef(); // Add a reference count
mInputFrame = pBuffer;
mFrameTime = rtTimestamp; // Save time stamp
mFrameDuration = rtTimelength;
if (cLogoWidth <= mImageWidth && cLogoHeight <= mImageHeight)
{
BYTE * pLine = pData;
BYTE newValue = (mFrameCount++ % 3 == 0) ? 0xFF : 0;
for (int i = 0; i < cLogoHeight; i++)
{
if (i % 2 == 0)
{
memset(pLine, newValue, mLogoStride);
}
pLine += mImageStride;
}
}
return S_OK;
}
HRESULT CFlickerLogo::InternalProcessOutput(DWORD dwFlags,
DWORD cOutputBufferCount,
DMO_OUTPUT_DATA_BUFFER *pOutputBuffers,
DWORD *pdwStatus)
{
PBYTE pOutData;
DWORD cbCurrent;
HRESULT hr = pOutputBuffers[0].pBuffer->GetBufferAndLength(&pOutData, &cbCurrent);
if (FAILED(hr))
{
return hr;
}
// Copy watermark-overlayed image data
if (mInputFrame)
{
PBYTE pInData;
DWORD dataLength = 0;
mInputFrame->GetBufferAndLength(&p