HRESULT D3DPresentEngine::createVideoSamples(IMFMediaType *format, QList<IMFSample*> &videoSampleQueue) { if (!format) return MF_E_UNEXPECTED; HRESULT hr = S_OK; D3DPRESENT_PARAMETERS pp; IDirect3DSwapChain9 *swapChain = NULL; IMFSample *videoSample = NULL; QMutexLocker locker(&m_mutex); releaseResources(); // Get the swap chain parameters from the media type. hr = getSwapChainPresentParameters(format, &pp); if (FAILED(hr)) goto done; // Create the video samples. for (int i = 0; i < PRESENTER_BUFFER_COUNT; i++) { // Create a new swap chain. hr = m_device->CreateAdditionalSwapChain(&pp, &swapChain); if (FAILED(hr)) goto done; // Create the video sample from the swap chain. hr = createD3DSample(swapChain, &videoSample); if (FAILED(hr)) goto done; // Add it to the list. videoSample->AddRef(); videoSampleQueue.append(videoSample); // Set the swap chain pointer as a custom attribute on the sample. This keeps // a reference count on the swap chain, so that the swap chain is kept alive // for the duration of the sample's lifetime. hr = videoSample->SetUnknown(MFSamplePresenter_SampleSwapChain, swapChain); if (FAILED(hr)) goto done; qt_wmf_safeRelease(&videoSample); qt_wmf_safeRelease(&swapChain); } done: if (FAILED(hr)) releaseResources(); qt_wmf_safeRelease(&swapChain); qt_wmf_safeRelease(&videoSample); return hr; }
HRESULT D3DPresentEngine::CreateVideoSamples( IMFMediaType *pFormat, VideoSampleList& videoSampleQueue ) { if (m_hwnd == NULL) { return MF_E_INVALIDREQUEST; } if (pFormat == NULL) { return MF_E_UNEXPECTED; } HRESULT hr = S_OK; D3DPRESENT_PARAMETERS pp; IDirect3DSwapChain9 *pSwapChain = NULL; // Swap chain IMFSample *pVideoSample = NULL; // Sampl AutoLock lock(m_ObjectLock); ReleaseResources(); // Get the swap chain parameters from the media type. CHECK_HR(hr = GetSwapChainPresentParameters(pFormat, &pp)); if(m_pRenderSurface) { SAFE_RELEASE(m_pRenderSurface); } // Create the video samples. for (int i = 0; i < m_bufferCount; i++) { // Create a new swap chain. CHECK_HR(hr = m_pDevice->CreateAdditionalSwapChain(&pp, &pSwapChain)); // Create the video sample from the swap chain. CHECK_HR(hr = CreateD3DSample(pSwapChain, &pVideoSample)); // Add it to the list. CHECK_HR(hr = videoSampleQueue.InsertBack(pVideoSample)); // Set the swap chain pointer as a custom attribute on the sample. This keeps // a reference count on the swap chain, so that the swap chain is kept alive // for the duration of the sample's lifetime. CHECK_HR(hr = pVideoSample->SetUnknown(MFSamplePresenter_SampleSwapChain, pSwapChain)); SAFE_RELEASE(pVideoSample); SAFE_RELEASE(pSwapChain); } // Let the derived class create any additional D3D resources that it needs. CHECK_HR(hr = OnCreateVideoSamples(pp)); done: if (FAILED(hr)) { ReleaseResources(); } SAFE_RELEASE(pSwapChain); SAFE_RELEASE(pVideoSample); return hr; }
HRESULT WavStream::RequestSample(IUnknown* pToken) { if (m_pSource == NULL) { return E_UNEXPECTED; } HRESULT hr = S_OK; IMFMediaSource *pSource = NULL; IMFSample *pSample = NULL; // Sample to deliver. EnterCriticalSection(&m_critSec); // Check if we are shut down. hr = CheckShutdown(); // Check if we already reached the end of the stream. if (SUCCEEDED(hr)) { if (m_EOS) { hr = MF_E_END_OF_STREAM; } } // Check the source is stopped. // GetState does not hold the source's critical section. Safe to call. if (SUCCEEDED(hr)) { if (m_pSource->GetState() == WavSource::STATE_STOPPED) { hr = MF_E_INVALIDREQUEST; } } if (SUCCEEDED(hr)) { // Create a new audio sample. hr = CreateAudioSample(&pSample); } if (SUCCEEDED(hr)) { // If the caller provided a token, attach it to the sample as // an attribute. // NOTE: If we processed sample requests asynchronously, we would // need to call AddRef on the token and put the token onto a FIFO // queue. See documenation for IMFMediaStream::RequestSample. if (pToken) { hr = pSample->SetUnknown(MFSampleExtension_Token, pToken); } } // If paused, queue the sample for later delivery. Otherwise, deliver the sample now. if (SUCCEEDED(hr)) { if (m_pSource->GetState() == WavSource::STATE_PAUSED) { hr = m_sampleQueue.Queue(pSample); } else { hr = DeliverSample(pSample); } } // Cache a pointer to the source, prior to leaving the critical section. if (SUCCEEDED(hr)) { pSource = m_pSource; pSource->AddRef(); } LeaveCriticalSection(&m_critSec); // We only have one stream, so the end of the stream is also the end of the // presentation. Therefore, when we reach the end of the stream, we need to // queue the end-of-presentation event from the source. Logically we would do // this inside the CheckEndOfStream method. However, we cannot hold the // source's critical section while holding the stream's critical section, at // risk of deadlock. if (SUCCEEDED(hr)) { if (m_EOS) { hr = pSource->QueueEvent(MEEndOfPresentation, GUID_NULL, S_OK, NULL); } } SafeRelease(&pSample); SafeRelease(&pSource); return hr; }
HRESULT MPEG1Stream::DispatchSamples() { HRESULT hr = S_OK; BOOL bNeedData = FALSE; BOOL bEOS = FALSE; IMFSample *pSample = NULL; IUnknown *pToken = NULL; SourceLock lock(m_pSource); // It's possible that an I/O request completed after the source // paused, stopped, or shut down. We should not deliver any samples // unless the source is running. if (m_state != STATE_STARTED) { hr = S_OK; goto done; } // Deliver as many samples as we can. while (!m_Samples.IsEmpty() && !m_Requests.IsEmpty()) { // Pull the next sample from the queue. CHECK_HR(hr = m_Samples.RemoveFront(&pSample)); // Pull the next request token from the queue. Tokens can be NULL. CHECK_HR(hr = m_Requests.RemoveFront(&pToken)); if (pToken) { CHECK_HR(hr = pSample->SetUnknown(MFSampleExtension_Token, pToken)); } CHECK_HR(hr = m_pEventQueue->QueueEventParamUnk(MEMediaSample, GUID_NULL, S_OK, pSample)); SAFE_RELEASE(pSample); SAFE_RELEASE(pToken); } if (m_Samples.IsEmpty() && m_bEOS) { // The sample queue is empty AND we have reached the end of the source stream. // Notify the pipeline by sending the end-of-stream event. CHECK_HR(hr = m_pEventQueue->QueueEventParamVar(MEEndOfStream, GUID_NULL, S_OK, NULL)); // Also notify the source, so that it can send the end-of-presentation event. CHECK_HR(hr = m_pSource->QueueAsyncOperation(SourceOp::OP_END_OF_STREAM)); } else if (NeedsData()) { // The sample queue is empty and the request queue is not empty (and we did not // reach the end of the stream). Ask the source for more data. CHECK_HR(hr = m_pSource->QueueAsyncOperation(SourceOp::OP_REQUEST_DATA)); } done: // If there was an error, queue MEError from the source (except after shutdown). if (FAILED(hr) && (m_state != STATE_SHUTDOWN)) { m_pSource->QueueEvent(MEError, GUID_NULL, hr, NULL); } SAFE_RELEASE(pSample); SAFE_RELEASE(pToken); return S_OK; }
HRESULT PpboxStream::DispatchSamples() { HRESULT hr = S_OK; BOOL bNeedData = FALSE; BOOL bEOS = FALSE; SourceLock lock(m_pSource); // An I/O request can complete after the source is paused, stopped, or // shut down. Do not deliver samples unless the source is running. if (m_state != STATE_STARTED) { return S_OK; } IMFSample *pSample = NULL; IUnknown *pToken = NULL; // Deliver as many samples as we can. while (!m_Samples.IsEmpty() && !m_Requests.IsEmpty()) { // Pull the next sample from the queue. hr = m_Samples.RemoveFront(&pSample); if (FAILED(hr)) { goto done; } // Pull the next request token from the queue. Tokens can be NULL. hr = m_Requests.RemoveFront(&pToken); if (FAILED(hr)) { goto done; } if (pToken) { // Set the token on the sample. hr = pSample->SetUnknown(MFSampleExtension_Token, pToken); if (FAILED(hr)) { goto done; } } // Send an MEMediaSample event with the sample. hr = m_pEventQueue->QueueEventParamUnk( MEMediaSample, GUID_NULL, S_OK, pSample); if (FAILED(hr)) { goto done; } SafeRelease(&pSample); SafeRelease(&pToken); } if (m_Samples.IsEmpty() && m_bEOS) { // The sample queue is empty AND we have reached the end of the source // stream. Notify the pipeline by sending the end-of-stream event. hr = m_pEventQueue->QueueEventParamVar( MEEndOfStream, GUID_NULL, S_OK, NULL); if (FAILED(hr)) { goto done; } // Notify the source. It will send the end-of-presentation event. hr = m_pSource->RequestSample(); if (FAILED(hr)) { goto done; } } else if (NeedsData()) { // The sample queue is empty; the request queue is not empty; and we // have not reached the end of the stream. Ask for more data. hr = m_pSource->RequestSample(); if (FAILED(hr)) { goto done; } } else { hr = S_OK; goto done; } done: if (FAILED(hr) && (m_state != STATE_SHUTDOWN)) { // An error occurred. Send an MEError even from the source, // unless the source is already shut down. m_pSource->QueueEvent(MEError, GUID_NULL, hr, NULL); } SafeRelease(&pSample); SafeRelease(&pToken); return S_OK; }