HRESULT CCINVideoDecompressor::GetMediaType( int iPosition, CMediaType *pMediaType ) { CAutoLock lock(m_pLock); // Check and validate the pointer CheckPointer(pMediaType, E_POINTER); ValidateWritePtr(pMediaType, sizeof(CMediaType)); // At this time we should have the format block if (!m_pFormat) return E_UNEXPECTED; if (iPosition < 0) return E_INVALIDARG; else if (iPosition > 0) return VFW_S_NO_MORE_ITEMS; else { pMediaType->InitMediaType(); // Is it needed ??? // Allocate the video info block VIDEOINFO *pVideoInfo = (VIDEOINFO*)pMediaType->AllocFormatBuffer(sizeof(VIDEOINFO)); if (pVideoInfo == NULL) return E_OUTOFMEMORY; // Prepare the video info block ZeroMemory(pVideoInfo, sizeof(VIDEOINFO)); SetRectEmpty(&pVideoInfo->rcSource); SetRectEmpty(&pVideoInfo->rcTarget); pVideoInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pVideoInfo->bmiHeader.biWidth = (LONG)m_pFormat->dwVideoWidth; pVideoInfo->bmiHeader.biHeight = -(LONG)m_pFormat->dwVideoHeight; pVideoInfo->bmiHeader.biPlanes = 1; pVideoInfo->bmiHeader.biBitCount = 8; pVideoInfo->bmiHeader.biCompression = BI_RGB; pVideoInfo->bmiHeader.biSizeImage = GetBitmapSize(&pVideoInfo->bmiHeader); pVideoInfo->bmiHeader.biXPelsPerMeter = 0; pVideoInfo->bmiHeader.biYPelsPerMeter = 0; pVideoInfo->bmiHeader.biClrUsed = 256; pVideoInfo->bmiHeader.biClrImportant = 0; pVideoInfo->dwBitRate = pVideoInfo->bmiHeader.biSizeImage * 8 * CIN_FPS; pVideoInfo->dwBitErrorRate = 0; pVideoInfo->AvgTimePerFrame = UNITS / CIN_FPS; // Set media type fields pMediaType->SetType(&MEDIATYPE_Video); pMediaType->SetSubtype(&MEDIASUBTYPE_RGB8); pMediaType->SetSampleSize(pVideoInfo->bmiHeader.biSizeImage); pMediaType->SetTemporalCompression(FALSE); pMediaType->SetFormatType(&FORMAT_VideoInfo); } return S_OK; }
STDMETHODIMP CMVEADPCMDecompressor::GetPages(CAUUID *pPages) { // Check and validate the pointer CheckPointer(pPages, E_POINTER); ValidateWritePtr(pPages, sizeof(CAUUID)); // Fill in the counted array structure pPages->cElems = 1; pPages->pElems = (GUID*)CoTaskMemAlloc(sizeof(GUID)); if (pPages->pElems == NULL) return E_OUTOFMEMORY; pPages->pElems[0] = CLSID_MVEADPCMDecompressorPage; return NOERROR; }
STDMETHODIMP CFSTSplitterFilter::GetPages(CAUUID *pPages) { // Check and validate the pointer CheckPointer(pPages, E_POINTER); ValidateWritePtr(pPages, sizeof(CAUUID)); // Fill in the counted array structure pPages->cElems = 2; pPages->pElems = (GUID*)CoTaskMemAlloc(2 * sizeof(GUID)); if (pPages->pElems == NULL) return E_OUTOFMEMORY; pPages->pElems[0] = CLSID_FSTSplitterPage; pPages->pElems[1] = CLSID_BaseParserPage; return NOERROR; }
HRESULT CMVEADPCMDecompressor::GetMediaType( int iPosition, CMediaType *pMediaType ) { CAutoLock lock(m_pLock); // Check and validate the pointer CheckPointer(pMediaType, E_POINTER); ValidateWritePtr(pMediaType, sizeof(CMediaType)); // At this time we should have the format block if (!m_pFormat) return E_UNEXPECTED; if (iPosition < 0) return E_INVALIDARG; else if (iPosition > 0) return VFW_S_NO_MORE_ITEMS; else { // Prepare the format block WAVEFORMATEX wfex = {0}; wfex.wFormatTag = WAVE_FORMAT_PCM; wfex.nChannels = (m_pFormat->wFlags & MVE_AUDIO_STEREO) ? 2 : 1; wfex.nSamplesPerSec = m_pFormat->wSampleRate; wfex.wBitsPerSample = (m_pFormat->wFlags & MVE_AUDIO_16BIT) ? 16 : 8; wfex.nBlockAlign = (wfex.nChannels * wfex.wBitsPerSample) / 8; wfex.nAvgBytesPerSec = wfex.nSamplesPerSec * wfex.nBlockAlign; wfex.cbSize = 0; // We support the only media type pMediaType->InitMediaType(); // Is it needed ??? pMediaType->SetType(&MEDIATYPE_Audio); // Audio stream pMediaType->SetSubtype(&MEDIASUBTYPE_PCM); // PCM audio pMediaType->SetSampleSize(wfex.nBlockAlign); // Sample size from the format pMediaType->SetTemporalCompression(FALSE); // No temporal compression pMediaType->SetFormatType(&FORMAT_WaveFormatEx); // WAVEFORMATEX pMediaType->SetFormat((BYTE*)&wfex, sizeof(wfex)); } return S_OK; }
HRESULT CFSTSplitterFilter::GetInputType(int iPosition, CMediaType *pMediaType) { // Check and validate the pointer CheckPointer(pMediaType, E_POINTER); ValidateWritePtr(pMediaType, sizeof(CMediaType)); if (iPosition < 0) return E_INVALIDARG; else if (iPosition > 0) return VFW_S_NO_MORE_ITEMS; else { // We support the only media type pMediaType->InitMediaType(); // Is it needed ??? pMediaType->SetType(&MEDIATYPE_Stream); // Byte stream pMediaType->SetSubtype(&MEDIASUBTYPE_FST); // From FST file pMediaType->SetVariableSize(); // Variable size samples pMediaType->SetTemporalCompression(FALSE); // No temporal compression pMediaType->SetFormatType(&FORMAT_None); // Is it needed ??? } return S_OK; }
HRESULT CFSTChunkParser::ParseChunkHeader( LONGLONG llStartPosition, BYTE *pbHeader, LONG *plDataSize ) { // Check and validate the pointer CheckPointer(plDataSize, E_POINTER); ValidateWritePtr(plDataSize, sizeof(LONG)); m_pPin = NULL; m_pSample = NULL; m_rtDelta = 0; m_llDelta = 0; // Adjust data start position to video/audio stream start llStartPosition -= sizeof(FST_HEADER) + m_nVideoFrames * sizeof(FST_FRAME_ENTRY); // Walk frame entries table until data start position falls // into the frame data range DWORD iFrame = 0; for (iFrame = 0; iFrame < m_nVideoFrames; iFrame++) { DWORD cbFrameData = m_pFrameTable[iFrame].cbImage + m_pFrameTable[iFrame].cbSound; if (llStartPosition < cbFrameData) break; llStartPosition -= cbFrameData; }; // At this point we should be either at the start of image data // or at the start of the sound data and nowhere else if ( (llStartPosition != 0) && (llStartPosition != m_pFrameTable[iFrame].cbImage) ) return E_UNEXPECTED; if (llStartPosition == 0) { // ---- Video data ---- *plDataSize = m_pFrameTable[iFrame].cbImage; m_pPin = m_ppOutputPin[0]; // We'll be dealing with video output pin // Check if we have correct video format parameters if (m_nFramesPerSecond == 0) return E_UNEXPECTED; m_rtDelta = UNITS / m_nFramesPerSecond; m_llDelta = 1; } else if (llStartPosition == m_pFrameTable[iFrame].cbImage) { // ---- Audio data ---- *plDataSize = m_pFrameTable[iFrame].cbSound; ASSERT(m_ppOutputPin[1]); // There should be the audio output pin m_pPin = m_ppOutputPin[1]; // We'll be dealing with audio output pin // Check if we have correct wave format parameters if ( (m_nSampleSize == 0) || (m_nAvgBytesPerSec == 0) ) return E_UNEXPECTED; // Calculate the stream and media deltas m_rtDelta = ((REFERENCE_TIME)(*plDataSize) * UNITS) / m_nAvgBytesPerSec; m_llDelta = (LONGLONG)(*plDataSize) / m_nSampleSize; } // We cannot find appropriate output pin for this chunk -- // just ignore it (and return no error) if (!m_pPin) { m_pSample = NULL; return NOERROR; } // If the output pin is not connected, just quit with no error. // There might be other output pins which are connected and // delivering samples -- we should not hamper their activities if (!m_pPin->IsConnected()) { m_pSample = NULL; return NOERROR; } // Get an empty sample from the output pin HRESULT hr = m_pPin->GetDeliveryBuffer(&m_pSample, NULL, NULL, 0); if (FAILED(hr)) { m_pSample = NULL; return hr; } hr = m_pSample->SetActualDataLength(0); if (FAILED(hr)) { m_pSample->Release(); m_pSample = NULL; return hr; } return NOERROR; }
STDMETHODIMP CEnumMediaTypes::Next(ULONG cMediaTypes, // place this many types... AM_MEDIA_TYPE **ppMediaTypes, // ...in this array ULONG *pcFetched) // actual count passed { CheckPointer(ppMediaTypes,E_POINTER); ValidateReadWritePtr(ppMediaTypes,cMediaTypes * sizeof(AM_MEDIA_TYPE *)); /* Check we are still in sync with the pin */ if (AreWeOutOfSync() == TRUE) { return VFW_E_ENUM_OUT_OF_SYNC; } if (pcFetched!=NULL) { ValidateWritePtr(pcFetched, sizeof(ULONG)); *pcFetched = 0; // default unless we succeed } // now check that the parameter is valid else if (cMediaTypes>1) { // pcFetched == NULL return E_INVALIDARG; } ULONG cFetched = 0; // increment as we get each one. /* Return each media type by asking the filter for them in turn - If we have an error code retured to us while we are retrieving a media type we assume that our internal state is stale with respect to the filter (for example the window size changing) so we return VFW_E_ENUM_OUT_OF_SYNC */ while (cMediaTypes) { CMediaType cmt; HRESULT hr = m_pPin->GetMediaType(m_Position++, &cmt); if (S_OK != hr) { break; } /* We now have a CMediaType object that contains the next media type but when we assign it to the array position we CANNOT just assign the AM_MEDIA_TYPE structure because as soon as the object goes out of scope it will delete the memory we have just copied. The function we use is CreateMediaType which allocates a task memory block */ /* Transfer across the format block manually to save an allocate and free on the format block and generally go faster */ *ppMediaTypes = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); if (*ppMediaTypes == NULL) { break; } /* Do a regular copy */ **ppMediaTypes = (AM_MEDIA_TYPE)cmt; /* Make sure the destructor doesn't free these */ cmt.pbFormat = NULL; cmt.cbFormat = NULL; cmt.pUnk = NULL; ppMediaTypes++; cFetched++; cMediaTypes--; } if (pcFetched!=NULL) { *pcFetched = cFetched; } return ( cMediaTypes==0 ? NOERROR : S_FALSE ); }
STDMETHODIMP CEnumPins::Next(ULONG cPins, // place this many pins... IPin **ppPins, // ...in this array ULONG *pcFetched) // actual count passed returned here { CheckPointer(ppPins,E_POINTER); ValidateReadWritePtr(ppPins,cPins * sizeof(IPin *)); ASSERT(ppPins); if (pcFetched!=NULL) { ValidateWritePtr(pcFetched, sizeof(ULONG)); *pcFetched = 0; // default unless we succeed } // now check that the parameter is valid else if (cPins>1) { // pcFetched == NULL return E_INVALIDARG; } ULONG cFetched = 0; // increment as we get each one. /* Check we are still in sync with the filter */ if (AreWeOutOfSync() == TRUE) { // If we are out of sync, we should refresh the enumerator. // This will reset the position and update the other members, but // will not clear cache of pins we have already returned. Refresh(); } /* Calculate the number of available pins */ int cRealPins = min(m_PinCount - m_Position, (int) cPins); if (cRealPins == 0) { return S_FALSE; } /* Return each pin interface NOTE GetPin returns CBasePin * not addrefed so we must QI for the IPin (which increments its reference count) If while we are retrieving a pin from the filter an error occurs we assume that our internal state is stale with respect to the filter (for example someone has deleted a pin) so we return VFW_E_ENUM_OUT_OF_SYNC */ while (cRealPins && (m_PinCount - m_Position)) { /* Get the next pin object from the filter */ CBasePin *pPin = m_pFilter->GetPin(m_Position++); if (pPin == NULL) { // If this happend, and it's not the first time through, then we've got a problem, // since we should really go back and release the iPins, which we have previously // AddRef'ed. ASSERT( cFetched==0 ); return VFW_E_ENUM_OUT_OF_SYNC; } /* We only want to return this pin, if it is not in our cache */ if (0 == m_PinCache.Find(pPin)) { /* From the object get an IPin interface */ *ppPins = pPin; pPin->AddRef(); cFetched++; ppPins++; m_PinCache.AddTail(pPin); cRealPins--; } } if (pcFetched!=NULL) { *pcFetched = cFetched; } return (cPins==cFetched ? NOERROR : S_FALSE); }