STDMETHODIMP_(DeviceStreamState) CCustomPin::SetState( _In_ DeviceStreamState State ) { HRESULT hr = S_OK; DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Id:%d Transition into state: %d ", streamId(), State); DeviceStreamState oldState = setPreferredStreamState( State ); if ( oldState != State ) { ComPtr<IMFMediaType> preferredMediaType = nullptr; if (State == DeviceStreamState_Run) { GetMediaTypeAt(0, preferredMediaType.ReleaseAndGetAddressOf()); } setPreferredMediaType(preferredMediaType.Get()); setPreferredStreamState( State ); { // // Notify the device transform manager that we have changed state // ComPtr<IMFMediaEvent> pEvent = nullptr; DMFTCHECKHR_GOTO( MFCreateMediaEvent(METransformInputStreamStateChanged, GUID_NULL, S_OK, NULL, pEvent.ReleaseAndGetAddressOf()), done ); DMFTCHECKHR_GOTO( pEvent->SetUINT32(MF_EVENT_MFT_INPUT_STREAM_ID, streamId()), done ); DMFTCHECKHR_GOTO( Parent()->QueueEvent(pEvent.Get()), done ); } // // Wait to be notified back from the pipeline. // DMFTCHECKHR_GOTO( WaitForSetInputPinMediaChange(),done ); } done: DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); return oldState; }
HRESULT WavSource::Start( IMFPresentationDescriptor* pPresentationDescriptor, const GUID* pguidTimeFormat, const PROPVARIANT* pvarStartPosition ) { HRESULT hr = S_OK; LONGLONG llStartOffset = 0; BOOL bIsSeek = FALSE; BOOL bIsRestartFromCurrentPosition = FALSE; BOOL bQueuedStartEvent = FALSE; IMFMediaEvent *pEvent = NULL; PROPVARIANT var; PropVariantInit(&var); // Check parameters. // Start position and presentation descriptor cannot be NULL. if (pvarStartPosition == NULL || pPresentationDescriptor == NULL) { return E_INVALIDARG; } // Check the time format. Must be "reference time" units. if ((pguidTimeFormat != NULL) && (*pguidTimeFormat != GUID_NULL)) { // Unrecognized time format GUID. return MF_E_UNSUPPORTED_TIME_FORMAT; } EnterCriticalSection(&m_critSec); // Fail if the source is shut down. hr = CheckShutdown(); if (FAILED(hr)) { goto done; } // Check the start position. if (pvarStartPosition->vt == VT_I8) { // Start position is given in pvarStartPosition in 100-ns units. llStartOffset = pvarStartPosition->hVal.QuadPart; if (m_state != STATE_STOPPED) { // Source is running or paused, so this is a seek. bIsSeek = TRUE; } } else if (pvarStartPosition->vt == VT_EMPTY) { // Start position is "current position". // For stopped, that means 0. Otherwise, use the current position. if (m_state == STATE_STOPPED) { llStartOffset = 0; } else { llStartOffset = GetCurrentPosition(); bIsRestartFromCurrentPosition = TRUE; } } else { // We don't support this time format. hr = MF_E_UNSUPPORTED_TIME_FORMAT; goto done; } // Validate the caller's presentation descriptor. hr = ValidatePresentationDescriptor(pPresentationDescriptor); if (FAILED(hr)) { goto done; } // Sends the MENewStream or MEUpdatedStream event. hr = QueueNewStreamEvent(pPresentationDescriptor); if (FAILED(hr)) { goto done; } // Notify the stream of the new start time. hr = m_pStream->SetPosition(llStartOffset); if (FAILED(hr)) { goto done; } // Send Started or Seeked events. var.vt = VT_I8; var.hVal.QuadPart = llStartOffset; // Send the source event. if (bIsSeek) { hr = QueueEvent(MESourceSeeked, GUID_NULL, hr, &var); if (FAILED(hr)) { goto done; } } else { // For starting, if we are RESTARTING from the current position and our // previous state was running/paused, then we need to add the // MF_EVENT_SOURCE_ACTUAL_START attribute to the event. This requires // creating the event object first. // Create the event. hr = MFCreateMediaEvent(MESourceStarted, GUID_NULL, hr, &var, &pEvent); if (FAILED(hr)) { goto done; } // For restarts, set the actual start time as an attribute. if (bIsRestartFromCurrentPosition) { hr = pEvent->SetUINT64(MF_EVENT_SOURCE_ACTUAL_START, llStartOffset); if (FAILED(hr)) { goto done; } } // Now queue the event. hr = m_pEventQueue->QueueEvent(pEvent); if (FAILED(hr)) { goto done; } } bQueuedStartEvent = TRUE; // Send the stream event. if (m_pStream) { if (bIsSeek) { hr = m_pStream->QueueEvent(MEStreamSeeked, GUID_NULL, hr, &var); } else { hr = m_pStream->QueueEvent(MEStreamStarted, GUID_NULL, hr, &var); } if (FAILED(hr)) { goto done; } } if (bIsSeek) { // For seek requests, flush any queued samples. hr = m_pStream->Flush(); } else { // Otherwise, deliver any queued samples. hr = m_pStream->DeliverQueuedSamples(); } if (FAILED(hr)) { goto done; } m_state = STATE_STARTED; done: // If a failure occurred and we have not sent the // MESourceStarted/MESourceSeeked event yet, then it is // OK just to return an error code from Start(). // If a failure occurred and we have already sent the // event (with a success code), then we need to raise an // MEError event. if (FAILED(hr) && bQueuedStartEvent) { hr = QueueEvent(MEError, GUID_NULL, hr, &var); } PropVariantClear(&var); SafeRelease(&pEvent); LeaveCriticalSection(&m_critSec); return hr; }
HRESULT CHWMFT::ProcessOutput( DWORD dwFlags, DWORD dwOutputBufferCount, MFT_OUTPUT_DATA_BUFFER* pOutputSamples, DWORD* pdwStatus) { /***************************************** ** See http://msdn.microsoft.com/en-us/library/ms704014(v=VS.85).aspx *****************************************/ HRESULT hr = S_OK; IMFSample* pSample = NULL; TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Enter", __FUNCTION__); do { if(IsLocked() != FALSE) { hr = MF_E_TRANSFORM_ASYNC_LOCKED; break; } { CAutoLock lock(&m_csLock); TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): HaveOutputCount: %u", __FUNCTION__, m_dwHaveOutputCount); if(m_dwHaveOutputCount == 0) { // This call does not correspond to a have output call hr = E_UNEXPECTED; break; } else { m_dwHaveOutputCount--; } } /***************************************** ** Todo: If your MFT supports more than one ** stream, make sure you modify ** MFT_MAX_STREAMS and adjust this function ** accordingly *****************************************/ if(dwOutputBufferCount < MFT_MAX_STREAMS) { hr = E_INVALIDARG; break; } if(IsMFTReady() == FALSE) { hr = MF_E_TRANSFORM_TYPE_NOT_SET; break; } /*************************************** ** Since this in an internal function ** we know m_pOutputSampleQueue can never be ** NULL due to InitializeTransform() ***************************************/ hr = m_pOutputSampleQueue->GetNextSample(&pSample); if(FAILED(hr)) { break; } if(pSample == NULL) { hr = MF_E_TRANSFORM_NEED_MORE_INPUT; break; } /******************************* ** Todo: This MFT only has one ** input stream, so the output ** samples array and stream ID ** will only use the first ** member *******************************/ pOutputSamples[0].dwStreamID = 0; if((pOutputSamples[0].pSample) == NULL) { // The MFT is providing it's own samples (pOutputSamples[0].pSample) = pSample; (pOutputSamples[0].pSample)->AddRef(); } else { // The pipeline has allocated the samples IMFMediaBuffer* pBuffer = NULL; do { hr = pSample->ConvertToContiguousBuffer(&pBuffer); if(FAILED(hr)) { break; } hr = (pOutputSamples[0].pSample)->AddBuffer(pBuffer); if(FAILED(hr)) { break; } }while(false); SAFERELEASE(pBuffer); if(FAILED(hr)) { break; } } /*************************************** ** Since this in an internal function ** we know m_pOutputSampleQueue can never be ** NULL due to InitializeTransform() ***************************************/ if(m_pOutputSampleQueue->IsQueueEmpty() != FALSE) { // We're out of samples in the output queue CAutoLock lock(&m_csLock); if((m_dwStatus & MYMFT_STATUS_DRAINING) != 0) { // We're done draining, time to send the event IMFMediaEvent* pDrainCompleteEvent = NULL; do { hr = MFCreateMediaEvent(METransformDrainComplete , GUID_NULL, S_OK, NULL, &pDrainCompleteEvent); if(FAILED(hr)) { break; } /******************************* ** Todo: This MFT only has one ** input stream, so the drain ** is always on stream zero. ** Update this is your MFT ** has more than one stream *******************************/ hr = pDrainCompleteEvent->SetUINT32(MF_EVENT_MFT_INPUT_STREAM_ID, 0); if(FAILED(hr)) { break; } /*************************************** ** Since this in an internal function ** we know m_pEventQueue can never be ** NULL due to InitializeTransform() ***************************************/ hr = m_pEventQueue->QueueEvent(pDrainCompleteEvent); if(FAILED(hr)) { break; } }while(false); SAFERELEASE(pDrainCompleteEvent); if(FAILED(hr)) { break; } m_dwStatus &= (~MYMFT_STATUS_DRAINING); } } }while(false); SAFERELEASE(pSample); TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Exit (hr=0x%x)", __FUNCTION__, hr); return hr; }
HRESULT HDMediaSource::DoStart(SourceOperation* op) { DbgLogPrintf(L"%s::DoStart...",L"HDMediaSource"); if (op->GetOperation() != SourceOperation::OP_START) return E_UNEXPECTED; ComPtr<IMFPresentationDescriptor> ppd; auto start_op = static_cast<StartOperation*>(op); HRESULT hr = start_op->GetPresentationDescriptor(ppd.GetAddressOf()); if (FAILED(hr)) return hr; bool bSeek = false,bResume = false; bool forceSeek = false; AutoPropVar propvar(&op->GetData()); if (propvar.GetType() == VT_I8) { if ((_state != STATE_STOPPED) && (propvar.GetInt64() != 0)) { bSeek = true; }else if (propvar.GetInt64() <= 0) { if (_state == STATE_STARTED || _state == STATE_PAUSED) bSeek = forceSeek = true; } }else if (propvar.GetType() == VT_EMPTY) { if (_state == STATE_PAUSED) bResume = true; } if (bResume) DbgLogPrintf(L"%s::DoStart->Resume Play...",L"HDMediaSource"); hr = SelectStreams(ppd.Get(),op->GetData(),bSeek,false); _seekAfterFlag = false; //指示Seek后的第一个Packet if ((SUCCEEDED(hr) && (propvar.GetInt64() != 0)) || forceSeek) { hr = SeekOpen(propvar.GetInt64()); //to Seek... }else{ if (start_op->GetSeekToTime() != PACKET_NO_PTS) _pMediaParser->Seek(start_op->GetSeekToTime(), true, AVSeekDirection::SeekDirection_Auto); } if (SUCCEEDED(hr)) { DbgLogPrintf(L"%s::DoStart->Event %s",L"HDMediaSource", bSeek ? L"MESourceSeeked":L"MESourceStarted"); ComPtr<IMFMediaEvent> pNewEvent; hr = MFCreateMediaEvent(bSeek ? MESourceSeeked:MESourceStarted,GUID_NULL,S_OK, &op->GetData(),pNewEvent.GetAddressOf()); if (SUCCEEDED(hr)) //[optional] MF_EVENT_SOURCE_ACTUAL_START... hr = _pEventQueue->QueueEvent(pNewEvent.Get()); if (SUCCEEDED(hr) && !bResume) { _state = STATE_BUFFERING; if (_network_mode) SendNetworkStartBuffering(); else PreloadStreamPacket(); //如果不是打开网络流,DoOpen就执行LoadSample队列 #ifdef _DEBUG double queueMaxTime = GetAllStreamMaxQueueTime(); DbgLogPrintf(L"%s::DoStart->Queue Max Time %0.3f",L"HDMediaSource",(float)queueMaxTime); #endif } if (SUCCEEDED(hr)) { for (unsigned i = 0;i < _streamList.Count();i++) { ComPtr<HDMediaStream> pStream; _streamList.GetAt(i,pStream.GetAddressOf()); if (pStream->IsActive()) { pStream->Start(op->GetData(),bSeek); pStream->SetOnceState(); } } } } _state = STATE_STARTED; if (FAILED(hr)) _pEventQueue->QueueEventParamVar(MESourceStarted,GUID_NULL,hr,nullptr); DbgLogPrintf(L"%s::DoStart Result:0x%08X",L"HDMediaSource",hr); return hr; }