/* * Implements Color Space Converter(CLSID_Colour). * * hidenori@a2.ctktv.ne.jp */ #include "config.h" #include "windef.h" #include "winbase.h" #include "wingdi.h" #include "winuser.h" #include "winerror.h" #include "vfw.h" #include "strmif.h" #include "control.h" #include "amvideo.h" #include "vfwmsgs.h" #include "uuids.h" #include "debugtools.h" DEFAULT_DEBUG_CHANNEL(quartz); #include "quartz_private.h" #include "xform.h" #include "videoblt.h" static const WCHAR ColorConv_FilterName[] = {'C','o','l','o','r',' ','S','p','a','c','e',' ','C','o','n','v','e','r','t','e','r',0}; struct BltHandler { const GUID* psubtypeIn; const GUID* psubtypeOut; pVIDEOBLT_Blt pBlt; }; static const struct BltHandler conv_handlers[] = { { &MEDIASUBTYPE_RGB24, &MEDIASUBTYPE_RGB32, VIDEOBLT_Blt_888_to_8888 }, { &MEDIASUBTYPE_RGB24, &MEDIASUBTYPE_RGB565, VIDEOBLT_Blt_888_to_565 }, { &MEDIASUBTYPE_RGB24, &MEDIASUBTYPE_RGB555, VIDEOBLT_Blt_888_to_555 }, { &MEDIASUBTYPE_RGB24, &MEDIASUBTYPE_RGB8, VIDEOBLT_Blt_888_to_332 }, { NULL, NULL, NULL }, }; typedef struct CColorConvImpl { pVIDEOBLT_Blt m_pBlt; AM_MEDIA_TYPE* m_pmtConv; DWORD m_cConv; LONG pitchIn; LONG pitchOut; } CColorConvImpl; /*************************************************************************** * * CColorConvImpl methods * */ static void ColorConv_FreeOutTypes(CColorConvImpl* This) { DWORD i; if ( This->m_pmtConv == NULL ) return; TRACE("cConv = %lu\n",This->m_cConv); for ( i = 0; i < This->m_cConv; i++ ) { QUARTZ_MediaType_Free(&This->m_pmtConv[i]); } QUARTZ_FreeMem(This->m_pmtConv); This->m_pmtConv = NULL; This->m_cConv = 0; } static HRESULT ColorConv_FillBitmapInfo( BITMAPINFO* pbiOut, LONG biWidth, LONG biHeight, const GUID* psubtype ) { int i; DWORD* pdwBitf; HRESULT hr = E_FAIL; pbiOut->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pbiOut->bmiHeader.biWidth = biWidth; pbiOut->bmiHeader.biHeight = biHeight; pbiOut->bmiHeader.biPlanes = 1; if ( IsEqualGUID( psubtype, &MEDIASUBTYPE_RGB8 ) ) { pbiOut->bmiHeader.biBitCount = 8; for ( i = 0; i < 256; i++ ) { pbiOut->bmiColors[i].rgbRed = ((i>>5)&7)*255/7; pbiOut->bmiColors[i].rgbGreen = ((i>>2)&7)*255/7; pbiOut->bmiColors[i].rgbBlue = (i&3)*255/3; } hr = S_OK; } if ( IsEqualGUID( psubtype, &MEDIASUBTYPE_RGB555 ) ) { pbiOut->bmiHeader.biBitCount = 16; hr = S_OK; } if ( IsEqualGUID( psubtype, &MEDIASUBTYPE_RGB565 ) ) { pbiOut->bmiHeader.biBitCount = 16; pbiOut->bmiHeader.biCompression = 3; pdwBitf = (DWORD*)(&pbiOut->bmiColors[0]); pdwBitf[0] = 0xf800; pdwBitf[1] = 0x07e0; pdwBitf[2] = 0x001f; hr = S_OK; } if ( IsEqualGUID( psubtype, &MEDIASUBTYPE_RGB24 ) ) { pbiOut->bmiHeader.biBitCount = 24; hr = S_OK; } if ( IsEqualGUID( psubtype, &MEDIASUBTYPE_RGB32 ) ) { pbiOut->bmiHeader.biBitCount = 32; hr = S_OK; } pbiOut->bmiHeader.biSizeImage = DIBSIZE(pbiOut->bmiHeader); return hr; } static HRESULT ColorConv_Init( CTransformBaseImpl* pImpl ) { CColorConvImpl* This = pImpl->m_pUserData; if ( This != NULL ) return NOERROR; This = (CColorConvImpl*)QUARTZ_AllocMem( sizeof(CColorConvImpl) ); if ( This == NULL ) return E_OUTOFMEMORY; ZeroMemory( This, sizeof(CColorConvImpl) ); pImpl->m_pUserData = This; /* construct */ This->m_pBlt = NULL; This->m_pmtConv = NULL; This->m_cConv = 0; return NOERROR; } static HRESULT ColorConv_Cleanup( CTransformBaseImpl* pImpl ) { CColorConvImpl* This = pImpl->m_pUserData; if ( This == NULL ) return NOERROR; /* destruct */ ColorConv_FreeOutTypes(This); QUARTZ_FreeMem( This ); pImpl->m_pUserData = NULL; return NOERROR; } static HRESULT ColorConv_CheckMediaType( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut ) { CColorConvImpl* This = pImpl->m_pUserData; BITMAPINFOHEADER* pbiIn = NULL; BITMAPINFOHEADER* pbiOut = NULL; HRESULT hr; GUID stIn, stOut; const struct BltHandler* phandler; TRACE("(%p)\n",This); if ( This == NULL ) return E_UNEXPECTED; if ( !IsEqualGUID( &pmtIn->majortype, &MEDIATYPE_Video ) ) return E_FAIL; if ( !IsEqualGUID( &pmtIn->formattype, &FORMAT_VideoInfo ) ) return E_FAIL; pbiIn = (&((VIDEOINFOHEADER*)pmtIn->pbFormat)->bmiHeader); if ( pbiIn->biCompression != 0 && pbiIn->biCompression != 3 ) return E_FAIL; hr = QUARTZ_MediaSubType_FromBitmap( &stIn, pbiIn ); if ( hr != S_OK || !IsEqualGUID( &pmtIn->subtype, &stIn ) ) return E_FAIL; if ( pmtOut != NULL ) { if ( !IsEqualGUID( &pmtOut->majortype, &MEDIATYPE_Video ) ) return E_FAIL; if ( !IsEqualGUID( &pmtOut->formattype, &FORMAT_VideoInfo ) ) return E_FAIL; pbiOut = (&((VIDEOINFOHEADER*)pmtOut->pbFormat)->bmiHeader); if ( pbiOut->biCompression != 0 && pbiOut->biCompression != 3 ) return E_FAIL; hr = QUARTZ_MediaSubType_FromBitmap( &stOut, pbiOut ); if ( hr != S_OK || !IsEqualGUID( &pmtOut->subtype, &stOut ) ) return E_FAIL; if ( pbiIn->biWidth != pbiOut->biWidth || pbiIn->biHeight != pbiOut->biHeight || pbiIn->biPlanes != 1 || pbiOut->biPlanes != 1 ) return E_FAIL; } phandler = conv_handlers; while ( phandler->psubtypeIn != NULL ) { if ( IsEqualGUID( &pmtIn->subtype, phandler->psubtypeIn ) ) { if ( pmtOut == NULL ) return S_OK; if ( IsEqualGUID( &pmtOut->subtype, phandler->psubtypeOut ) ) return S_OK; } phandler ++; } return E_FAIL; } static HRESULT ColorConv_GetOutputTypes( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE** ppmtAcceptTypes, ULONG* pcAcceptTypes ) { CColorConvImpl* This = pImpl->m_pUserData; HRESULT hr; const struct BltHandler* phandler; DWORD cConv; BITMAPINFOHEADER* pbiIn = NULL; BITMAPINFOHEADER* pbiOut = NULL; TRACE("(%p)\n",This); if ( This == NULL ) return E_UNEXPECTED; hr = ColorConv_CheckMediaType( pImpl, pmtIn, NULL ); if ( FAILED(hr) ) return hr; pbiIn = (&((VIDEOINFOHEADER*)pmtIn->pbFormat)->bmiHeader); ColorConv_FreeOutTypes(This); cConv = 0; phandler = conv_handlers; while ( phandler->psubtypeIn != NULL ) { if ( IsEqualGUID( &pmtIn->subtype, phandler->psubtypeIn ) ) cConv ++; phandler ++; } This->m_cConv = cConv; This->m_pmtConv = (AM_MEDIA_TYPE*)QUARTZ_AllocMem( sizeof(AM_MEDIA_TYPE) * cConv ); if ( This->m_pmtConv == NULL ) return E_OUTOFMEMORY; ZeroMemory( This->m_pmtConv, sizeof(AM_MEDIA_TYPE) * cConv ); cConv = 0; phandler = conv_handlers; while ( phandler->psubtypeIn != NULL ) { if ( IsEqualGUID( &pmtIn->subtype, phandler->psubtypeIn ) ) { memcpy( &This->m_pmtConv[cConv].majortype, &MEDIATYPE_Video, sizeof(GUID) ); memcpy( &This->m_pmtConv[cConv].subtype, phandler->psubtypeOut, sizeof(GUID) ); This->m_pmtConv[cConv].bFixedSizeSamples = 1; This->m_pmtConv[cConv].bTemporalCompression = 0; This->m_pmtConv[cConv].lSampleSize = DIBSIZE(*pbiIn); memcpy( &This->m_pmtConv[cConv].formattype, &FORMAT_VideoInfo, sizeof(GUID) ); This->m_pmtConv[cConv].cbFormat = sizeof(VIDEOINFO); This->m_pmtConv[cConv].pbFormat = (BYTE*)CoTaskMemAlloc( This->m_pmtConv[cConv].cbFormat ); if ( This->m_pmtConv[cConv].pbFormat == NULL ) return E_OUTOFMEMORY; ZeroMemory( This->m_pmtConv[cConv].pbFormat, This->m_pmtConv[cConv].cbFormat ); pbiOut = &(((VIDEOINFOHEADER*)(This->m_pmtConv[cConv].pbFormat))->bmiHeader); hr = ColorConv_FillBitmapInfo( (BITMAPINFO*)pbiOut, pbiIn->biWidth, pbiIn->biHeight, phandler->psubtypeOut ); if ( FAILED(hr) ) return hr; cConv ++; } phandler ++; } *ppmtAcceptTypes = This->m_pmtConv; *pcAcceptTypes = This->m_cConv; return NOERROR; } static HRESULT ColorConv_GetAllocProp( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut, ALLOCATOR_PROPERTIES* pProp, BOOL* pbTransInPlace, BOOL* pbTryToReuseSample ) { CColorConvImpl* This = pImpl->m_pUserData; HRESULT hr; BITMAPINFOHEADER* pbiOut = NULL; TRACE("(%p)\n",This); if ( This == NULL ) return E_UNEXPECTED; hr = ColorConv_CheckMediaType( pImpl, pmtIn, pmtOut ); if ( FAILED(hr) ) return hr; pbiOut = (&((VIDEOINFOHEADER*)pmtOut->pbFormat)->bmiHeader); pProp->cBuffers = 1; pProp->cbBuffer = DIBSIZE(*pbiOut); TRACE("%ldx%ldx%u cbBuffer = %ld\n",pbiOut->biWidth,pbiOut->biHeight,(unsigned)pbiOut->biBitCount,pProp->cbBuffer); return NOERROR; } static HRESULT ColorConv_BeginTransform( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut, BOOL bReuseSample ) { CColorConvImpl* This = pImpl->m_pUserData; HRESULT hr; BITMAPINFOHEADER* pbiIn = NULL; BITMAPINFOHEADER* pbiOut = NULL; const struct BltHandler* phandler; TRACE("(%p)\n",This); if ( This == NULL ) return E_UNEXPECTED; hr = ColorConv_CheckMediaType( pImpl, pmtIn, pmtOut ); if ( FAILED(hr) ) return hr; pbiIn = (&((VIDEOINFOHEADER*)pmtIn->pbFormat)->bmiHeader); pbiOut = (&((VIDEOINFOHEADER*)pmtOut->pbFormat)->bmiHeader); This->pitchIn = DIBWIDTHBYTES(*pbiIn); This->pitchOut = DIBWIDTHBYTES(*pbiOut); This->m_pBlt = NULL; phandler = conv_handlers; while ( phandler->psubtypeIn != NULL ) { if ( IsEqualGUID( &pmtIn->subtype, phandler->psubtypeIn ) ) { if ( IsEqualGUID( &pmtOut->subtype, phandler->psubtypeOut ) ) { This->m_pBlt = phandler->pBlt; return S_OK; } } phandler ++; } return E_FAIL; } static HRESULT ColorConv_Transform( CTransformBaseImpl* pImpl, IMediaSample* pSampIn, IMediaSample* pSampOut ) { CColorConvImpl* This = pImpl->m_pUserData; BYTE* pDataIn = NULL; BYTE* pDataOut = NULL; BITMAPINFO* pbiIn; BITMAPINFO* pbiOut; HRESULT hr; if ( This == NULL ) return E_UNEXPECTED; hr = IMediaSample_GetPointer( pSampIn, &pDataIn ); if ( FAILED(hr) ) return hr; hr = IMediaSample_GetPointer( pSampOut, &pDataOut ); if ( FAILED(hr) ) return hr; if ( This->m_pBlt != NULL ) { pbiIn = (BITMAPINFO*)&(((VIDEOINFOHEADER*)pImpl->pInPin->pin.pmtConn->pbFormat)->bmiHeader); pbiOut = (BITMAPINFO*)&(((VIDEOINFOHEADER*)pImpl->pOutPin->pin.pmtConn->pbFormat)->bmiHeader); This->m_pBlt( pDataOut, This->pitchOut, pDataIn, This->pitchIn, pbiIn->bmiHeader.biWidth, abs(pbiIn->bmiHeader.biHeight), &pbiIn->bmiColors[0], pbiIn->bmiHeader.biClrUsed ); hr = IMediaSample_SetActualDataLength(pSampOut,DIBSIZE(pbiOut->bmiHeader)); if ( FAILED(hr) ) return hr; } return NOERROR; } static HRESULT ColorConv_EndTransform( CTransformBaseImpl* pImpl ) { CColorConvImpl* This = pImpl->m_pUserData; if ( This == NULL ) return E_UNEXPECTED; This->m_pBlt = NULL; return NOERROR; } static const TransformBaseHandlers transhandlers = { ColorConv_Init, ColorConv_Cleanup, ColorConv_CheckMediaType, ColorConv_GetOutputTypes, ColorConv_GetAllocProp, ColorConv_BeginTransform, ColorConv_Transform, ColorConv_EndTransform, }; HRESULT QUARTZ_CreateColour(IUnknown* punkOuter,void** ppobj) { return QUARTZ_CreateTransformBase( punkOuter,ppobj, &CLSID_Colour, ColorConv_FilterName, NULL, NULL, &transhandlers ); }