HRESULT Inpin::NewSegment( REFERENCE_TIME st, REFERENCE_TIME sp, double r) { Filter::Lock lock; HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; if (!bool(m_pPinConnection)) return VFW_E_NOT_CONNECTED; if (IPin* pPin = m_pFilter->m_outpin.m_pPinConnection) { lock.Release(); const HRESULT hr = pPin->NewSegment(st, sp, r); return hr; } return S_OK; }
HRESULT Inpin::EndFlush() { Filter::Lock lock; HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; if (!bool(m_pPinConnection)) return VFW_E_NOT_CONNECTED; #if 0 //def _DEBUG odbgstream os; os << "vp8decoder::inpin::endflush" << endl; #endif m_bFlush = false; m_bEndOfStream = false; if (IPin* pPin = m_pFilter->m_outpin.m_pPinConnection) { lock.Release(); const HRESULT hr = pPin->EndFlush(); return hr; } return S_OK; }
HRESULT OutpinVideo::CheckCapabilities(DWORD* pdw) { Filter::Lock lock; HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; if (!bool(m_pPinConnection)) return VFW_E_NOT_CONNECTED; const Inpin& inpin = m_pFilter->m_inpin; const GraphUtil::IMediaSeekingPtr pSeek(inpin.m_pPinConnection); if (bool(pSeek)) { lock.Release(); return pSeek->CheckCapabilities(pdw); } if (pdw == 0) return E_POINTER; DWORD& dw = *pdw; const DWORD dwRequested = dw; if (dwRequested == 0) return E_INVALIDARG; return E_FAIL; }
HRESULT OutpinVideo::GetPositions( LONGLONG* pCurrPos, LONGLONG* pStopPos) { Filter::Lock lock; HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; if (!bool(m_pPinConnection)) return VFW_E_NOT_CONNECTED; const Inpin& inpin = m_pFilter->m_inpin; const GraphUtil::IMediaSeekingPtr pSeek(inpin.m_pPinConnection); if (bool(pSeek)) { lock.Release(); return pSeek->GetPositions(pCurrPos, pStopPos); } return E_FAIL; }
HRESULT OutpinVideo::GetAvailable( LONGLONG* pEarliest, LONGLONG* pLatest) { Filter::Lock lock; HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; if (!bool(m_pPinConnection)) return VFW_E_NOT_CONNECTED; const Inpin& inpin = m_pFilter->m_inpin; const GraphUtil::IMediaSeekingPtr pSeek(inpin.m_pPinConnection); if (bool(pSeek)) { lock.Release(); return pSeek->GetAvailable(pEarliest, pLatest); } return E_FAIL; }
HRESULT OutpinVideo::GetDuration(LONGLONG* p) { Filter::Lock lock; HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; if (!bool(m_pPinConnection)) return VFW_E_NOT_CONNECTED; const Inpin& inpin = m_pFilter->m_inpin; const GraphUtil::IMediaSeekingPtr pSeek(inpin.m_pPinConnection); if (bool(pSeek)) { lock.Release(); return pSeek->GetDuration(p); } if (p == 0) return E_POINTER; return E_FAIL; }
HRESULT OutpinVideo::GetCurrentPosition(LONGLONG* p) { Filter::Lock lock; HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; if (!bool(m_pPinConnection)) return VFW_E_NOT_CONNECTED; const Inpin& inpin = m_pFilter->m_inpin; #if 0 const GraphUtil::IMediaSeekingPtr pSeek(inpin.m_pPinConnection); if (bool(pSeek)) { lock.Release(); return pSeek->GetCurrentPosition(p); } if (p == 0) return E_POINTER; return E_FAIL; #else if (p == 0) return E_POINTER; *p = inpin.m_start_reftime; return S_OK; #endif }
HRESULT OutpinVideo::SetTimeFormat(const GUID* p) { Filter::Lock lock; HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; if (!bool(m_pPinConnection)) return VFW_E_NOT_CONNECTED; const Inpin& inpin = m_pFilter->m_inpin; const GraphUtil::IMediaSeekingPtr pSeek(inpin.m_pPinConnection); if (bool(pSeek)) { lock.Release(); return pSeek->SetTimeFormat(p); } if (p == 0) return E_INVALIDARG; if (*p == TIME_FORMAT_MEDIA_TIME) return S_OK; return E_INVALIDARG; }
HRESULT OutpinVideo::QueryPreferredFormat(GUID* p) { Filter::Lock lock; HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; if (!bool(m_pPinConnection)) return VFW_E_NOT_CONNECTED; const Inpin& inpin = m_pFilter->m_inpin; const GraphUtil::IMediaSeekingPtr pSeek(inpin.m_pPinConnection); if (bool(pSeek)) { lock.Release(); return pSeek->QueryPreferredFormat(p); } if (p == 0) return E_POINTER; *p = TIME_FORMAT_MEDIA_TIME; return S_OK; }
HRESULT OutpinVideo::IsFormatSupported(const GUID* p) { Filter::Lock lock; HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; if (!bool(m_pPinConnection)) return VFW_E_NOT_CONNECTED; const Inpin& inpin = m_pFilter->m_inpin; const GraphUtil::IMediaSeekingPtr pSeek(inpin.m_pPinConnection); if (bool(pSeek)) { lock.Release(); return pSeek->IsFormatSupported(p); } if (p == 0) return E_POINTER; const GUID& g = *p; if (g == TIME_FORMAT_MEDIA_TIME) return S_OK; return S_FALSE; }
HRESULT Inpin::BeginFlush() { Filter::Lock lock; HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; if (!bool(m_pPinConnection)) return VFW_E_NOT_CONNECTED; //TODO: //if (m_bFlush) // return S_FALSE; #if 0 //def _DEBUG odbgstream os; os << "vp8decoder::inpin::beginflush" << endl; #endif m_bFlush = true; if (IPin* pPin = m_pFilter->m_outpin.m_pPinConnection) { lock.Release(); const HRESULT hr = pPin->BeginFlush(); return hr; } return S_OK; }
HRESULT OutpinVideo::GetCapabilities(DWORD* pdw) { Filter::Lock lock; HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; if (!bool(m_pPinConnection)) return VFW_E_NOT_CONNECTED; const Inpin& inpin = m_pFilter->m_inpin; const GraphUtil::IMediaSeekingPtr pSeek(inpin.m_pPinConnection); if (bool(pSeek)) { lock.Release(); return pSeek->GetCapabilities(pdw); } if (pdw == 0) return E_POINTER; DWORD& dw = *pdw; dw = 0; return S_OK; //? }
HRESULT Inpin::ReceiveCanBlock() { Filter::Lock lock; const HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return S_OK; //? if (IMemInputPin* pPin = m_pFilter->m_outpin.m_pInputPin) { lock.Release(); return pPin->ReceiveCanBlock(); } return S_FALSE; }
HRESULT OutpinVideo::ConvertTimeFormat( LONGLONG* ptgt, const GUID* ptgtfmt, LONGLONG src, const GUID* psrcfmt) { Filter::Lock lock; HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; if (!bool(m_pPinConnection)) return VFW_E_NOT_CONNECTED; const Inpin& inpin = m_pFilter->m_inpin; const GraphUtil::IMediaSeekingPtr pSeek(inpin.m_pPinConnection); if (bool(pSeek)) { lock.Release(); return pSeek->ConvertTimeFormat(ptgt, ptgtfmt, src, psrcfmt); } if (ptgt == 0) return E_POINTER; LONGLONG& tgt = *ptgt; const GUID& tgtfmt = ptgtfmt ? *ptgtfmt : TIME_FORMAT_MEDIA_TIME; const GUID& srcfmt = psrcfmt ? *psrcfmt : TIME_FORMAT_MEDIA_TIME; if (tgtfmt != TIME_FORMAT_MEDIA_TIME) return E_INVALIDARG; if (srcfmt != TIME_FORMAT_MEDIA_TIME) return E_INVALIDARG; tgt = src; return S_OK; }
HRESULT OutpinVideo::SetPositions( LONGLONG* pCurr_, DWORD dwCurr_, LONGLONG* pStop_, DWORD dwStop_) { Filter::Lock lock; HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; if (!bool(m_pPinConnection)) return VFW_E_NOT_CONNECTED; const Inpin& inpin = m_pFilter->m_inpin; const GraphUtil::IMediaSeekingPtr pSeek(inpin.m_pPinConnection); if (bool(pSeek)) { lock.Release(); LONGLONG curr; LONGLONG* const pCurr = pCurr_ ? pCurr_ : &curr; const DWORD dwCurr = pCurr_ ? dwCurr_ : AM_SEEKING_NoPositioning; LONGLONG stop; LONGLONG* const pStop = pStop_ ? pStop_ : &stop; const DWORD dwStop = pStop_ ? dwStop_ : AM_SEEKING_NoPositioning; return pSeek->SetPositions(pCurr, dwCurr, pStop, dwStop); } return E_FAIL; }
HRESULT OutpinVideo::SetRate(double r) { Filter::Lock lock; HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; if (!bool(m_pPinConnection)) return VFW_E_NOT_CONNECTED; const Inpin& inpin = m_pFilter->m_inpin; const GraphUtil::IMediaSeekingPtr pSeek(inpin.m_pPinConnection); if (bool(pSeek)) { lock.Release(); return pSeek->SetRate(r); } return E_FAIL; }
HRESULT Inpin::EndOfStream() { Filter::Lock lock; HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; if (!bool(m_pPinConnection)) return VFW_E_NOT_CONNECTED; m_bEndOfStream = true; if (IPin* pPin = m_pFilter->m_outpin.m_pPinConnection) { lock.Release(); #ifdef _DEBUG odbgstream os; os << "vp8decoder::inpin::EOS: calling pin->EOS" << endl; #endif const HRESULT hr = pPin->EndOfStream(); #ifdef _DEBUG os << "vp8decoder::inpin::EOS: called pin->EOS; hr=0x" << hex << hr << dec << endl; #endif return hr; } return S_OK; }
HRESULT Outpin::SetPositions( LONGLONG* pCurr, DWORD dwCurr_, LONGLONG* pStop, DWORD dwStop_) { Filter::Lock lock; HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; #if 0 //def _DEBUG wodbgstream os; os << "\nwebmsource::Outpin[" << m_id << "]::SetPos(begin): pCurr=" << dec << (pCurr ? *pCurr : -1) << " dwCurr=0x" << hex << dwCurr_ << " pStop=" << dec << (pStop ? *pStop : -1) << " dwStop=0x" << hex << dwStop_ << "; STATE=" << m_pFilter->m_state << endl; #endif if (m_connection == 0) return VFW_E_NOT_CONNECTED; const DWORD dwCurrPos = dwCurr_ & AM_SEEKING_PositioningBitsMask; const DWORD dwStopPos = dwStop_ & AM_SEEKING_PositioningBitsMask; if (dwCurrPos == AM_SEEKING_NoPositioning) { if (dwCurr_ & AM_SEEKING_ReturnTime) { if (pCurr == 0) return E_POINTER; *pCurr = m_pStream->GetCurrTime(); if (*pCurr < 0) //means "use duration" { hr = GetDuration(pCurr); if (FAILED(hr) || (*pCurr < 0)) *pCurr = 0; //? } } if (dwStopPos == AM_SEEKING_NoPositioning) { if (dwStop_ & AM_SEEKING_ReturnTime) { if (pStop == 0) return E_POINTER; *pStop = m_pStream->GetStopTime(); if (*pStop < 0) //means "use duration" { hr = GetDuration(pStop); if (FAILED(hr) || (*pStop < 0)) *pStop = 0; //? } } return S_FALSE; //no position change } if (pStop == 0) return E_INVALIDARG; LONGLONG& tStop = *pStop; //It makes sense to be able to adjust this during stop. //However, if we're paused/running, then the thread is either //still sending frames, or it has already sent EOS. In the //former case, it makes sense to be able to adjust where //the running thread will stop. But in the latter case, //the thread has already terminated, and it wouldn't //make any sense to restart the thread because there //would be a large time gap. m_pStream->SetStopPosition(tStop, dwStop_); if (dwStop_ & AM_SEEKING_ReturnTime) { tStop = m_pStream->GetStopTime(); if (tStop < 0) //means "use duration" { hr = GetDuration(&tStop); if (FAILED(hr) || (tStop < 0)) tStop = 0; //?? } } //TODO: You're supposed to return S_FALSE if there has //been no change in position. Does changing only the stop //position count has having changed the position? return S_OK; } //Check for errors first, before changing any state. if (pCurr == 0) return E_INVALIDARG; switch (dwCurrPos) { case AM_SEEKING_IncrementalPositioning: default: return E_INVALIDARG; //applies only to stop pos case AM_SEEKING_AbsolutePositioning: case AM_SEEKING_RelativePositioning: break; } if (dwStopPos == AM_SEEKING_NoPositioning) { if (((dwStop_ & AM_SEEKING_ReturnTime) != 0) && (pStop == 0)) return E_POINTER; } else if (pStop == 0) return E_INVALIDARG; assert(pCurr); //vetted above LONGLONG& tCurr = *pCurr; if (tCurr == Filter::kNoSeek) return E_INVALIDARG; //we need a nonce value if (m_pFilter->m_state != State_Stopped) { #if 0 //def _DEBUG os << "webmsource::Outpin[" << m_id << "]::SetPos(cont'd): pCurr=" << dec << (pCurr ? tCurr : -1) << " dwCurr=0x" << hex << dwCurr_ << " pStop=" << dec << (pStop ? *pStop : -1) << " dwStop=0x" << hex << dwStop_ << "; BEGIN FLUSH: releasing filter lock; STATE=" << m_pFilter->m_state << endl; #endif lock.Release(); #if 0 //def _DEBUG os << "webmsource::Outpin[" << m_id << "]::SetPos(cont'd): pCurr=" << dec << (pCurr ? tCurr : -1) << " dwCurr=0x" << hex << dwCurr_ << " pStop=" << dec << (pStop ? *pStop : -1) << " dwStop=0x" << hex << dwStop_ << "; BEGIN FLUSH: released filter lock; " << "connection->calling BeginFlush" << endl; #endif hr = m_connection->BeginFlush(); #if 0 //def _DEBUG os << "webmsource::Outpin[" << m_id << "]::SetPos(cont'd): pCurr=" << dec << (pCurr ? tCurr : -1) << " dwCurr=0x" << hex << dwCurr_ << " pStop=" << dec << (pStop ? *pStop : -1) << " dwStop=0x" << hex << dwStop_ << "; BEGIN FLUSH: released filter lock; " << "connection->called BeginFlush; " << "waiting for thread termination" << endl; #endif assert(m_hThread); const DWORD dw = WaitForSingleObject(m_hThread, 5000); //assert(dw == WAIT_OBJECT_0); if (dw == WAIT_TIMEOUT) return VFW_E_TIMEOUT; const BOOL b = CloseHandle(m_hThread); assert(b); m_hThread = 0; #if 0 //def _DEBUG os << "webmsource::Outpin[" << m_id << "]::SetPos(cont'd): pCurr=" << dec << (pCurr ? tCurr : -1) << " dwCurr=0x" << hex << dwCurr_ << " pStop=" << dec << (pStop ? *pStop : -1) << " dwStop=0x" << hex << dwStop_ << "; END FLUSH: calling connection->EndFlush" << endl; #endif hr = m_connection->EndFlush(); #if 0 //def _DEBUG os << "webmsource::Outpin[" << m_id << "]::SetPos(cont'd): pCurr=" << dec << (pCurr ? tCurr : -1) << " dwCurr=0x" << hex << dwCurr_ << " pStop=" << dec << (pStop ? *pStop : -1) << " dwStop=0x" << hex << dwStop_ << "; END FLUSH: called connection->EndFlush; seizing filter lock" << endl; #endif hr = lock.Seize(m_pFilter); assert(SUCCEEDED(hr)); //TODO #if 0 //def _DEBUG os << "webmsource::Outpin[" << m_id << "]::SetPos(cont'd): pCurr=" << dec << (pCurr ? tCurr : -1) << " dwCurr=0x" << hex << dwCurr_ << " pStop=" << dec << (pStop ? *pStop : -1) << " dwStop=0x" << hex << dwStop_ << "; END FLUSH: seized filter lock" << endl; #endif } #if 0 //def _DEBUG os << "webmsource::Outpin[" << m_id << "]::SetPos(cont'd): pCurr=" << dec << (pCurr ? tCurr : -1) << " pStop=" << dec << (pStop ? *pStop : -1) << "; SET CURR POSN (begin)" << endl; #endif m_pFilter->SetCurrPosition(tCurr, dwCurr_, this); if (dwStopPos == AM_SEEKING_NoPositioning) { //TODO: I still haven't figured what should happen to the //stop position if the user doesn't seek the stop time //too. For now I assume that that user wants to play //the entire remainder of the stream starting from the //seek time. m_pStream->SetStopPositionEOS(); } else { assert(pStop); //vetted above m_pStream->SetStopPosition(*pStop, dwStop_); } #if 0 //def _DEBUG os << "webmsource::Outpin[" << m_id << "]::SetPos(cont'd): pCurr=" << dec << (pCurr ? tCurr : -1) << " pStop=" << dec << (pStop ? *pStop : -1) << "; SET CURR POSN (end)" << endl; #endif if (dwCurr_ & AM_SEEKING_ReturnTime) { tCurr = m_pStream->GetCurrTime(); if (tCurr < 0) //means "use duration" { hr = GetDuration(&tCurr); if (FAILED(hr) || (tCurr < 0)) tCurr = 0; //? } } if (dwStop_ & AM_SEEKING_ReturnTime) { assert(pStop); //we checked this above *pStop = m_pStream->GetStopTime(); if (*pStop < 0) //means "use duration" { hr = GetDuration(pStop); if (FAILED(hr) || (*pStop < 0)) *pStop = 0; //? } } if (m_pFilter->m_state != State_Stopped) StartThread(); #if 0 //def _DEBUG os << "webmsource::Outpin[" << m_id << "]::SetPos(end): pCurr=" << dec << (pCurr ? tCurr : -1) << " pStop=" << dec << (pStop ? *pStop : -1) << "; DONE\n" << endl; #endif return S_OK; }
HRESULT Outpin::PopulateSamples(OggTrack::samples_t& samples) { for (;;) { assert(samples.empty()); Filter::Lock lock; HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; long count; hr = m_pTrack->GetPackets(count); if (FAILED(hr)) //TODO: handle underflow if req'd for ogg parsing return hr; if (hr != S_OK) //EOS return S_FALSE; //report EOS assert(count > 0); hr = lock.Release(); assert(SUCCEEDED(hr)); samples.reserve(count); for (long idx = 0; idx < count; ++idx) { IMediaSample* sample; hr = m_pAllocator->GetBuffer(&sample, 0, 0, 0); if (hr != S_OK) return E_FAIL; //we're done samples.push_back(sample); } hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; hr = m_pTrack->PopulateSamples(samples); if (FAILED(hr)) return hr; if (hr != 2) //2 means "must parse more, and then re-try" return hr; //have samples (0) or EOS (1), so we're done hr = lock.Release(); assert(SUCCEEDED(hr)); OggTrack::Clear(samples); } }
HRESULT Inpin::BeginFlush() { #ifdef _DEBUG odbgstream os; os << "webmvorbisdecoder::inpin::beginflush(begin)" << endl; #endif Filter::Lock lock; HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; if (!bool(m_pPinConnection)) return VFW_E_NOT_CONNECTED; //IPin::BeginFlush //In a flush operation, a filter discards whatever data it was processing. //It rejects new data until the flush is completed. The flush is //completed when the upstream pin calls the IPin::EndFlush method. //Flushing enables the filter graph to be more responsive when events //alter the normal data flow. For example, flushing occurs during a seek. // //When BeginFlush is called, the filter performs the following steps: // //(1) Passes the IPin::BeginFlush call downstream. // //(2) Sets an internal flag that causes all data-streaming methods to // fail, such as IMemInputPin::Receive. // //(3) Returns from any blocked calls to the Receive method. // // //When the BeginFlush notification reaches a renderer filter, //the renderer frees any samples that it holds. // //After BeginFlush is called, the pin rejects all samples from upstream, //with a return value of S_FALSE, until the IPin::EndFlush method is //called. //IPin::EndOfStream //The IPin::BeginFlush method flushes any queued end-of-stream //notifications. This is intended for input pins only. m_bFlush = true; Outpin& outpin = m_pFilter->m_outpin; if (IPin* const pPin = outpin.m_pPinConnection) { #ifdef _DEBUG os << "webmvorbisdecoder::inpin::beginflush:" << " flushing downstream filter" << endl; #endif hr = pPin->BeginFlush(); //safe to do this here, while holding lock? #ifdef _DEBUG os << "webmvorbisdecoder::inpin::beginflush:" << " called BeginFlush: hr=0x" << hex << hr << dec << "\nwebmvorbisdecoder::inpin::beginflush: waiting for thread" << "to terminate" << endl; #endif const BOOL b = SetEvent(m_hSamples); //to terminate thread assert(b); hr = lock.Release(); assert(SUCCEEDED(hr)); //The thread might not exist yet, if we have been connected but not //started. In which case, attempting to stop the thread is benign. outpin.StopThread(); } #ifdef _DEBUG os << "webmvorbisdecoder::inpin::beginflush(end #2): thread terminated" << endl; #endif return S_OK; }
HRESULT Inpin::Receive(IMediaSample* pInSample) { if (pInSample == 0) return E_INVALIDARG; //#define DEBUG_RECEIVE #ifdef DEBUG_RECEIVE { __int64 start_reftime, stop_reftime; const HRESULT hr = pInSample->GetTime(&start_reftime, &stop_reftime); odbgstream os; os << "vp8dec::inpin::receive: "; os << std::fixed << std::setprecision(3); if (hr == S_OK) os << "start[ms]=" << double(start_reftime) / 10000 << "; stop[ms]=" << double(stop_reftime) / 10000 << "; dt[ms]=" << double(stop_reftime - start_reftime) / 10000; else if (hr == VFW_S_NO_STOP_TIME) os << "start[ms]=" << double(start_reftime) / 10000; os << endl; } #endif Filter::Lock lock; HRESULT hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; //#ifdef DEBUG_RECEIVE // wodbgstream os; // os << L"vp8dec::inpin::Receive: THREAD=0x" // << std::hex << GetCurrentThreadId() << std::dec // << endl; //#endif if (!bool(m_pPinConnection)) return VFW_E_NOT_CONNECTED; Outpin& outpin = m_pFilter->m_outpin; if (!bool(outpin.m_pPinConnection)) return S_FALSE; if (!bool(outpin.m_pAllocator)) //should never happen return VFW_E_NO_ALLOCATOR; if (m_pFilter->m_state == State_Stopped) return VFW_E_NOT_RUNNING; if (m_bEndOfStream) return VFW_E_SAMPLE_REJECTED_EOS; if (m_bFlush) return S_FALSE; BYTE* buf; hr = pInSample->GetPointer(&buf); assert(SUCCEEDED(hr)); assert(buf); const long len = pInSample->GetActualDataLength(); assert(len >= 0); const vpx_codec_err_t err = vpx_codec_decode(&m_ctx, buf, len, 0, 0); if (err != VPX_CODEC_OK) { GraphUtil::IMediaEventSinkPtr pSink(m_pFilter->m_info.pGraph); if (bool(pSink)) { lock.Release(); hr = pSink->Notify( EC_STREAM_ERROR_STOPPED, VFW_E_SAMPLE_REJECTED, err); } m_bEndOfStream = true; //clear this when we stop and then start again return S_FALSE; } if (pInSample->IsPreroll() == S_OK) return S_OK; lock.Release(); GraphUtil::IMediaSamplePtr pOutSample; hr = outpin.m_pAllocator->GetBuffer(&pOutSample, 0, 0, 0); if (FAILED(hr)) return S_FALSE; assert(bool(pOutSample)); hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; if (m_pFilter->m_state == State_Stopped) return VFW_E_NOT_RUNNING; if (!bool(outpin.m_pPinConnection)) //should never happen return S_FALSE; if (!bool(outpin.m_pInputPin)) //should never happen return S_FALSE; vpx_codec_iter_t iter = 0; vpx_image_t* const f = vpx_codec_get_frame(&m_ctx, &iter); if (f == 0) return S_OK; AM_MEDIA_TYPE* pmt; hr = pOutSample->GetMediaType(&pmt); if (SUCCEEDED(hr) && (pmt != 0)) { assert(outpin.QueryAccept(pmt) == S_OK); outpin.m_connection_mtv.Clear(); outpin.m_connection_mtv.Add(*pmt); MediaTypeUtil::Free(pmt); pmt = 0; } const AM_MEDIA_TYPE& mt = outpin.m_connection_mtv[0]; assert(mt.formattype == FORMAT_VideoInfo); assert(mt.cbFormat >= sizeof(VIDEOINFOHEADER)); assert(mt.pbFormat); const VIDEOINFOHEADER& vih = (VIDEOINFOHEADER&)(*mt.pbFormat); const BITMAPINFOHEADER& bmih = vih.bmiHeader; //Y const BYTE* pInY = f->planes[PLANE_Y]; assert(pInY); unsigned int wIn = f->d_w; unsigned int hIn = f->d_h; BYTE* pOutBuf; hr = pOutSample->GetPointer(&pOutBuf); assert(SUCCEEDED(hr)); assert(pOutBuf); BYTE* pOut = pOutBuf; const int strideInY = f->stride[PLANE_Y]; LONG strideOut = bmih.biWidth; assert(strideOut); assert((strideOut % 2) == 0); //? for (unsigned int y = 0; y < hIn; ++y) { memcpy(pOut, pInY, wIn); pInY += strideInY; pOut += strideOut; } strideOut /= 2; wIn = (wIn + 1) / 2; hIn = (hIn + 1) / 2; const BYTE* pInV = f->planes[PLANE_V]; assert(pInV); const int strideInV = f->stride[PLANE_V]; const BYTE* pInU = f->planes[PLANE_U]; assert(pInU); const int strideInU = f->stride[PLANE_U]; if (mt.subtype == MEDIASUBTYPE_YV12) { //V for (unsigned int y = 0; y < hIn; ++y) { memcpy(pOut, pInV, wIn); pInV += strideInV; pOut += strideOut; } //U for (unsigned int y = 0; y < hIn; ++y) { memcpy(pOut, pInU, wIn); pInU += strideInU; pOut += strideOut; } } else { //U for (unsigned int y = 0; y < hIn; ++y) { memcpy(pOut, pInU, wIn); pInU += strideInU; pOut += strideOut; } //V for (unsigned int y = 0; y < hIn; ++y) { memcpy(pOut, pInV, wIn); pInV += strideInV; pOut += strideOut; } } __int64 st, sp; hr = pInSample->GetTime(&st, &sp); if (FAILED(hr)) { hr = pOutSample->SetTime(0, 0); assert(SUCCEEDED(hr)); } else if (hr == S_OK) { hr = pOutSample->SetTime(&st, &sp); assert(SUCCEEDED(hr)); } else { hr = pOutSample->SetTime(&st, 0); assert(SUCCEEDED(hr)); } hr = pOutSample->SetSyncPoint(TRUE); assert(SUCCEEDED(hr)); hr = pOutSample->SetPreroll(FALSE); assert(SUCCEEDED(hr)); const ptrdiff_t lenOut_ = pOut - pOutBuf; const long lenOut = static_cast<long>(lenOut_); hr = pOutSample->SetActualDataLength(lenOut); assert(SUCCEEDED(hr)); hr = pInSample->IsDiscontinuity(); hr = pOutSample->SetDiscontinuity(hr == S_OK); hr = pOutSample->SetMediaTime(0, 0); lock.Release(); return outpin.m_pInputPin->Receive(pOutSample); }
HRESULT Inpin::Receive(IMediaSample* pInSample) { if (pInSample == 0) return E_INVALIDARG; HRESULT hr; //#define DEBUG_RECEIVE #undef DEBUG_RECEIVE #ifdef DEBUG_RECEIVE __int64 start_reftime_, stop_reftime_; hr = pInSample->GetTime(&start_reftime_, &stop_reftime_); #endif Filter::Lock lock; hr = lock.Seize(m_pFilter); if (FAILED(hr)) return hr; //#ifdef DEBUG_RECEIVE // wodbgstream os; // os << L"vp8dec::inpin::Receive: THREAD=0x" // << std::hex << GetCurrentThreadId() << std::dec // << endl; //#endif if (!bool(m_pPinConnection)) return VFW_E_NOT_CONNECTED; Outpin& outpin = m_pFilter->m_outpin; if (!bool(outpin.m_pPinConnection)) return S_FALSE; if (!bool(outpin.m_pAllocator)) //should never happen return VFW_E_NO_ALLOCATOR; if (m_pFilter->m_state == State_Stopped) return VFW_E_NOT_RUNNING; if (m_bEndOfStream) return VFW_E_SAMPLE_REJECTED_EOS; if (m_bFlush) return S_FALSE; if (m_bDone) return S_FALSE; if (m_first_reftime < 0) { LONGLONG sp; hr = pInSample->GetTime(&m_first_reftime, &sp); if (FAILED(hr)) return S_OK; if (m_first_reftime < 0) return S_OK; m_start_reftime = m_first_reftime; m_samples = 0; #ifdef DEBUG_RECEIVE odbgstream os; os << std::fixed << std::setprecision(3); os << "\nwebmvorbisdec::Inpin::Receive: RESET FIRST REFTIME;" << " st=" << m_start_reftime << " st[sec]=" << (double(m_start_reftime) / 10000000) << endl; #endif const int status = vorbis_synthesis_restart(&m_dsp_state); status; assert(status == 0); //success m_bDiscontinuity = true; } #ifdef DEBUG_RECEIVE { odbgstream os; os << "webmvorbisdec::inpin::receive: "; os << std::fixed << std::setprecision(3); if (hr == S_OK) os << "start[sec]=" << double(start_reftime_) / 10000000 << "; stop[sec]=" << double(stop_reftime_) / 10000000 << "; dt[ms]=" << double(stop_reftime_ - start_reftime_) / 10000; else if (hr == VFW_S_NO_STOP_TIME) os << "start[sec]=" << double(start_reftime_) / 10000000; os << endl; } #endif Decode(pInSample); hr = lock.Release(); assert(SUCCEEDED(hr)); if (FAILED(hr)) return hr; return PopulateSamples(); }