HRESULT CWavPackSplitterFilterInputPin::DeliverOneFrame(WavPack_parser* wpp) { IMediaSample *pSample; BYTE *Buffer = NULL; HRESULT hr; unsigned long FrameLenBytes = 0, FrameLenSamples = 0, FrameIndex = 0; // Get a new media sample hr = m_pParentFilter->m_pOutputPin->GetDeliveryBuffer(&pSample, NULL, NULL, 0); if (FAILED(hr)) { return hr; } hr = pSample->GetPointer(&Buffer); if (FAILED(hr)) { pSample->Release(); return hr; } FrameLenBytes = wavpack_parser_read_frame(wpp, Buffer, &FrameIndex, &FrameLenSamples); if (!FrameLenBytes) { // Something bad happened, let's end here pSample->Release(); m_pParentFilter->m_pOutputPin->DeliverEndOfStream(); // TODO : check if we need to stop the thread return hr; } pSample->SetActualDataLength(FrameLenBytes); REFERENCE_TIME rtStart, rtStop; rtStart = FrameIndex; rtStop = rtStart + FrameLenSamples; rtStart = (rtStart * 10000000) / wpp->sample_rate; rtStop = (rtStop * 10000000) / wpp->sample_rate; rtStart -= m_pParentFilter->m_rtStart; rtStop -= m_pParentFilter->m_rtStart; pSample->SetTime(&rtStart, &rtStop); pSample->SetPreroll(FALSE); pSample->SetDiscontinuity(m_bDiscontinuity); if (m_bDiscontinuity) { m_bDiscontinuity = FALSE; } pSample->SetSyncPoint(TRUE); // Deliver the sample hr = m_pParentFilter->m_pOutputPin->Deliver(pSample); pSample->Release(); pSample = NULL; if (FAILED(hr)) { return hr; } return S_OK; }
HRESULT CPushAudioPin::DoBufferProcessingLoop(void) { Command com; OnThreadStartPlay(); do { while (!CheckRequest(&com)) { HRESULT hr; CAutoLock lock(&m_cSharedState); if( WaitForSingleObject( this->buffLockEvent, 500 ) == WAIT_OBJECT_0 ){ if( this->buffData.size() != 0 ){ if( this->buffLockEvent != NULL ){ SetEvent(this->buffLockEvent); } IMediaSample *pSample; hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); if (FAILED(hr)) { Sleep(1); continue; } hr = FillBuffer(pSample); if (hr == S_OK) { hr = Deliver(pSample); pSample->Release(); if(hr != S_OK) { return S_OK; } } else if (hr == S_FALSE) { pSample->Release(); DeliverEndOfStream(); return S_OK; } else { pSample->Release(); DeliverEndOfStream(); m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0); return hr; } }else{ if( this->buffLockEvent != NULL ){ SetEvent(this->buffLockEvent); } Sleep(10); } } } // For all commands sent to us there must be a Reply call! if (com == CMD_RUN || com == CMD_PAUSE) { Reply(NOERROR); } else if (com != CMD_STOP) { Reply((DWORD) E_UNEXPECTED); } } while (com != CMD_STOP); return S_FALSE; }
dsnerror_t Decode(const BYTE *src, int size, double pts, double *newpts, BYTE *pImage, int keyframe) { IMediaSample* sample = NULL; REFERENCE_TIME start = PTS2RT(pts); /* sometimes I get x99999 instead of y00000 */ REFERENCE_TIME stoptime = start + m_frametime; BYTE *ptr; DSN_CHECK(m_pAll->GetBuffer(&sample, 0, 0, 0), DSN_FAIL_DECODESAMPLE); DSN_CHECK(sample->SetActualDataLength(size), DSN_FAIL_DECODESAMPLE); DSN_CHECK(sample->GetPointer(&ptr), DSN_FAIL_DECODESAMPLE); memcpy(ptr, src, size); DSN_CHECK(sample->SetTime(&start, &stoptime), DSN_FAIL_DECODESAMPLE); DSN_CHECK(sample->SetSyncPoint(keyframe), DSN_FAIL_DECODESAMPLE); DSN_CHECK(sample->SetPreroll(pImage ? 0 : 1), DSN_FAIL_DECODESAMPLE); DSN_CHECK(sample->SetDiscontinuity(m_discontinuity), DSN_FAIL_DECODESAMPLE); m_discontinuity = 0; m_pOurOutput->SetPointer(pImage); DSN_CHECK(m_pImp->Receive(sample), DSN_FAIL_RECEIVE); sample->Release(); *newpts = RT2PTS(m_pOurOutput->GetPTS()); return DSN_OK; }
HRESULT CPullPin::QueueSample( __inout REFERENCE_TIME& tCurrent, REFERENCE_TIME tAlignStop, BOOL bDiscontinuity ) { IMediaSample* pSample; HRESULT hr = m_pAlloc->GetBuffer(&pSample, NULL, NULL, 0); if (FAILED(hr)) { return hr; } LONGLONG tStopThis = tCurrent + (pSample->GetSize() * UNITS); if (tStopThis > tAlignStop) { tStopThis = tAlignStop; } pSample->SetTime(&tCurrent, &tStopThis); tCurrent = tStopThis; pSample->SetDiscontinuity(bDiscontinuity); hr = m_pReader->Request( pSample, 0); if (FAILED(hr)) { pSample->Release(); CleanupCancelled(); OnError(hr); } return hr; }
HRESULT CTSParserOutputPin::SendOut( DWORD nGroupFlag, const BYTE* pData, DWORD dwBytes, DWORD* dwUsedBytes ) { IMediaSample *pSample; BYTE *pSampleData; DWORD cbData; *dwUsedBytes = 0; HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); if (FAILED(hr)) return E_FAIL; pSample->GetPointer(&pSampleData); cbData = pSample->GetSize(); if ( cbData < dwBytes ) { dwBytes = cbData; ASSERT( 0 ); } memcpy( pSampleData, pData, dwBytes ); pSample->SetActualDataLength( dwBytes ); *dwUsedBytes = dwBytes; hr = Deliver(pSample); pSample->Release(); return S_OK; }
STDMETHODIMP FakeOutputPin::PushBuffer(byte *buffer, __int64 start, __int64 stop, unsigned int size, bool discont) { IMediaSample *pSample = NULL; if (start != -1) { start /= 100; stop /= 100; } HRESULT hres = GetDeliveryBuffer(&pSample, NULL, NULL, 0); if (hres == S_OK && pSample) { BYTE *sample_buffer; pSample->GetPointer(&sample_buffer); if(sample_buffer) { memcpy (sample_buffer, buffer, size); pSample->SetActualDataLength(size); } pSample->SetDiscontinuity(discont); pSample->SetSyncPoint(TRUE); pSample->SetPreroll(FALSE); if (start != -1) pSample->SetTime(&start, &stop); hres = Deliver(pSample); pSample->Release(); } return S_OK; }
// // GetStaticImage // // Return a copy of the current image in the video renderer // HRESULT CVideoText::GetStaticImage(long *pBufferSize,long *pDIBImage) { NOTE("Entering GetStaticImage"); IMediaSample *pMediaSample; pMediaSample = m_pRenderer->GetCurrentSample(); RECT SourceRect; // Is there an image available if (pMediaSample == NULL) return E_UNEXPECTED; // Find a scaled source rectangle for the current bitmap m_pRenderer->m_DrawImage.GetSourceRect(&SourceRect); SourceRect = m_pRenderer->m_DrawImage.ScaleSourceRect(&SourceRect); VIDEOINFOHEADER *pVideoInfo = (VIDEOINFOHEADER *) m_pRenderer->m_mtIn.Format(); // Call the base class helper method to do the work HRESULT hr = CopyImage(pMediaSample, // Buffer containing image pVideoInfo, // Type representing bitmap pBufferSize, // Size of buffer for DIB (BYTE*) pDIBImage, // Data buffer for output &SourceRect); // Current source position pMediaSample->Release(); return hr; } // GetStaticImage
HRESULT CPullPin::CollectAndDeliver( REFERENCE_TIME tStart, REFERENCE_TIME tStop) { IMediaSample* pSample = NULL; // better be sure pSample is set DWORD_PTR dwUnused; HRESULT hr = m_pReader->WaitForNext( INFINITE, &pSample, &dwUnused); if (FAILED(hr)) { if (pSample) { pSample->Release(); } } else { hr = DeliverSample(pSample, tStart, tStop); } if (FAILED(hr)) { CleanupCancelled(); OnError(hr); } return hr; }
MediaChunk::~MediaChunk() { // I wanted to use list<IMediaSamplePtr> but the // compiler could not handle the deep nesting of templates while(m_Samples.size() > 0) { IMediaSample* pSample = m_Samples.front(); pSample->Release(); m_Samples.pop_front(); } }
HRESULT OutputPin::Push(void *buf, long size) { HRESULT hr; IMediaSample *pSample; VIDEOINFOHEADER *vi; AM_MEDIA_TYPE *pmt; BYTE *dst_buf; /** * Hold the critical section here as the pin might get disconnected * during the Deliver() method call. */ m_pLock->Lock(); hr = GetDeliveryBuffer(&pSample, NULL, NULL, 0); if (FAILED(hr)) goto on_error; pSample->GetMediaType(&pmt); if (pmt) { mediaType.Set(*pmt); bufSize = pmt->lSampleSize; } pSample->GetPointer(&dst_buf); vi = (VIDEOINFOHEADER *)mediaType.pbFormat; if (vi->rcSource.right == vi->bmiHeader.biWidth) { assert(pSample->GetSize() >= size); memcpy(dst_buf, buf, size); } else { unsigned i, bpp; unsigned dststride, srcstride; BYTE *src_buf = (BYTE *)buf; bpp = size / abs(vi->bmiHeader.biHeight) / vi->rcSource.right; dststride = vi->bmiHeader.biWidth * bpp; srcstride = vi->rcSource.right * bpp; for (i = abs(vi->bmiHeader.biHeight); i > 0; i--) { memcpy(dst_buf, src_buf, srcstride); dst_buf += dststride; src_buf += srcstride; } } pSample->SetActualDataLength(size); hr = Deliver(pSample); pSample->Release(); on_error: m_pLock->Unlock(); return hr; }
HRESULT COutputPin::DeliverSample(GstBuffer *pBuffer) { HRESULT hr = S_OK; IMediaSample *pSample = NULL; REFERENCE_TIME start = -1; REFERENCE_TIME stop = -1; hr = m_pAlloc->SetGstBuffer(pBuffer); if (FAILED(hr)) return hr; hr = GetDeliveryBuffer(&pSample, NULL, NULL, 0); if (FAILED(hr)) return hr; // Set media time pSample->SetMediaTime(NULL, NULL); // Set time if (GST_BUFFER_TIMESTAMP_IS_VALID(pBuffer)) { start = GST_BUFFER_TIMESTAMP(pBuffer) / 100; if (GST_BUFFER_DURATION_IS_VALID(pBuffer)) { stop = (GST_BUFFER_TIMESTAMP(pBuffer) + GST_BUFFER_DURATION(pBuffer)) / 100; } else { stop = start + 1; } if (stop <= start) // Sometimes it may happen stop = start + 1; pSample->SetTime(&start, &stop); } else { pSample->SetTime(NULL, NULL); } if (GST_BUFFER_IS_DISCONT(pBuffer)) pSample->SetDiscontinuity(TRUE); hr = Deliver(pSample); pSample->Release(); if (FAILED(hr)) return hr; return S_OK; }
HRESULT STDMETHODCALLTYPE CGraphConnector::ClearQueueContent( int OutInd ) { CAutoLock lock(&m_QueueLock); if( OutInd >= m_nNumOutputs ) return S_FALSE; while( m_pSampleQueue[OutInd].empty() == false ) { IMediaSample *p = m_pSampleQueue[OutInd].back(); m_pSampleQueue[OutInd].pop_back(); p->Release(); } return S_OK; }
DWORD STDCALL PackPlanarThread(ConvertData *data) { do { WaitForSingleObject(data->hSignalConvert, INFINITE); if(data->bKillThread) break; IMediaSample *sample = data->sample; PackPlanar(data->output, data->input, data->width, data->height, data->pitch, data->startY, data->endY); sample->Release(); SetEvent(data->hSignalComplete); }while(!data->bKillThread); return 0; }
// after a flush, cancelled i/o will be waiting for collection // and release void CPullPin::CleanupCancelled(void) { while(1) { IMediaSample * pSample; DWORD_PTR dwUnused; HRESULT hr = m_pReader->WaitForNext(0, // no wait &pSample, &dwUnused); if(pSample) { pSample->Release(); } else { // no more samples return; } } }
// after a flush, cancelled i/o will be waiting for collection // and release void CPullPin::CleanupCancelled(void) { for (;;) { IMediaSample * pSample; DWORD_PTR dwUnused; HRESULT hr = m_pReader->WaitForNext( 0, // no wait &pSample, &dwUnused); UNREFERENCED_PARAMETER(hr); if(pSample) { pSample->Release(); } else { // no more samples return; } } }
HRESULT CAMROutputPin::DeliverDataPacketAMR(DataPacketAMR &packet) { IMediaSample *sample; HRESULT hr = GetDeliveryBuffer(&sample, NULL, NULL, 0); if (FAILED(hr)) { return E_FAIL; } // we should have enough space in there long lsize = sample->GetSize(); ASSERT(lsize >= packet.size); BYTE *buf; sample->GetPointer(&buf); memcpy(buf, packet.buf, packet.size); sample->SetActualDataLength(packet.size); // sync point, discontinuity ? if (packet.sync_point) { sample->SetSyncPoint(TRUE); } else { sample->SetSyncPoint(FALSE); } if (packet.discontinuity) { sample->SetDiscontinuity(TRUE); } else { sample->SetDiscontinuity(FALSE); } // do we have a time stamp ? if (packet.has_time) { sample->SetTime(&packet.rtStart, &packet.rtStop); } // dorucime hr = Deliver(sample); sample->Release(); return hr; }
//---------------------------------------------------------------------------- //! @brief サンプルをダウンストリームへ送り続ける処理 //! @return エラーコード //---------------------------------------------------------------------------- HRESULT CDemuxOutputPin::DoBufferProcessingLoop(void) { Command com; HRESULT hr; OnThreadStartPlay(); do { while( !CheckRequest(&com) ) { // Virtual function user will override. IMediaSample *pSample; hr = RetrieveBuffer(&pSample); if( hr == S_OK ) { hr = Deliver(pSample); pSample->Release(); if(hr != S_OK) { DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned %08x; stopping"), hr)); return S_OK; } } else if (hr == S_FALSE) { // derived class wants us to stop pushing data DeliverEndOfStream(); return S_OK; } else { // derived class encountered an error DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr)); DeliverEndOfStream(); m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0); return hr; } } if( com == CMD_RUN || com == CMD_PAUSE ) { Reply(NOERROR); } else if( com != CMD_STOP ) { Reply((DWORD) E_UNEXPECTED); DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!"))); } } while( com != CMD_STOP ); return S_FALSE; }
unsigned int __stdcall CBonSrcPin::StreamThread(LPVOID lpParameter) { CBonSrcPin *pThis = static_cast<CBonSrcPin*>(lpParameter); TRACE(TEXT("CBonSrcPin::StreamThread() Start\n")); ::CoInitialize(NULL); DWORD Wait = 0; while (::WaitForSingleObject(pThis->m_hEndEvent, Wait) == WAIT_TIMEOUT) { if (pThis->m_SrcStream.IsDataAvailable()) { // 空のメディアサンプルを要求する IMediaSample *pSample = NULL; HRESULT hr = pThis->GetDeliveryBuffer(&pSample, NULL, NULL, 0); if (SUCCEEDED(hr)) { // 書き込み先ポインタを取得する BYTE *pSampleData = NULL; hr = pSample->GetPointer(&pSampleData); if (SUCCEEDED(hr)) { DWORD Size = SAMPLE_PACKETS; if (pThis->m_SrcStream.GetData(pSampleData, &Size)) { pSample->SetActualDataLength(Size * TS_PACKETSIZE); pThis->Deliver(pSample); } pSample->Release(); } } Wait = 0; } else { Wait = 5; } } ::CoUninitialize(); TRACE(TEXT("CBonSrcPin::StreamThread() End\n")); return 0; }
// Remove and Release() all queued and Batched samples void COutputQueue::FreeSamples() { CAutoLock lck(this); if (IsQueued()) { while (TRUE) { IMediaSample *pSample = m_List->RemoveHead(); // inform derived class we took something off the queue if (m_hEventPop) { //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); SetEvent(m_hEventPop); } if (pSample == NULL) { break; } if (!IsSpecialSample(pSample)) { pSample->Release(); } else { if (pSample == NEW_SEGMENT) { // Free NEW_SEGMENT packet NewSegmentPacket *ppacket = (NewSegmentPacket *) m_List->RemoveHead(); // inform derived class we took something off the queue if (m_hEventPop) { //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); SetEvent(m_hEventPop); } ASSERT(ppacket != NULL); delete ppacket; } } } } for (int i = 0; i < m_nBatched; i++) { m_ppSamples[i]->Release(); } m_nBatched = 0; }
void CPullPin::Process(void) { // is there anything to do? if (m_tStop <= m_tStart) { EndOfStream(); return; } BOOL bDiscontinuity = TRUE; // if there is more than one sample at the allocator, // then try to queue 2 at once in order to overlap. // -- get buffer count and required alignment ALLOCATOR_PROPERTIES Actual; HRESULT hr = m_pAlloc->GetProperties(&Actual); // align the start position downwards REFERENCE_TIME tStart = AlignDown(m_tStart / UNITS, Actual.cbAlign) * UNITS; REFERENCE_TIME tCurrent = tStart; REFERENCE_TIME tStop = m_tStop; if (tStop > m_tDuration) { tStop = m_tDuration; } // align the stop position - may be past stop, but that // doesn't matter REFERENCE_TIME tAlignStop = AlignUp(tStop / UNITS, Actual.cbAlign) * UNITS; DWORD dwRequest; if (!m_bSync) { // Break out of the loop either if we get to the end or we're asked // to do something else while (tCurrent < tAlignStop) { // Break out without calling EndOfStream if we're asked to // do something different if (CheckRequest(&dwRequest)) { return; } // queue a first sample if (Actual.cBuffers > 1) { hr = QueueSample(tCurrent, tAlignStop, TRUE); bDiscontinuity = FALSE; if (FAILED(hr)) { return; } } // loop queueing second and waiting for first.. while (tCurrent < tAlignStop) { hr = QueueSample(tCurrent, tAlignStop, bDiscontinuity); bDiscontinuity = FALSE; if (FAILED(hr)) { return; } hr = CollectAndDeliver(tStart, tStop); if (S_OK != hr) { // stop if error, or if downstream filter said // to stop. return; } } if (Actual.cBuffers > 1) { hr = CollectAndDeliver(tStart, tStop); if (FAILED(hr)) { return; } } } } else { // sync version of above loop while (tCurrent < tAlignStop) { // Break out without calling EndOfStream if we're asked to // do something different if (CheckRequest(&dwRequest)) { return; } IMediaSample* pSample; hr = m_pAlloc->GetBuffer(&pSample, NULL, NULL, 0); if (FAILED(hr)) { OnError(hr); return; } LONGLONG tStopThis = tCurrent + (pSample->GetSize() * UNITS); if (tStopThis > tAlignStop) { tStopThis = tAlignStop; } pSample->SetTime(&tCurrent, &tStopThis); tCurrent = tStopThis; if (bDiscontinuity) { pSample->SetDiscontinuity(TRUE); bDiscontinuity = FALSE; } hr = m_pReader->SyncReadAligned(pSample); if (FAILED(hr)) { pSample->Release(); OnError(hr); return; } hr = DeliverSample(pSample, tStart, tStop); if (hr != S_OK) { if (FAILED(hr)) { OnError(hr); } return; } } } EndOfStream(); }
HRESULT CBufferFilter::Receive(IMediaSample* pSample) { /* Check for other streams and pass them on */ AM_SAMPLE2_PROPERTIES* const pProps = m_pInput->SampleProps(); if(pProps->dwStreamId != AM_STREAM_MEDIA) return m_pOutput->Deliver(pSample); HRESULT hr; ASSERT(pSample); IMediaSample* pOutSample; ASSERT(m_pOutput != NULL); // Set up the output sample hr = InitializeOutputSample(pSample, &pOutSample); if(FAILED(hr)) return hr; // Start timing the transform (if PERF is defined) MSR_START(m_idTransform); // have the derived class transform the data hr = Transform(pSample, pOutSample); // Stop the clock and log it (if PERF is defined) MSR_STOP(m_idTransform); if(FAILED(hr)) { DbgLog((LOG_TRACE,1,TEXT("Error from transform"))); } else { // the Transform() function can return S_FALSE to indicate that the // sample should not be delivered; we only deliver the sample if it's // really S_OK (same as NOERROR, of course.) if(hr == NOERROR) { hr = m_pOutput->Deliver(pOutSample); m_bSampleSkipped = FALSE; // last thing no longer dropped } else { // S_FALSE returned from Transform is a PRIVATE agreement // We should return NOERROR from Receive() in this cause because returning S_FALSE // from Receive() means that this is the end of the stream and no more data should // be sent. if(S_FALSE == hr) { // Release the sample before calling notify to avoid // deadlocks if the sample holds a lock on the system // such as DirectDraw buffers do pOutSample->Release(); m_bSampleSkipped = TRUE; if(!m_bQualityChanged) { NotifyEvent(EC_QUALITY_CHANGE,0,0); m_bQualityChanged = TRUE; } return NOERROR; } } } // release the output buffer. If the connected pin still needs it, // it will have addrefed it itself. pOutSample->Release(); return hr; }
HRESULT CMPIptvSourceStream::DoBufferProcessingLoop(void) { Command com; OnThreadStartPlay(); WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); #ifdef logging LogDebug("Starting grabber thread"); #endif sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; if (localip) { addr.sin_addr.s_addr = inet_addr(localip); } else { addr.sin_addr.s_addr = htonl(INADDR_ANY); } addr.sin_port = htons((u_short)port); ip_mreq imr; imr.imr_multiaddr.s_addr = inet_addr(ip); if (localip) { imr.imr_interface.s_addr = inet_addr(localip); } else { imr.imr_interface.s_addr = INADDR_ANY; } unsigned long nonblocking = 1; if((m_socket = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { /* u_long argp = 1; ioctlsocket(m_socket, FIONBIO, &argp); */ DWORD dw = TRUE; int dwLen = sizeof(dw); if(setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&dw, sizeof(dw)) < 0) { closesocket(m_socket); m_socket = -1; } if(setsockopt(m_socket, SOL_SOCKET, SO_BROADCAST, (const char*)&dw, sizeof(dw)) < 0) { closesocket(m_socket); m_socket = -1; } getsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, (char *)&dw, &dwLen); #ifdef logging LogDebug("Socket receive buffer is: %d (%d)", dw, dwLen); LogDebug("Trying to set receive buffer to %d", IPTV_SOCKET_BUFFER_SIZE); #endif dw = IPTV_SOCKET_BUFFER_SIZE; if(setsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, (const char*)&dw, sizeof(dw)) < 0) { closesocket(m_socket); m_socket = -1; } dwLen = sizeof(dw); getsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, (char *)&dw, &dwLen); #ifdef logging LogDebug("New socket receive buffer is: %d (%d)", dw, dwLen); #endif if (ioctlsocket(m_socket, FIONBIO, &nonblocking) != 0) { closesocket(m_socket); m_socket = -1; } if(bind(m_socket, (struct sockaddr*)&addr, sizeof(addr)) < 0) { closesocket(m_socket); m_socket = -1; } if(IN_MULTICAST(htonl(imr.imr_multiaddr.s_addr))) { int ret = setsockopt(m_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&imr, sizeof(imr)); if(ret < 0) ret = ::WSAGetLastError(); ret = ret; } } SetThreadPriority(m_hThread, THREAD_PRIORITY_TIME_CRITICAL); int fromlen = sizeof(addr); m_buffsize = 0; timeval tv; //Will be used for select() below tv.tv_sec = 0; tv.tv_usec = 100000; //100 msec do { BOOL requestAvail; while ((requestAvail = CheckRequest(&com)) == FALSE) { DWORD startRecvTime; startRecvTime = GetTickCount(); #ifdef FILL_DIRECTLY_INTO_BUFFER IMediaSample *pSample; char *pData; long cbData; HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); if (FAILED(hr)) continue; CheckPointer(pSample, E_POINTER); // Access the sample's data buffer pSample->GetPointer((BYTE **)&pData); cbData = pSample->GetSize(); #endif do { //Try to read the complete remaining buffer size //But stop reading after 100ms have passed (slow streams like internet radio) #ifdef FILL_DIRECTLY_INTO_BUFFER int len = recvfrom(m_socket, &pData[m_buffsize], cbData - m_buffsize, 0, (SOCKADDR*)&addr, &fromlen); #else int len = recvfrom(m_socket, &m_buffer[m_buffsize], IPTV_BUFFER_SIZE - m_buffsize, 0, (SOCKADDR*)&addr, &fromlen); #endif if(len <= 0) { //Wait until there's something in the receive buffer fd_set myFDsocket; myFDsocket.fd_count = 1; myFDsocket.fd_array[0] = m_socket; int selectRet = select(0, &myFDsocket, NULL, NULL, &tv); #ifdef logging LogDebug("select return code: %d", selectRet); #endif continue; //On error or nothing read just repeat the loop } #ifdef logging LogDebug("Read %d bytes at pos %d of %d", len, m_buffsize, IPTV_BUFFER_SIZE); #endif m_buffsize += len; #ifdef FILL_DIRECTLY_INTO_BUFFER } while ((requestAvail = CheckRequest(&com)) == FALSE && m_buffsize < (cbData * 3 / 4) && abs((signed long)(GetTickCount() - startRecvTime)) < 100); #else } while ((requestAvail = CheckRequest(&com)) == FALSE && m_buffsize < (IPTV_BUFFER_SIZE * 3 / 4) && abs((signed long)(GetTickCount() - startRecvTime)) < 100); #endif if (requestAvail) break; #ifndef FILL_DIRECTLY_INTO_BUFFER if (m_buffsize == 0) continue; //100ms passed but no buffer received IMediaSample *pSample; HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); if (FAILED(hr)) { continue; // go round again. Perhaps the error will go away // or the allocator is decommited & we will be asked to // exit soon. } #endif // fill buffer hr = FillBuffer(pSample); if (hr == S_OK) { hr = Deliver(pSample); pSample->Release(); // downstream filter returns S_FALSE if it wants us to // stop or an error if it's reporting an error. if(hr != S_OK) { #ifdef logging LogDebug("Deliver() returned %08x; stopping", hr); #endif if(m_socket >= 0) {closesocket(m_socket); m_socket = -1;} WSACleanup(); return S_OK; } } else if (hr == S_FALSE) { // derived class wants us to stop pushing data pSample->Release(); DeliverEndOfStream(); if(m_socket >= 0) {closesocket(m_socket); m_socket = -1;} WSACleanup(); return S_OK; } else { // derived class encountered an error pSample->Release(); #ifdef logging LogDebug("Error %08lX from FillBuffer!!!", hr); #endif DeliverEndOfStream(); m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0); if(m_socket >= 0) {closesocket(m_socket); m_socket = -1;} WSACleanup(); return hr; } // all paths release the sample } // For all commands sent to us there must be a Reply call! if (com == CMD_RUN || com == CMD_PAUSE) { Reply(NOERROR); } else if (com != CMD_STOP) { Reply((DWORD) E_UNEXPECTED); #ifdef logging LogDebug("Unexpected command %d!!!", com); #endif } } while (com != CMD_STOP);
// the loop executed while running HRESULT FCapturePin::DoBufferProcessingLoop(void) { Command com; OnThreadStartPlay(); int32 LastFrame = -1; do { while (!CheckRequest(&com)) { // Wait for the next frame from the game thread if ( !GCaptureSyncEvent->Wait(1000) ) { FPlatformProcess::Sleep( 0.01f ); continue; // Reevaluate request } IMediaSample *pSample; int32 FrameNumber = FAVIWriter::GetInstance()->GetFrameNumber(); if (FrameNumber > LastFrame) { UE_LOG(LogMovieCapture, Log, TEXT(" FrameNumber > LastFrame = %d > %d"), FrameNumber, LastFrame); HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); if (FAILED(hr)) { if (pSample) { pSample->Release(); } } else { LastFrame = FrameNumber; hr = FillBuffer(pSample); if (hr == S_OK) { hr = Deliver(pSample); pSample->Release(); // downstream filter returns S_FALSE if it wants us to // stop or an error if it's reporting an error. if(hr != S_OK) { UE_LOG(LogMovieCapture, Log, TEXT("Deliver() returned %08x; stopping"), hr); return S_OK; } } } } // Allow the game thread read more data GCaptureSyncEvent->Trigger(); } // For all commands sent to us there must be a Reply call! if (com == CMD_RUN || com == CMD_PAUSE) { Reply(NOERROR); } else if (com != CMD_STOP) { Reply((uint32) E_UNEXPECTED); } } while (com != CMD_STOP); return S_FALSE; }
HRESULT CAudioPin::DoBufferProcessingLoop(void) { if (!m_bConnected) { return S_OK; m_bThreadRunning = false; } Command com; OnThreadStartPlay(); m_bThreadRunning = true; SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); do { while (!CheckRequest(&com)) { IMediaSample *pSample; HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); if (FAILED(hr)) { Sleep(1); continue; // go round again. Perhaps the error will go away // or the allocator is decommited & we will be asked to // exit soon. } // Virtual function user will override. hr = FillBuffer(pSample); if (hr == S_OK) { // Some decoders seem to crash when we provide empty samples if ((pSample->GetActualDataLength() > 0) && !m_pTsReaderFilter->IsStopping() && m_bConnected) { hr = Deliver(pSample); m_sampleCount++ ; } else { m_bDiscontinuity = true; } pSample->Release(); // downstream filter returns S_FALSE if it wants us to // stop or an error if it's reporting an error. if(hr != S_OK) { DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned %08x; stopping"), hr)); m_bThreadRunning = false; return S_OK; } } else if (hr == S_FALSE) { // derived class wants us to stop pushing data pSample->Release(); DeliverEndOfStream(); m_bThreadRunning = false; return S_OK; } else { // derived class encountered an error pSample->Release(); DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr)); DeliverEndOfStream(); m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0); m_bThreadRunning = false; return hr; } // all paths release the sample } // For all commands sent to us there must be a Reply call! if (com == CMD_RUN || com == CMD_PAUSE) { Reply(NOERROR); } else if (com != CMD_STOP) { Reply((DWORD) E_UNEXPECTED); DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!"))); } } while (com != CMD_STOP); m_bThreadRunning = false; return S_FALSE; }
// // DoBufferProcessingLoop // // Grabs a buffer and calls the users processing function. // Overridable, so that different delivery styles can be catered for. HRESULT CSourceStream::DoBufferProcessingLoop(void) { Command com; OnThreadStartPlay(); do { while (!CheckRequest(&com)) { IMediaSample *pSample; HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); if (FAILED(hr)) { Sleep(1); continue; // go round again. Perhaps the error will go away // or the allocator is decommited & we will be asked to // exit soon. } // Virtual function user will override. hr = FillBuffer(pSample); if (hr == S_OK) { hr = Deliver(pSample); pSample->Release(); // downstream filter returns S_FALSE if it wants us to // stop or an error if it's reporting an error. if(hr != S_OK) { DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned %08x; stopping"), hr)); return S_OK; } } else if (hr == S_FALSE) { // derived class wants us to stop pushing data pSample->Release(); DeliverEndOfStream(); return S_OK; } else { // derived class encountered an error pSample->Release(); DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr)); DeliverEndOfStream(); m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0); return hr; } // all paths release the sample } // For all commands sent to us there must be a Reply call! if (com == CMD_RUN || com == CMD_PAUSE) { Reply(NOERROR); } else if (com != CMD_STOP) { Reply((DWORD) E_UNEXPECTED); DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!"))); } } while (com != CMD_STOP); return S_FALSE; }
HRESULT CWavPackDSSplitterInputPin::DeliverOneFrame(WavPack_parser* wpp) { IMediaSample *pSample; BYTE *Buffer = NULL; HRESULT hr; unsigned long FrameLenBytes = 0, FrameLenSamples = 0, FrameIndex = 0; // Get a new media sample hr = m_pParentFilter->m_pOutputPin->GetDeliveryBuffer(&pSample, NULL, NULL, 0); if (FAILED(hr)) { DebugLog("CWavPackDSSplitterInputPin::DoProcessingLoop GetDeliveryBuffer failed 0x%08X",hr); return hr; } hr = pSample->GetPointer(&Buffer); if (FAILED(hr)) { DebugLog("CWavPackDSSplitterInputPin::DoProcessingLoop GetPointer failed 0x%08X",hr); pSample->Release(); return hr; } FrameLenBytes = wavpack_parser_read_frame(wpp, Buffer, &FrameIndex, &FrameLenSamples); if(!FrameLenBytes) { // Something bad happened, let's end here pSample->Release(); m_pParentFilter->m_pOutputPin->DeliverEndOfStream(); // TODO : check if we need to stop the thread DebugLog("CWavPackDSSplitterInputPin::DoProcessingLoop wavpack_parser_read_frame error"); return hr; } pSample->SetActualDataLength(FrameLenBytes); if(wpp->is_correction == TRUE) { IMediaSample2 *pSample2; if (SUCCEEDED(pSample->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) { AM_SAMPLE2_PROPERTIES ams2p; ZeroMemory(&ams2p, sizeof(AM_SAMPLE2_PROPERTIES)); hr = pSample2->GetProperties(sizeof(AM_SAMPLE2_PROPERTIES), (PBYTE)&ams2p); if(SUCCEEDED(hr)) { ams2p.dwStreamId = AM_STREAM_BLOCK_ADDITIONNAL; pSample2->SetProperties(sizeof(AM_SAMPLE2_PROPERTIES), (PBYTE)&ams2p); } pSample2->Release(); pSample2 = NULL; } } REFERENCE_TIME rtStart, rtStop; rtStart = FrameIndex; rtStop = rtStart + FrameLenSamples; rtStart = (rtStart * 10000000) / wpp->sample_rate; rtStop = (rtStop * 10000000) / wpp->sample_rate; rtStart -= m_pParentFilter->m_rtStart; rtStop -= m_pParentFilter->m_rtStart; pSample->SetTime(&rtStart, &rtStop); pSample->SetPreroll(FALSE); pSample->SetDiscontinuity(m_bDiscontinuity); if(m_bDiscontinuity) { m_bDiscontinuity = FALSE; } pSample->SetSyncPoint(TRUE); // Deliver the sample hr = m_pParentFilter->m_pOutputPin->Deliver(pSample); pSample->Release(); pSample = NULL; if (FAILED(hr)) { DebugLog("CWavPackDSSplitterInputPin::DoProcessingLoop Deliver failed 0x%08X",hr); return hr; } return S_OK; }
STDMETHODIMP CLAVSubtitleConsumer::ProcessFrame(LAVFrame *pFrame) { CheckPointer(m_pProvider, E_FAIL); HRESULT hr = S_OK; LPDIRECT3DSURFACE9 pSurface = nullptr; // Wait for the requested frame m_evFrame.Wait(); if (m_SubtitleFrame != nullptr) { int count = 0; if (FAILED(m_SubtitleFrame->GetBitmapCount(&count))) { count = 0; } if (count == 0) { SafeRelease(&m_SubtitleFrame); return S_FALSE; } BYTE *data[4] = {0}; ptrdiff_t stride[4] = {0}; LAVPixelFormat format = pFrame->format; int bpp = pFrame->bpp; if (pFrame->format == LAVPixFmt_DXVA2) { // Copy the surface, if required if (!(pFrame->flags & LAV_FRAME_FLAG_BUFFER_MODIFY)) { IMediaSample *pOrigSample = (IMediaSample *)pFrame->data[0]; LPDIRECT3DSURFACE9 pOrigSurface = (LPDIRECT3DSURFACE9)pFrame->data[3]; hr = m_pLAVVideo->GetD3DBuffer(pFrame); if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"CLAVSubtitleConsumer::ProcessFrame: getting a new D3D buffer failed")); } else { IMediaSample *pNewSample = (IMediaSample *)pFrame->data[0]; pSurface = (LPDIRECT3DSURFACE9)pFrame->data[3]; IDirect3DDevice9 *pDevice = nullptr; if (SUCCEEDED(hr = pSurface->GetDevice(&pDevice))) { hr = pDevice->StretchRect(pOrigSurface, nullptr, pSurface, nullptr, D3DTEXF_NONE); if (SUCCEEDED(hr)) { pFrame->flags |= LAV_FRAME_FLAG_BUFFER_MODIFY|LAV_FRAME_FLAG_DXVA_NOADDREF; pOrigSurface = nullptr; // Release the surface, we only want to hold a ref on the media buffer pSurface->Release(); } SafeRelease(&pDevice); } if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"CLAVSubtitleConsumer::ProcessFrame: processing d3d buffer failed, restoring previous buffer")); pNewSample->Release(); pSurface->Release(); pFrame->data[0] = (BYTE *)pOrigSample; pFrame->data[3] = (BYTE *)pOrigSurface; } } } pSurface = (LPDIRECT3DSURFACE9)pFrame->data[3]; D3DSURFACE_DESC surfaceDesc; pSurface->GetDesc(&surfaceDesc); D3DLOCKED_RECT LockedRect; hr = pSurface->LockRect(&LockedRect, nullptr, 0); if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"pSurface->LockRect failed (hr: %X)", hr)); SafeRelease(&m_SubtitleFrame); return E_FAIL; } data[0] = (BYTE *)LockedRect.pBits; data[1] = data[0] + (surfaceDesc.Height * LockedRect.Pitch); stride[0] = LockedRect.Pitch; stride[1] = LockedRect.Pitch; format = LAVPixFmt_NV12; bpp = 8; } else { if (!(pFrame->flags & LAV_FRAME_FLAG_BUFFER_MODIFY)) { CopyLAVFrameInPlace(pFrame); } memcpy(&data, &pFrame->data, sizeof(pFrame->data)); memcpy(&stride, &pFrame->stride, sizeof(pFrame->stride)); } RECT videoRect; ::SetRect(&videoRect, 0, 0, pFrame->width, pFrame->height); RECT subRect; m_SubtitleFrame->GetOutputRect(&subRect); ULONGLONG id; POINT position; SIZE size; const uint8_t *rgbData; int pitch; for (int i = 0; i < count; i++) { if (FAILED(m_SubtitleFrame->GetBitmap(i, &id, &position, &size, (LPCVOID *)&rgbData, &pitch))) { DbgLog((LOG_TRACE, 10, L"GetBitmap() failed on index %d", i)); break; } ProcessSubtitleBitmap(format, bpp, videoRect, data, stride, subRect, position, size, rgbData, pitch); } if (pSurface) pSurface->UnlockRect(); SafeRelease(&m_SubtitleFrame); return S_OK; } return S_FALSE; }
HRESULT CVideoTransformFilter::Receive(IMediaSample *pSample) { // If the next filter downstream is the video renderer, then it may // be able to operate in DirectDraw mode which saves copying the data // and gives higher performance. In that case the buffer which we // get from GetDeliveryBuffer will be a DirectDraw buffer, and // drawing into this buffer draws directly onto the display surface. // This means that any waiting for the correct time to draw occurs // during GetDeliveryBuffer, and that once the buffer is given to us // the video renderer will count it in its statistics as a frame drawn. // This means that any decision to drop the frame must be taken before // calling GetDeliveryBuffer. ASSERT(CritCheckIn(&m_csReceive)); AM_MEDIA_TYPE *pmtOut, *pmt; #ifdef _DEBUG FOURCCMap fccOut; #endif HRESULT hr; ASSERT(pSample); IMediaSample * pOutSample; // If no output pin to deliver to then no point sending us data ASSERT (m_pOutput != NULL) ; // The source filter may dynamically ask us to start transforming from a // different media type than the one we're using now. If we don't, we'll // draw garbage. (typically, this is a palette change in the movie, // but could be something more sinister like the compression type changing, // or even the video size changing) #define rcS1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcSource #define rcT1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcTarget pSample->GetMediaType(&pmt); if (pmt != NULL && pmt->pbFormat != NULL) { // spew some debug output ASSERT(!IsEqualGUID(pmt->majortype, GUID_NULL)); #ifdef _DEBUG fccOut.SetFOURCC(&pmt->subtype); LONG lCompression = HEADER(pmt->pbFormat)->biCompression; LONG lBitCount = HEADER(pmt->pbFormat)->biBitCount; LONG lStride = (HEADER(pmt->pbFormat)->biWidth * lBitCount + 7) / 8; lStride = (lStride + 3) & ~3; DbgLog((LOG_TRACE,3,TEXT("*Changing input type on the fly to"))); DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"), fccOut.GetFOURCC(), lCompression, lBitCount)); DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"), HEADER(pmt->pbFormat)->biHeight, rcT1.left, rcT1.top, rcT1.right, rcT1.bottom)); DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"), rcS1.left, rcS1.top, rcS1.right, rcS1.bottom, lStride)); #endif // now switch to using the new format. I am assuming that the // derived filter will do the right thing when its media type is // switched and streaming is restarted. StopStreaming(); m_pInput->CurrentMediaType() = *pmt; DeleteMediaType(pmt); // if this fails, playback will stop, so signal an error hr = StartStreaming(); if (FAILED(hr)) { return AbortPlayback(hr); } } // Now that we have noticed any format changes on the input sample, it's // OK to discard it. if (ShouldSkipFrame(pSample)) { MSR_NOTE(m_idSkip); m_bSampleSkipped = TRUE; return NOERROR; } // Set up the output sample hr = InitializeOutputSample(pSample, &pOutSample); if (FAILED(hr)) { return hr; } m_bSampleSkipped = FALSE; // The renderer may ask us to on-the-fly to start transforming to a // different format. If we don't obey it, we'll draw garbage #define rcS ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcSource #define rcT ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcTarget pOutSample->GetMediaType(&pmtOut); if (pmtOut != NULL && pmtOut->pbFormat != NULL) { // spew some debug output ASSERT(!IsEqualGUID(pmtOut->majortype, GUID_NULL)); #ifdef _DEBUG fccOut.SetFOURCC(&pmtOut->subtype); LONG lCompression = HEADER(pmtOut->pbFormat)->biCompression; LONG lBitCount = HEADER(pmtOut->pbFormat)->biBitCount; LONG lStride = (HEADER(pmtOut->pbFormat)->biWidth * lBitCount + 7) / 8; lStride = (lStride + 3) & ~3; DbgLog((LOG_TRACE,3,TEXT("*Changing output type on the fly to"))); DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"), fccOut.GetFOURCC(), lCompression, lBitCount)); DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"), HEADER(pmtOut->pbFormat)->biHeight, rcT.left, rcT.top, rcT.right, rcT.bottom)); DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"), rcS.left, rcS.top, rcS.right, rcS.bottom, lStride)); #endif // now switch to using the new format. I am assuming that the // derived filter will do the right thing when its media type is // switched and streaming is restarted. StopStreaming(); m_pOutput->CurrentMediaType() = *pmtOut; DeleteMediaType(pmtOut); hr = StartStreaming(); if (SUCCEEDED(hr)) { // a new format, means a new empty buffer, so wait for a keyframe // before passing anything on to the renderer. // !!! a keyframe may never come, so give up after 30 frames DbgLog((LOG_TRACE,3,TEXT("Output format change means we must wait for a keyframe"))); m_nWaitForKey = 30; // if this fails, playback will stop, so signal an error } else { // Must release the sample before calling AbortPlayback // because we might be holding the win16 lock or // ddraw lock pOutSample->Release(); AbortPlayback(hr); return hr; } } // After a discontinuity, we need to wait for the next key frame if (pSample->IsDiscontinuity() == S_OK) { DbgLog((LOG_TRACE,3,TEXT("Non-key discontinuity - wait for keyframe"))); m_nWaitForKey = 30; } // Start timing the transform (and log it if PERF is defined) if (SUCCEEDED(hr)) { m_tDecodeStart = timeGetTime(); MSR_START(m_idTransform); // have the derived class transform the data hr = Transform(pSample, pOutSample); // Stop the clock (and log it if PERF is defined) MSR_STOP(m_idTransform); m_tDecodeStart = timeGetTime()-m_tDecodeStart; m_itrAvgDecode = m_tDecodeStart*(10000/16) + 15*(m_itrAvgDecode/16); // Maybe we're waiting for a keyframe still? if (m_nWaitForKey) m_nWaitForKey--; if (m_nWaitForKey && pSample->IsSyncPoint() == S_OK) m_nWaitForKey = FALSE; // if so, then we don't want to pass this on to the renderer if (m_nWaitForKey && hr == NOERROR) { DbgLog((LOG_TRACE,3,TEXT("still waiting for a keyframe"))); hr = S_FALSE; } } if (FAILED(hr)) { DbgLog((LOG_TRACE,1,TEXT("Error from video transform"))); } else { // the Transform() function can return S_FALSE to indicate that the // sample should not be delivered; we only deliver the sample if it's // really S_OK (same as NOERROR, of course.) // Try not to return S_FALSE to a direct draw buffer (it's wasteful) // Try to take the decision earlier - before you get it. if (hr == NOERROR) { hr = m_pOutput->Deliver(pOutSample); } else { // S_FALSE returned from Transform is a PRIVATE agreement // We should return NOERROR from Receive() in this case because returning S_FALSE // from Receive() means that this is the end of the stream and no more data should // be sent. if (S_FALSE == hr) { // We must Release() the sample before doing anything // like calling the filter graph because having the // sample means we may have the DirectDraw lock // (== win16 lock on some versions) pOutSample->Release(); m_bSampleSkipped = TRUE; if (!m_bQualityChanged) { m_bQualityChanged = TRUE; NotifyEvent(EC_QUALITY_CHANGE,0,0); } return NOERROR; } } } // release the output buffer. If the connected pin still needs it, // it will have addrefed it itself. pOutSample->Release(); ASSERT(CritCheckIn(&m_csReceive)); return hr; }
HRESULT CMpeg2DecoderDXVA2::DecodeFrame(IMediaSample **ppSample) { if (ppSample) { *ppSample = nullptr; } if (!m_pDec || !m_pVideoDecoder) { return E_UNEXPECTED; } if (m_pDec->picture->flags & PIC_FLAG_SKIP) { return GetDisplaySample(ppSample); } m_DecodeSampleIndex = GetFBufIndex(m_pDec->fbuf[0]); if (!m_SliceCount || m_DecodeSampleIndex < 0) { return S_FALSE; } if (m_fWaitForDecodeKeyFrame) { if ((m_pDec->picture->flags & PIC_MASK_CODING_TYPE) != PIC_FLAG_CODING_TYPE_I) { return S_FALSE; } m_fWaitForDecodeKeyFrame = false; } HRESULT hr; hr = m_pDeviceManager->TestDevice(m_pFilter->m_hDXVADevice); if (FAILED(hr)) { if (hr == DXVA2_E_NEW_VIDEO_DEVICE) { DBG_TRACE(TEXT("Device lost")); m_fDeviceLost = true; } return hr; } switch (m_pDec->picture->flags & PIC_MASK_CODING_TYPE) { case PIC_FLAG_CODING_TYPE_I: m_PrevRefSurfaceIndex = -1; m_ForwardRefSurfaceIndex = -1; //DBG_TRACE(TEXT("I [%d]"), m_CurSurfaceIndex); break; case PIC_FLAG_CODING_TYPE_P: m_PrevRefSurfaceIndex = GetFBufSampleID(m_pDec->fbuf[1]); m_ForwardRefSurfaceIndex = -1; //DBG_TRACE(TEXT("P [%d]->%d"), m_CurSurfaceIndex, m_PrevRefSurfaceIndex); break; case PIC_FLAG_CODING_TYPE_B: m_PrevRefSurfaceIndex = GetFBufSampleID(m_pDec->fbuf[1]); m_ForwardRefSurfaceIndex = GetFBufSampleID(m_pDec->fbuf[2]); //DBG_TRACE(TEXT("B %d->[%d]->%d"), m_PrevRefSurfaceIndex, m_CurSurfaceIndex, m_ForwardRefSurfaceIndex); if (m_ForwardRefSurfaceIndex < 0) return S_FALSE; break; } CDXVA2MediaSample *pSample = m_Samples[m_DecodeSampleIndex].pSample; if (!pSample) { IMediaSample *pMediaSample; IDXVA2MediaSample *pDXVA2Sample; for (;;) { hr = m_pFilter->GetDeliveryBuffer(&pMediaSample); if (FAILED(hr)) { return hr; } hr = pMediaSample->QueryInterface(IID_PPV_ARGS(&pDXVA2Sample)); pMediaSample->Release(); if (FAILED(hr)) { return hr; } pSample = static_cast<CDXVA2MediaSample*>(pDXVA2Sample); if (pSample->GetSurfaceID() == m_RefSamples[0].SurfaceID) { m_RefSamples[0].pSample = pSample; } else if (pSample->GetSurfaceID() == m_RefSamples[1].SurfaceID) { m_RefSamples[1].pSample = pSample; } else { break; } } m_Samples[m_DecodeSampleIndex].pSample = pSample; m_Samples[m_DecodeSampleIndex].SurfaceID = pSample->GetSurfaceID(); } m_CurSurfaceIndex = pSample->GetSurfaceID(); #ifdef _DEBUG if ((m_pDec->picture->flags & PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_P) { _ASSERT(m_PrevRefSurfaceIndex>=0 && m_CurSurfaceIndex != m_PrevRefSurfaceIndex); } else if ((m_pDec->picture->flags & PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_B) { _ASSERT(m_PrevRefSurfaceIndex>=0 && m_CurSurfaceIndex != m_PrevRefSurfaceIndex && m_ForwardRefSurfaceIndex>=0 && m_CurSurfaceIndex != m_ForwardRefSurfaceIndex); } #endif IDirect3DSurface9 *pSurface; IMFGetService *pMFGetService; hr = pSample->QueryInterface(IID_PPV_ARGS(&pMFGetService)); if (SUCCEEDED(hr)) { hr = pMFGetService->GetService(MR_BUFFER_SERVICE, IID_PPV_ARGS(&pSurface)); pMFGetService->Release(); } if (FAILED(hr)) { return hr; } int Retry = 0; for (;;) { hr = m_pVideoDecoder->BeginFrame(pSurface, nullptr); if (hr != E_PENDING || Retry >= 50) break; ::Sleep(2); Retry++; } if (SUCCEEDED(hr)) { hr = CommitBuffers(); if (SUCCEEDED(hr)) { DXVA2_DecodeExecuteParams ExecParams; DXVA2_DecodeBufferDesc BufferDesc[4]; const UINT NumMBsInBuffer = (m_PictureParams.wPicWidthInMBminus1 + 1) * (m_PictureParams.wPicHeightInMBminus1 + 1); ::ZeroMemory(BufferDesc, sizeof(BufferDesc)); BufferDesc[0].CompressedBufferType = DXVA2_PictureParametersBufferType; BufferDesc[0].DataSize = sizeof(DXVA_PictureParameters); BufferDesc[1].CompressedBufferType = DXVA2_InverseQuantizationMatrixBufferType; BufferDesc[1].DataSize = sizeof(DXVA_QmatrixData); BufferDesc[2].CompressedBufferType = DXVA2_BitStreamDateBufferType; BufferDesc[2].DataSize = (UINT)m_SliceDataSize; BufferDesc[2].NumMBsInBuffer = NumMBsInBuffer; BufferDesc[3].CompressedBufferType = DXVA2_SliceControlBufferType; BufferDesc[3].DataSize = m_SliceCount * sizeof(DXVA_SliceInfo); BufferDesc[3].NumMBsInBuffer = NumMBsInBuffer; ExecParams.NumCompBuffers = 4; ExecParams.pCompressedBuffers = BufferDesc; ExecParams.pExtensionData = nullptr; hr = m_pVideoDecoder->Execute(&ExecParams); if (SUCCEEDED(hr)) { hr = GetDisplaySample(ppSample); } } m_pVideoDecoder->EndFrame(nullptr); } if ((m_pDec->picture->flags & PIC_MASK_CODING_TYPE) != PIC_FLAG_CODING_TYPE_B && ppSample) { SafeRelease(m_RefSamples[1].pSample); m_RefSamples[1] = m_RefSamples[0]; m_RefSamples[0].pSample = nullptr; m_RefSamples[0].SurfaceID = m_CurSurfaceIndex; } pSurface->Release(); return hr; }
// // Copy // // return a pointer to an identical copy of pSample IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource) { IMediaSample * pDest; HRESULT hr; REFERENCE_TIME tStart, tStop; const BOOL bTime = S_OK == pSource->GetTime( &tStart, &tStop); // this may block for an indeterminate amount of time hr = OutputPin()->PeekAllocator()->GetBuffer( &pDest , bTime ? &tStart : NULL , bTime ? &tStop : NULL , m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0 ); if (FAILED(hr)) { return NULL; } ASSERT(pDest); IMediaSample2 *pSample2; if (SUCCEEDED(pDest->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) { HRESULT hr = pSample2->SetProperties( FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, pbBuffer), (PBYTE)m_pInput->SampleProps()); pSample2->Release(); if (FAILED(hr)) { pDest->Release(); return NULL; } } else { if (bTime) { pDest->SetTime(&tStart, &tStop); } if (S_OK == pSource->IsSyncPoint()) { pDest->SetSyncPoint(TRUE); } if (S_OK == pSource->IsDiscontinuity() || m_bSampleSkipped) { pDest->SetDiscontinuity(TRUE); } if (S_OK == pSource->IsPreroll()) { pDest->SetPreroll(TRUE); } // Copy the media type AM_MEDIA_TYPE *pMediaType; if (S_OK == pSource->GetMediaType(&pMediaType)) { pDest->SetMediaType(pMediaType); DeleteMediaType( pMediaType ); } } m_bSampleSkipped = FALSE; // Copy the sample media times REFERENCE_TIME TimeStart, TimeEnd; if (pSource->GetMediaTime(&TimeStart,&TimeEnd) == NOERROR) { pDest->SetMediaTime(&TimeStart,&TimeEnd); } // Copy the actual data length and the actual data. { const long lDataLength = pSource->GetActualDataLength(); pDest->SetActualDataLength(lDataLength); // Copy the sample data { BYTE *pSourceBuffer, *pDestBuffer; long lSourceSize = pSource->GetSize(); long lDestSize = pDest->GetSize(); ASSERT(lDestSize >= lSourceSize && lDestSize >= lDataLength); pSource->GetPointer(&pSourceBuffer); pDest->GetPointer(&pDestBuffer); ASSERT(lDestSize == 0 || pSourceBuffer != NULL && pDestBuffer != NULL); CopyMemory( (PVOID) pDestBuffer, (PVOID) pSourceBuffer, lDataLength ); } } return pDest; } // Copy