| /* |
| * Implements IEnumMediaTypes and helper functions. (internal) |
| * |
| * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp> |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| #include "config.h" |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "wingdi.h" |
| #include "winuser.h" |
| #include "winerror.h" |
| #include "mmsystem.h" |
| #include "strmif.h" |
| #include "vfwmsgs.h" |
| #include "uuids.h" |
| |
| #include "wine/debug.h" |
| WINE_DEFAULT_DEBUG_CHANNEL(quartz); |
| |
| #include "quartz_private.h" |
| #include "mtype.h" |
| #include "iunk.h" |
| |
| |
| /****************************************************************************/ |
| |
| |
| |
| HRESULT QUARTZ_MediaType_Copy( |
| AM_MEDIA_TYPE* pmtDst, |
| const AM_MEDIA_TYPE* pmtSrc ) |
| { |
| memcpy( &pmtDst->majortype, &pmtSrc->majortype, sizeof(GUID) ); |
| memcpy( &pmtDst->subtype, &pmtSrc->subtype, sizeof(GUID) ); |
| pmtDst->bFixedSizeSamples = pmtSrc->bFixedSizeSamples; |
| pmtDst->bTemporalCompression = pmtSrc->bTemporalCompression; |
| pmtDst->lSampleSize = pmtSrc->lSampleSize; |
| memcpy( &pmtDst->formattype, &pmtSrc->formattype, sizeof(GUID) ); |
| pmtDst->pUnk = NULL; |
| pmtDst->cbFormat = pmtSrc->cbFormat; |
| pmtDst->pbFormat = NULL; |
| |
| if ( pmtSrc->pbFormat != NULL && pmtSrc->cbFormat != 0 ) |
| { |
| pmtDst->pbFormat = (BYTE*)CoTaskMemAlloc( pmtSrc->cbFormat ); |
| if ( pmtDst->pbFormat == NULL ) |
| { |
| CoTaskMemFree( pmtDst ); |
| return E_OUTOFMEMORY; |
| } |
| memcpy( pmtDst->pbFormat, pmtSrc->pbFormat, pmtSrc->cbFormat ); |
| } |
| |
| if ( pmtSrc->pUnk != NULL ) |
| { |
| pmtDst->pUnk = pmtSrc->pUnk; |
| IUnknown_AddRef( pmtSrc->pUnk ); |
| } |
| |
| return S_OK; |
| } |
| |
| void QUARTZ_MediaType_Free( |
| AM_MEDIA_TYPE* pmt ) |
| { |
| if ( pmt->pUnk != NULL ) |
| { |
| IUnknown_Release( pmt->pUnk ); |
| pmt->pUnk = NULL; |
| } |
| if ( pmt->pbFormat != NULL ) |
| { |
| CoTaskMemFree( pmt->pbFormat ); |
| pmt->cbFormat = 0; |
| pmt->pbFormat = NULL; |
| } |
| } |
| |
| AM_MEDIA_TYPE* QUARTZ_MediaType_Duplicate( |
| const AM_MEDIA_TYPE* pmtSrc ) |
| { |
| AM_MEDIA_TYPE* pmtDup; |
| |
| pmtDup = (AM_MEDIA_TYPE*)CoTaskMemAlloc( sizeof(AM_MEDIA_TYPE) ); |
| if ( pmtDup == NULL ) |
| return NULL; |
| if ( QUARTZ_MediaType_Copy( pmtDup, pmtSrc ) != S_OK ) |
| { |
| CoTaskMemFree( pmtDup ); |
| return NULL; |
| } |
| |
| return pmtDup; |
| } |
| |
| void QUARTZ_MediaType_Destroy( |
| AM_MEDIA_TYPE* pmt ) |
| { |
| QUARTZ_MediaType_Free( pmt ); |
| CoTaskMemFree( pmt ); |
| } |
| |
| void QUARTZ_MediaSubType_FromFourCC( |
| GUID* psubtype, DWORD dwFourCC ) |
| { |
| TRACE( "FourCC %c%c%c%c\n", |
| (int)(dwFourCC>> 0)&0xff, |
| (int)(dwFourCC>> 8)&0xff, |
| (int)(dwFourCC>>16)&0xff, |
| (int)(dwFourCC>>24)&0xff ); |
| memcpy( psubtype, &MEDIASUBTYPE_PCM, sizeof(GUID) ); |
| psubtype->Data1 = dwFourCC; |
| } |
| |
| BOOL QUARTZ_MediaSubType_IsFourCC( |
| const GUID* psubtype ) |
| { |
| GUID guidTemp; |
| |
| QUARTZ_MediaSubType_FromFourCC( |
| &guidTemp, psubtype->Data1 ); |
| return IsEqualGUID( psubtype, &guidTemp ); |
| } |
| |
| HRESULT QUARTZ_MediaSubType_FromBitmap( |
| GUID* psubtype, const BITMAPINFOHEADER* pbi ) |
| { |
| HRESULT hr; |
| DWORD* pdwBitf; |
| |
| if ( (pbi->biCompression & 0xffff0000) != 0 ) |
| return S_FALSE; |
| |
| if ( pbi->biWidth <= 0 || pbi->biHeight == 0 ) |
| return E_FAIL; |
| |
| hr = E_FAIL; |
| switch ( pbi->biCompression ) |
| { |
| case 0: |
| if ( pbi->biPlanes != 1 ) |
| break; |
| switch ( pbi->biBitCount ) |
| { |
| case 1: |
| memcpy( psubtype, &MEDIASUBTYPE_RGB1, sizeof(GUID) ); |
| hr = S_OK; |
| break; |
| case 4: |
| memcpy( psubtype, &MEDIASUBTYPE_RGB4, sizeof(GUID) ); |
| hr = S_OK; |
| break; |
| case 8: |
| memcpy( psubtype, &MEDIASUBTYPE_RGB8, sizeof(GUID) ); |
| hr = S_OK; |
| break; |
| case 16: |
| memcpy( psubtype, &MEDIASUBTYPE_RGB555, sizeof(GUID) ); |
| hr = S_OK; |
| break; |
| case 24: |
| memcpy( psubtype, &MEDIASUBTYPE_RGB24, sizeof(GUID) ); |
| hr = S_OK; |
| break; |
| case 32: |
| memcpy( psubtype, &MEDIASUBTYPE_RGB32, sizeof(GUID) ); |
| hr = S_OK; |
| break; |
| } |
| break; |
| case 1: |
| if ( pbi->biPlanes == 1 && pbi->biHeight > 0 && |
| pbi->biBitCount == 8 ) |
| { |
| QUARTZ_MediaSubType_FromFourCC( psubtype, 1 ); |
| hr = S_OK; |
| } |
| break; |
| case 2: |
| if ( pbi->biPlanes == 1 && pbi->biHeight > 0 && |
| pbi->biBitCount == 4 ) |
| { |
| QUARTZ_MediaSubType_FromFourCC( psubtype, 2 ); |
| hr = S_OK; |
| } |
| break; |
| case 3: |
| if ( pbi->biPlanes != 1 ) |
| break; |
| pdwBitf = (DWORD*)( (BYTE*)pbi + sizeof(BITMAPINFOHEADER) ); |
| switch ( pbi->biBitCount ) |
| { |
| case 16: |
| if ( pdwBitf[0] == 0x7c00 && |
| pdwBitf[1] == 0x03e0 && |
| pdwBitf[2] == 0x001f ) |
| { |
| memcpy( psubtype, &MEDIASUBTYPE_RGB555, sizeof(GUID) ); |
| hr = S_OK; |
| } |
| if ( pdwBitf[0] == 0xf800 && |
| pdwBitf[1] == 0x07e0 && |
| pdwBitf[2] == 0x001f ) |
| { |
| memcpy( psubtype, &MEDIASUBTYPE_RGB565, sizeof(GUID) ); |
| hr = S_OK; |
| } |
| break; |
| case 32: |
| if ( pdwBitf[0] == 0x00ff0000 && |
| pdwBitf[1] == 0x0000ff00 && |
| pdwBitf[2] == 0x000000ff ) |
| { |
| memcpy( psubtype, &MEDIASUBTYPE_RGB32, sizeof(GUID) ); |
| hr = S_OK; |
| } |
| break; |
| } |
| break; |
| } |
| |
| return hr; |
| } |
| |
| void QUARTZ_PatchBitmapInfoHeader( BITMAPINFOHEADER* pbi ) |
| { |
| switch ( pbi->biCompression ) |
| { |
| case mmioFOURCC('R','G','B',' '): |
| pbi->biCompression = 0; |
| break; |
| case mmioFOURCC('R','L','E',' '): |
| case mmioFOURCC('M','R','L','E'): |
| case mmioFOURCC('R','L','E','8'): |
| case mmioFOURCC('R','L','E','4'): |
| if ( pbi->biBitCount == 4 ) |
| pbi->biCompression = 2; |
| else |
| pbi->biCompression = 1; |
| break; |
| } |
| } |
| |
| BOOL QUARTZ_BitmapHasFixedSample( const BITMAPINFOHEADER* pbi ) |
| { |
| switch ( pbi->biCompression ) |
| { |
| case 0: |
| case 3: |
| case mmioFOURCC('I','4','2','0'): |
| case mmioFOURCC('I','Y','U','V'): |
| case mmioFOURCC('Y','U','Y','V'): |
| case mmioFOURCC('Y','V','U','9'): |
| case mmioFOURCC('Y','4','1','1'): |
| case mmioFOURCC('Y','4','1','P'): |
| case mmioFOURCC('Y','U','Y','2'): |
| case mmioFOURCC('Y','V','Y','U'): |
| case mmioFOURCC('U','Y','V','Y'): |
| case mmioFOURCC('Y','2','1','1'): |
| case mmioFOURCC('Y','V','1','2'): |
| return TRUE; |
| } |
| |
| return FALSE; |
| } |
| |
| |
| /****************************************************************************/ |
| |
| typedef struct IEnumMediaTypesImpl |
| { |
| ICOM_VFIELD(IEnumMediaTypes); |
| } IEnumMediaTypesImpl; |
| |
| typedef struct |
| { |
| QUARTZ_IUnkImpl unk; |
| IEnumMediaTypesImpl enummtype; |
| struct QUARTZ_IFEntry IFEntries[1]; |
| CRITICAL_SECTION cs; |
| AM_MEDIA_TYPE* pTypes; |
| ULONG cTypes; |
| ULONG cCur; |
| } CEnumMediaTypes; |
| |
| #define CEnumMediaTypes_THIS(iface,member) CEnumMediaTypes* This = ((CEnumMediaTypes*)(((char*)iface)-offsetof(CEnumMediaTypes,member))) |
| |
| |
| |
| static HRESULT WINAPI |
| IEnumMediaTypes_fnQueryInterface(IEnumMediaTypes* iface,REFIID riid,void** ppobj) |
| { |
| CEnumMediaTypes_THIS(iface,enummtype); |
| |
| TRACE("(%p)->()\n",This); |
| |
| return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj); |
| } |
| |
| static ULONG WINAPI |
| IEnumMediaTypes_fnAddRef(IEnumMediaTypes* iface) |
| { |
| CEnumMediaTypes_THIS(iface,enummtype); |
| |
| TRACE("(%p)->()\n",This); |
| |
| return IUnknown_AddRef(This->unk.punkControl); |
| } |
| |
| static ULONG WINAPI |
| IEnumMediaTypes_fnRelease(IEnumMediaTypes* iface) |
| { |
| CEnumMediaTypes_THIS(iface,enummtype); |
| |
| TRACE("(%p)->()\n",This); |
| |
| return IUnknown_Release(This->unk.punkControl); |
| } |
| |
| static HRESULT WINAPI |
| IEnumMediaTypes_fnNext(IEnumMediaTypes* iface,ULONG cReq,AM_MEDIA_TYPE** ppmtype,ULONG* pcFetched) |
| { |
| CEnumMediaTypes_THIS(iface,enummtype); |
| HRESULT hr; |
| ULONG cFetched; |
| |
| TRACE("(%p)->(%lu,%p,%p)\n",This,cReq,ppmtype,pcFetched); |
| |
| if ( pcFetched == NULL && cReq > 1 ) |
| return E_INVALIDARG; |
| if ( ppmtype == NULL ) |
| return E_POINTER; |
| |
| EnterCriticalSection( &This->cs ); |
| |
| hr = NOERROR; |
| cFetched = 0; |
| while ( cReq > 0 ) |
| { |
| if ( This->cCur >= This->cTypes ) |
| { |
| hr = S_FALSE; |
| break; |
| } |
| ppmtype[ cFetched ] = |
| QUARTZ_MediaType_Duplicate( &This->pTypes[ This->cCur ] ); |
| if ( ppmtype[ cFetched ] == NULL ) |
| { |
| hr = E_OUTOFMEMORY; |
| while ( cFetched > 0 ) |
| { |
| cFetched --; |
| QUARTZ_MediaType_Destroy( ppmtype[ cFetched ] ); |
| } |
| break; |
| } |
| |
| cFetched ++; |
| |
| This->cCur ++; |
| cReq --; |
| } |
| |
| LeaveCriticalSection( &This->cs ); |
| |
| if ( pcFetched != NULL ) |
| *pcFetched = cFetched; |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI |
| IEnumMediaTypes_fnSkip(IEnumMediaTypes* iface,ULONG cSkip) |
| { |
| CEnumMediaTypes_THIS(iface,enummtype); |
| HRESULT hr; |
| |
| TRACE("(%p)->()\n",This); |
| |
| EnterCriticalSection( &This->cs ); |
| |
| hr = NOERROR; |
| while ( cSkip > 0 ) |
| { |
| if ( This->cCur >= This->cTypes ) |
| { |
| hr = S_FALSE; |
| break; |
| } |
| This->cCur ++; |
| cSkip --; |
| } |
| |
| LeaveCriticalSection( &This->cs ); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI |
| IEnumMediaTypes_fnReset(IEnumMediaTypes* iface) |
| { |
| CEnumMediaTypes_THIS(iface,enummtype); |
| |
| TRACE("(%p)->()\n",This); |
| |
| EnterCriticalSection( &This->cs ); |
| |
| This->cCur = 0; |
| |
| LeaveCriticalSection( &This->cs ); |
| |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI |
| IEnumMediaTypes_fnClone(IEnumMediaTypes* iface,IEnumMediaTypes** ppobj) |
| { |
| CEnumMediaTypes_THIS(iface,enummtype); |
| HRESULT hr; |
| |
| TRACE("(%p)->()\n",This); |
| |
| if ( ppobj == NULL ) |
| return E_POINTER; |
| |
| EnterCriticalSection( &This->cs ); |
| |
| hr = QUARTZ_CreateEnumMediaTypes( |
| ppobj, |
| This->pTypes, This->cTypes ); |
| if ( SUCCEEDED(hr) ) |
| IEnumMediaTypes_Skip( *ppobj, This->cCur ); |
| |
| LeaveCriticalSection( &This->cs ); |
| |
| return hr; |
| } |
| |
| |
| static ICOM_VTABLE(IEnumMediaTypes) ienummtype = |
| { |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE |
| /* IUnknown fields */ |
| IEnumMediaTypes_fnQueryInterface, |
| IEnumMediaTypes_fnAddRef, |
| IEnumMediaTypes_fnRelease, |
| /* IEnumMediaTypes fields */ |
| IEnumMediaTypes_fnNext, |
| IEnumMediaTypes_fnSkip, |
| IEnumMediaTypes_fnReset, |
| IEnumMediaTypes_fnClone, |
| }; |
| |
| |
| /* can I use offsetof safely? - FIXME? */ |
| static QUARTZ_IFEntry IFEntries[] = |
| { |
| { &IID_IEnumMediaTypes, offsetof(CEnumMediaTypes,enummtype)-offsetof(CEnumMediaTypes,unk) }, |
| }; |
| |
| |
| void QUARTZ_DestroyEnumMediaTypes(IUnknown* punk) |
| { |
| CEnumMediaTypes_THIS(punk,unk); |
| ULONG i; |
| |
| if ( This->pTypes != NULL ) |
| { |
| for ( i = 0; i < This->cTypes; i++ ) |
| QUARTZ_MediaType_Free( &This->pTypes[i] ); |
| QUARTZ_FreeMem( This->pTypes ); |
| } |
| |
| DeleteCriticalSection( &This->cs ); |
| } |
| |
| HRESULT QUARTZ_CreateEnumMediaTypes( |
| IEnumMediaTypes** ppobj, |
| const AM_MEDIA_TYPE* pTypes, ULONG cTypes ) |
| { |
| CEnumMediaTypes* penum; |
| AM_MEDIA_TYPE* pTypesDup = NULL; |
| ULONG i; |
| HRESULT hr; |
| |
| TRACE("(%p,%p,%lu)\n",ppobj,pTypes,cTypes); |
| |
| if ( cTypes > 0 ) |
| { |
| pTypesDup = (AM_MEDIA_TYPE*)QUARTZ_AllocMem( |
| sizeof( AM_MEDIA_TYPE ) * cTypes ); |
| if ( pTypesDup == NULL ) |
| return E_OUTOFMEMORY; |
| |
| i = 0; |
| while ( i < cTypes ) |
| { |
| hr = QUARTZ_MediaType_Copy( &pTypesDup[i], &pTypes[i] ); |
| if ( FAILED(hr) ) |
| { |
| while ( i > 0 ) |
| { |
| i --; |
| QUARTZ_MediaType_Free( &pTypesDup[i] ); |
| } |
| QUARTZ_FreeMem( pTypesDup ); |
| return hr; |
| } |
| |
| i ++; |
| } |
| } |
| |
| penum = (CEnumMediaTypes*)QUARTZ_AllocObj( sizeof(CEnumMediaTypes) ); |
| if ( penum == NULL ) |
| { |
| return E_OUTOFMEMORY; |
| } |
| penum->pTypes = pTypesDup; |
| penum->cTypes = cTypes; |
| penum->cCur = 0; |
| |
| QUARTZ_IUnkInit( &penum->unk, NULL ); |
| ICOM_VTBL(&penum->enummtype) = &ienummtype; |
| |
| penum->unk.pEntries = IFEntries; |
| penum->unk.dwEntries = sizeof(IFEntries)/sizeof(IFEntries[0]); |
| penum->unk.pOnFinalRelease = QUARTZ_DestroyEnumMediaTypes; |
| |
| InitializeCriticalSection( &penum->cs ); |
| |
| *ppobj = (IEnumMediaTypes*)(&penum->enummtype); |
| |
| return S_OK; |
| } |
| |
| |