802 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			802 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
								 | 
							
								//------------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								// File: OutputQ.cpp
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Desc: DirectShow base classes - implements COutputQueue class used by an
							 | 
						||
| 
								 | 
							
								//       output pin which may sometimes want to queue output samples on a
							 | 
						||
| 
								 | 
							
								//       separate thread and sometimes call Receive() directly on the input
							 | 
						||
| 
								 | 
							
								//       pin.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Copyright (c) 1992-2001 Microsoft Corporation.  All rights reserved.
							 | 
						||
| 
								 | 
							
								//------------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <streams.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  COutputQueue Constructor :
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  Determines if a thread is to be created and creates resources
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//     pInputPin  - the downstream input pin we're queueing samples to
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//     phr        - changed to a failure code if this function fails
							 | 
						||
| 
								 | 
							
								//                  (otherwise unchanges)
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//     bAuto      - Ask pInputPin if it can block in Receive by calling
							 | 
						||
| 
								 | 
							
								//                  its ReceiveCanBlock method and create a thread if
							 | 
						||
| 
								 | 
							
								//                  it can block, otherwise not.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//     bQueue     - if bAuto == FALSE then we create a thread if and only
							 | 
						||
| 
								 | 
							
								//                  if bQueue == TRUE
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//     lBatchSize - work in batches of lBatchSize
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//     bBatchEact - Use exact batch sizes so don't send until the
							 | 
						||
| 
								 | 
							
								//                  batch is full or SendAnyway() is called
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//     lListSize  - If we create a thread make the list of samples queued
							 | 
						||
| 
								 | 
							
								//                  to the thread have this size cache
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//     dwPriority - If we create a thread set its priority to this
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								COutputQueue::COutputQueue(
							 | 
						||
| 
								 | 
							
								             IPin         *pInputPin,          //  Pin to send stuff to
							 | 
						||
| 
								 | 
							
								             __inout HRESULT      *phr,        //  'Return code'
							 | 
						||
| 
								 | 
							
								             BOOL          bAuto,              //  Ask pin if queue or not
							 | 
						||
| 
								 | 
							
								             BOOL          bQueue,             //  Send through queue
							 | 
						||
| 
								 | 
							
								             LONG          lBatchSize,         //  Batch
							 | 
						||
| 
								 | 
							
								             BOOL          bBatchExact,        //  Batch exactly to BatchSize
							 | 
						||
| 
								 | 
							
								             LONG          lListSize,
							 | 
						||
| 
								 | 
							
								             DWORD         dwPriority,
							 | 
						||
| 
								 | 
							
								             bool          bFlushingOpt        // flushing optimization
							 | 
						||
| 
								 | 
							
								            ) : m_lBatchSize(lBatchSize),
							 | 
						||
| 
								 | 
							
								                m_bBatchExact(bBatchExact && (lBatchSize > 1)),
							 | 
						||
| 
								 | 
							
								                m_hThread(NULL),
							 | 
						||
| 
								 | 
							
								                m_hSem(NULL),
							 | 
						||
| 
								 | 
							
								                m_List(NULL),
							 | 
						||
| 
								 | 
							
								                m_pPin(pInputPin),
							 | 
						||
| 
								 | 
							
								                m_ppSamples(NULL),
							 | 
						||
| 
								 | 
							
								                m_lWaiting(0),
							 | 
						||
| 
								 | 
							
								                m_evFlushComplete(FALSE, phr),
							 | 
						||
| 
								 | 
							
								                m_pInputPin(NULL),
							 | 
						||
| 
								 | 
							
								                m_bSendAnyway(FALSE),
							 | 
						||
| 
								 | 
							
								                m_nBatched(0),
							 | 
						||
| 
								 | 
							
								                m_bFlushing(FALSE),
							 | 
						||
| 
								 | 
							
								                m_bFlushed(TRUE),
							 | 
						||
| 
								 | 
							
								                m_bFlushingOpt(bFlushingOpt),
							 | 
						||
| 
								 | 
							
								                m_bTerminate(FALSE),
							 | 
						||
| 
								 | 
							
								                m_hEventPop(NULL),
							 | 
						||
| 
								 | 
							
								                m_hr(S_OK)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    ASSERT(m_lBatchSize > 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (FAILED(*phr)) {
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //  Check the input pin is OK and cache its IMemInputPin interface
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    *phr = pInputPin->QueryInterface(IID_IMemInputPin, (void **)&m_pInputPin);
							 | 
						||
| 
								 | 
							
								    if (FAILED(*phr)) {
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // See if we should ask the downstream pin
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (bAuto) {
							 | 
						||
| 
								 | 
							
								        HRESULT hr = m_pInputPin->ReceiveCanBlock();
							 | 
						||
| 
								 | 
							
								        if (SUCCEEDED(hr)) {
							 | 
						||
| 
								 | 
							
								            bQueue = hr == S_OK;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //  Create our sample batch
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    m_ppSamples = new PMEDIASAMPLE[m_lBatchSize];
							 | 
						||
| 
								 | 
							
								    if (m_ppSamples == NULL) {
							 | 
						||
| 
								 | 
							
								        *phr = E_OUTOFMEMORY;
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //  If we're queueing allocate resources
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (bQueue) {
							 | 
						||
| 
								 | 
							
								        DbgLog((LOG_TRACE, 2, TEXT("Creating thread for output pin")));
							 | 
						||
| 
								 | 
							
								        m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL);
							 | 
						||
| 
								 | 
							
								        if (m_hSem == NULL) {
							 | 
						||
| 
								 | 
							
								            DWORD dwError = GetLastError();
							 | 
						||
| 
								 | 
							
								            *phr = AmHresultFromWin32(dwError);
							 | 
						||
| 
								 | 
							
								            return;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        m_List = new CSampleList(NAME("Sample Queue List"),
							 | 
						||
| 
								 | 
							
								                                 lListSize,
							 | 
						||
| 
								 | 
							
								                                 FALSE         // No lock
							 | 
						||
| 
								 | 
							
								                                );
							 | 
						||
| 
								 | 
							
								        if (m_List == NULL) {
							 | 
						||
| 
								 | 
							
								            *phr = E_OUTOFMEMORY;
							 | 
						||
| 
								 | 
							
								            return;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        DWORD dwThreadId;
							 | 
						||
| 
								 | 
							
								        m_hThread = CreateThread(NULL,
							 | 
						||
| 
								 | 
							
								                                 0,
							 | 
						||
| 
								 | 
							
								                                 InitialThreadProc,
							 | 
						||
| 
								 | 
							
								                                 (LPVOID)this,
							 | 
						||
| 
								 | 
							
								                                 0,
							 | 
						||
| 
								 | 
							
								                                 &dwThreadId);
							 | 
						||
| 
								 | 
							
								        if (m_hThread == NULL) {
							 | 
						||
| 
								 | 
							
								            DWORD dwError = GetLastError();
							 | 
						||
| 
								 | 
							
								            *phr = AmHresultFromWin32(dwError);
							 | 
						||
| 
								 | 
							
								            return;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        SetThreadPriority(m_hThread, dwPriority);
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        DbgLog((LOG_TRACE, 2, TEXT("Calling input pin directly - no thread")));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  COutputQueuee Destructor :
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  Free all resources -
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//      Thread,
							 | 
						||
| 
								 | 
							
								//      Batched samples
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								COutputQueue::~COutputQueue()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    DbgLog((LOG_TRACE, 3, TEXT("COutputQueue::~COutputQueue")));
							 | 
						||
| 
								 | 
							
								    /*  Free our pointer */
							 | 
						||
| 
								 | 
							
								    if (m_pInputPin != NULL) {
							 | 
						||
| 
								 | 
							
								        m_pInputPin->Release();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (m_hThread != NULL) {
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            CAutoLock lck(this);
							 | 
						||
| 
								 | 
							
								            m_bTerminate = TRUE;
							 | 
						||
| 
								 | 
							
								            m_hr = S_FALSE;
							 | 
						||
| 
								 | 
							
								            NotifyThread();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        DbgWaitForSingleObject(m_hThread);
							 | 
						||
| 
								 | 
							
								        EXECUTE_ASSERT(CloseHandle(m_hThread));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //  The thread frees the samples when asked to terminate
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ASSERT(m_List->GetCount() == 0);
							 | 
						||
| 
								 | 
							
								        delete m_List;
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        FreeSamples();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (m_hSem != NULL) {
							 | 
						||
| 
								 | 
							
								        EXECUTE_ASSERT(CloseHandle(m_hSem));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    delete [] m_ppSamples;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  Call the real thread proc as a member function
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								DWORD WINAPI COutputQueue::InitialThreadProc(__in LPVOID pv)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    HRESULT hrCoInit = CAMThread::CoInitializeHelper();
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    COutputQueue *pSampleQueue = (COutputQueue *)pv;
							 | 
						||
| 
								 | 
							
								    DWORD dwReturn = pSampleQueue->ThreadProc();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if(hrCoInit == S_OK) {
							 | 
						||
| 
								 | 
							
								        CoUninitialize();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    return dwReturn;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  Thread sending the samples downstream :
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  When there is nothing to do the thread sets m_lWaiting (while
							 | 
						||
| 
								 | 
							
								//  holding the critical section) and then waits for m_hSem to be
							 | 
						||
| 
								 | 
							
								//  set (not holding the critical section)
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								DWORD COutputQueue::ThreadProc()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    while (TRUE) {
							 | 
						||
| 
								 | 
							
								        BOOL          bWait = FALSE;
							 | 
						||
| 
								 | 
							
								        IMediaSample *pSample;
							 | 
						||
| 
								 | 
							
								        LONG          lNumberToSend; // Local copy
							 | 
						||
| 
								 | 
							
								        NewSegmentPacket* ppacket;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //
							 | 
						||
| 
								 | 
							
								        //  Get a batch of samples and send it if possible
							 | 
						||
| 
								 | 
							
								        //  In any case exit the loop if there is a control action
							 | 
						||
| 
								 | 
							
								        //  requested
							 | 
						||
| 
								 | 
							
								        //
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            CAutoLock lck(this);
							 | 
						||
| 
								 | 
							
								            while (TRUE) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (m_bTerminate) {
							 | 
						||
| 
								 | 
							
								                    FreeSamples();
							 | 
						||
| 
								 | 
							
								                    return 0;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                if (m_bFlushing) {
							 | 
						||
| 
								 | 
							
								                    FreeSamples();
							 | 
						||
| 
								 | 
							
								                    SetEvent(m_evFlushComplete);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                //  Get a sample off the list
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                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 &&
							 | 
						||
| 
								 | 
							
								                    !IsSpecialSample(pSample)) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    //  If its just a regular sample just add it to the batch
							 | 
						||
| 
								 | 
							
								                    //  and exit the loop if the batch is full
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    m_ppSamples[m_nBatched++] = pSample;
							 | 
						||
| 
								 | 
							
								                    if (m_nBatched == m_lBatchSize) {
							 | 
						||
| 
								 | 
							
								                        break;
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                } else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    //  If there was nothing in the queue and there's nothing
							 | 
						||
| 
								 | 
							
								                    //  to send (either because there's nothing or the batch
							 | 
						||
| 
								 | 
							
								                    //  isn't full) then prepare to wait
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    if (pSample == NULL &&
							 | 
						||
| 
								 | 
							
								                        (m_bBatchExact || m_nBatched == 0)) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        //  Tell other thread to set the event when there's
							 | 
						||
| 
								 | 
							
								                        //  something do to
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        ASSERT(m_lWaiting == 0);
							 | 
						||
| 
								 | 
							
								                        m_lWaiting++;
							 | 
						||
| 
								 | 
							
								                        bWait      = TRUE;
							 | 
						||
| 
								 | 
							
								                    } else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        //  We break out of the loop on SEND_PACKET unless
							 | 
						||
| 
								 | 
							
								                        //  there's nothing to send
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        if (pSample == SEND_PACKET && m_nBatched == 0) {
							 | 
						||
| 
								 | 
							
								                            continue;
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        if (pSample == NEW_SEGMENT) {
							 | 
						||
| 
								 | 
							
								                            // now we need the parameters - we are
							 | 
						||
| 
								 | 
							
								                            // guaranteed that the next packet contains them
							 | 
						||
| 
								 | 
							
								                            ppacket = (NewSegmentPacket *) m_List->RemoveHead();
							 | 
						||
| 
								 | 
							
											    // we took something off the queue
							 | 
						||
| 
								 | 
							
											    if (m_hEventPop) {
							 | 
						||
| 
								 | 
							
								                    	        //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered  SET EVENT")));
							 | 
						||
| 
								 | 
							
										    	        SetEvent(m_hEventPop);
							 | 
						||
| 
								 | 
							
											    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                            ASSERT(ppacket);
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								                        //  EOS_PACKET falls through here and we exit the loop
							 | 
						||
| 
								 | 
							
								                        //  In this way it acts like SEND_PACKET
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                    break;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (!bWait) {
							 | 
						||
| 
								 | 
							
								                // We look at m_nBatched from the client side so keep
							 | 
						||
| 
								 | 
							
								                // it up to date inside the critical section
							 | 
						||
| 
								 | 
							
								                lNumberToSend = m_nBatched;  // Local copy
							 | 
						||
| 
								 | 
							
								                m_nBatched = 0;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //  Wait for some more data
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (bWait) {
							 | 
						||
| 
								 | 
							
								            DbgWaitForSingleObject(m_hSem);
							 | 
						||
| 
								 | 
							
								            continue;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //  OK - send it if there's anything to send
							 | 
						||
| 
								 | 
							
								        //  We DON'T check m_bBatchExact here because either we've got
							 | 
						||
| 
								 | 
							
								        //  a full batch or we dropped through because we got
							 | 
						||
| 
								 | 
							
								        //  SEND_PACKET or EOS_PACKET - both of which imply we should
							 | 
						||
| 
								 | 
							
								        //  flush our batch
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (lNumberToSend != 0) {
							 | 
						||
| 
								 | 
							
								            long nProcessed;
							 | 
						||
| 
								 | 
							
								            if (m_hr == S_OK) {
							 | 
						||
| 
								 | 
							
								                ASSERT(!m_bFlushed);
							 | 
						||
| 
								 | 
							
								                HRESULT hr = m_pInputPin->ReceiveMultiple(m_ppSamples,
							 | 
						||
| 
								 | 
							
								                                                          lNumberToSend,
							 | 
						||
| 
								 | 
							
								                                                          &nProcessed);
							 | 
						||
| 
								 | 
							
								                /*  Don't overwrite a flushing state HRESULT */
							 | 
						||
| 
								 | 
							
								                CAutoLock lck(this);
							 | 
						||
| 
								 | 
							
								                if (m_hr == S_OK) {
							 | 
						||
| 
								 | 
							
								                    m_hr = hr;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                ASSERT(!m_bFlushed);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            while (lNumberToSend != 0) {
							 | 
						||
| 
								 | 
							
								                m_ppSamples[--lNumberToSend]->Release();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (m_hr != S_OK) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                //  In any case wait for more data - S_OK just
							 | 
						||
| 
								 | 
							
								                //  means there wasn't an error
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                DbgLog((LOG_ERROR, 2, TEXT("ReceiveMultiple returned %8.8X"),
							 | 
						||
| 
								 | 
							
								                       m_hr));
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //  Check for end of stream
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (pSample == EOS_PACKET) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            //  We don't send even end of stream on if we've previously
							 | 
						||
| 
								 | 
							
								            //  returned something other than S_OK
							 | 
						||
| 
								 | 
							
								            //  This is because in that case the pin which returned
							 | 
						||
| 
								 | 
							
								            //  something other than S_OK should have either sent
							 | 
						||
| 
								 | 
							
								            //  EndOfStream() or notified the filter graph
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (m_hr == S_OK) {
							 | 
						||
| 
								 | 
							
								                DbgLog((LOG_TRACE, 2, TEXT("COutputQueue sending EndOfStream()")));
							 | 
						||
| 
								 | 
							
								                HRESULT hr = m_pPin->EndOfStream();
							 | 
						||
| 
								 | 
							
								                if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
								                    DbgLog((LOG_ERROR, 2, TEXT("COutputQueue got code 0x%8.8X from EndOfStream()")));
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //  Data from a new source
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (pSample == RESET_PACKET) {
							 | 
						||
| 
								 | 
							
								            m_hr = S_OK;
							 | 
						||
| 
								 | 
							
								            SetEvent(m_evFlushComplete);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (pSample == NEW_SEGMENT) {
							 | 
						||
| 
								 | 
							
								            m_pPin->NewSegment(ppacket->tStart, ppacket->tStop, ppacket->dRate);
							 | 
						||
| 
								 | 
							
								            delete ppacket;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//  Send batched stuff anyway
							 | 
						||
| 
								 | 
							
								void COutputQueue::SendAnyway()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (!IsQueued()) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //  m_bSendAnyway is a private parameter checked in ReceiveMultiple
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        m_bSendAnyway = TRUE;
							 | 
						||
| 
								 | 
							
								        LONG nProcessed;
							 | 
						||
| 
								 | 
							
								        ReceiveMultiple(NULL, 0, &nProcessed);
							 | 
						||
| 
								 | 
							
								        m_bSendAnyway = FALSE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        CAutoLock lck(this);
							 | 
						||
| 
								 | 
							
								        QueueSample(SEND_PACKET);
							 | 
						||
| 
								 | 
							
								        NotifyThread();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void
							 | 
						||
| 
								 | 
							
								COutputQueue::NewSegment(
							 | 
						||
| 
								 | 
							
								    REFERENCE_TIME tStart,
							 | 
						||
| 
								 | 
							
								    REFERENCE_TIME tStop,
							 | 
						||
| 
								 | 
							
								    double dRate)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (!IsQueued()) {
							 | 
						||
| 
								 | 
							
								        if (S_OK == m_hr) {
							 | 
						||
| 
								 | 
							
								            if (m_bBatchExact) {
							 | 
						||
| 
								 | 
							
								                SendAnyway();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            m_pPin->NewSegment(tStart, tStop, dRate);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        if (m_hr == S_OK) {
							 | 
						||
| 
								 | 
							
								            //
							 | 
						||
| 
								 | 
							
								            // we need to queue the new segment to appear in order in the
							 | 
						||
| 
								 | 
							
								            // data, but we need to pass parameters to it. Rather than
							 | 
						||
| 
								 | 
							
								            // take the hit of wrapping every single sample so we can tell
							 | 
						||
| 
								 | 
							
								            // special ones apart, we queue special pointers to indicate
							 | 
						||
| 
								 | 
							
								            // special packets, and we guarantee (by holding the
							 | 
						||
| 
								 | 
							
								            // critical section) that the packet immediately following a
							 | 
						||
| 
								 | 
							
								            // NEW_SEGMENT value is a NewSegmentPacket containing the
							 | 
						||
| 
								 | 
							
								            // parameters.
							 | 
						||
| 
								 | 
							
								            NewSegmentPacket * ppack = new NewSegmentPacket;
							 | 
						||
| 
								 | 
							
								            if (ppack == NULL) {
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            ppack->tStart = tStart;
							 | 
						||
| 
								 | 
							
								            ppack->tStop = tStop;
							 | 
						||
| 
								 | 
							
								            ppack->dRate = dRate;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            CAutoLock lck(this);
							 | 
						||
| 
								 | 
							
								            QueueSample(NEW_SEGMENT);
							 | 
						||
| 
								 | 
							
								            QueueSample( (IMediaSample*) ppack);
							 | 
						||
| 
								 | 
							
								            NotifyThread();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  End of Stream is queued to output device
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								void COutputQueue::EOS()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    CAutoLock lck(this);
							 | 
						||
| 
								 | 
							
								    if (!IsQueued()) {
							 | 
						||
| 
								 | 
							
								        if (m_bBatchExact) {
							 | 
						||
| 
								 | 
							
								            SendAnyway();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (m_hr == S_OK) {
							 | 
						||
| 
								 | 
							
								            DbgLog((LOG_TRACE, 2, TEXT("COutputQueue sending EndOfStream()")));
							 | 
						||
| 
								 | 
							
								            m_bFlushed = FALSE;
							 | 
						||
| 
								 | 
							
								            HRESULT hr = m_pPin->EndOfStream();
							 | 
						||
| 
								 | 
							
								            if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
								                DbgLog((LOG_ERROR, 2, TEXT("COutputQueue got code 0x%8.8X from EndOfStream()")));
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        if (m_hr == S_OK) {
							 | 
						||
| 
								 | 
							
								            m_bFlushed = FALSE;
							 | 
						||
| 
								 | 
							
								            QueueSample(EOS_PACKET);
							 | 
						||
| 
								 | 
							
								            NotifyThread();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  Flush all the samples in the queue
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								void COutputQueue::BeginFlush()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (IsQueued()) {
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            CAutoLock lck(this);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // block receives -- we assume this is done by the
							 | 
						||
| 
								 | 
							
								            // filter in which we are a component
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // discard all queued data
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            m_bFlushing = TRUE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            //  Make sure we discard all samples from now on
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (m_hr == S_OK) {
							 | 
						||
| 
								 | 
							
								                m_hr = S_FALSE;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // Optimize so we don't keep calling downstream all the time
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (m_bFlushed && m_bFlushingOpt) {
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // Make sure we really wait for the flush to complete
							 | 
						||
| 
								 | 
							
								            m_evFlushComplete.Reset();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            NotifyThread();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // pass this downstream
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        m_pPin->BeginFlush();
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        // pass downstream first to avoid deadlocks
							 | 
						||
| 
								 | 
							
								        m_pPin->BeginFlush();
							 | 
						||
| 
								 | 
							
								        CAutoLock lck(this);
							 | 
						||
| 
								 | 
							
								        // discard all queued data
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        m_bFlushing = TRUE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //  Make sure we discard all samples from now on
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (m_hr == S_OK) {
							 | 
						||
| 
								 | 
							
								            m_hr = S_FALSE;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// leave flush mode - pass this downstream
							 | 
						||
| 
								 | 
							
								void COutputQueue::EndFlush()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        CAutoLock lck(this);
							 | 
						||
| 
								 | 
							
								        ASSERT(m_bFlushing);
							 | 
						||
| 
								 | 
							
								        if (m_bFlushingOpt && m_bFlushed && IsQueued()) {
							 | 
						||
| 
								 | 
							
								            m_bFlushing = FALSE;
							 | 
						||
| 
								 | 
							
								            m_hr = S_OK;
							 | 
						||
| 
								 | 
							
								            return;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // sync with pushing thread -- done in BeginFlush
							 | 
						||
| 
								 | 
							
								    // ensure no more data to go downstream -- done in BeginFlush
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    // Because we are synching here there is no need to hold the critical
							 | 
						||
| 
								 | 
							
								    // section (in fact we'd deadlock if we did!)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (IsQueued()) {
							 | 
						||
| 
								 | 
							
								        m_evFlushComplete.Wait();
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        FreeSamples();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //  Be daring - the caller has guaranteed no samples will arrive
							 | 
						||
| 
								 | 
							
								    //  before EndFlush() returns
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    m_bFlushing = FALSE;
							 | 
						||
| 
								 | 
							
								    m_bFlushed  = TRUE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // call EndFlush on downstream pins
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    m_pPin->EndFlush();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    m_hr = S_OK;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//  COutputQueue::QueueSample
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  private method to Send a sample to the output queue
							 | 
						||
| 
								 | 
							
								//  The critical section MUST be held when this is called
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void COutputQueue::QueueSample(IMediaSample *pSample)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (NULL == m_List->AddTail(pSample)) {
							 | 
						||
| 
								 | 
							
								        if (!IsSpecialSample(pSample)) {
							 | 
						||
| 
								 | 
							
								            pSample->Release();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  COutputQueue::Receive()
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  Send a single sample by the multiple sample route
							 | 
						||
| 
								 | 
							
								//  (NOTE - this could be optimized if necessary)
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  On return the sample will have been Release()'d
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT COutputQueue::Receive(IMediaSample *pSample)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    LONG nProcessed;
							 | 
						||
| 
								 | 
							
								    return ReceiveMultiple(&pSample, 1, &nProcessed);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  COutputQueue::ReceiveMultiple()
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  Send a set of samples to the downstream pin
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//      ppSamples           - array of samples
							 | 
						||
| 
								 | 
							
								//      nSamples            - how many
							 | 
						||
| 
								 | 
							
								//      nSamplesProcessed   - How many were processed
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  On return all samples will have been Release()'d
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT COutputQueue::ReceiveMultiple (
							 | 
						||
| 
								 | 
							
								    __in_ecount(nSamples) IMediaSample **ppSamples,
							 | 
						||
| 
								 | 
							
								    long nSamples,
							 | 
						||
| 
								 | 
							
								    __out long *nSamplesProcessed)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (nSamples < 0) {
							 | 
						||
| 
								 | 
							
								        return E_INVALIDARG;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    CAutoLock lck(this);
							 | 
						||
| 
								 | 
							
								    //  Either call directly or queue up the samples
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!IsQueued()) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //  If we already had a bad return code then just return
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (S_OK != m_hr) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            //  If we've never received anything since the last Flush()
							 | 
						||
| 
								 | 
							
								            //  and the sticky return code is not S_OK we must be
							 | 
						||
| 
								 | 
							
								            //  flushing
							 | 
						||
| 
								 | 
							
								            //  ((!A || B) is equivalent to A implies B)
							 | 
						||
| 
								 | 
							
								            ASSERT(!m_bFlushed || m_bFlushing);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            //  We're supposed to Release() them anyway!
							 | 
						||
| 
								 | 
							
								            *nSamplesProcessed = 0;
							 | 
						||
| 
								 | 
							
								            for (int i = 0; i < nSamples; i++) {
							 | 
						||
| 
								 | 
							
								                DbgLog((LOG_TRACE, 3, TEXT("COutputQueue (direct) : Discarding %d samples code 0x%8.8X"),
							 | 
						||
| 
								 | 
							
								                        nSamples, m_hr));
							 | 
						||
| 
								 | 
							
								                ppSamples[i]->Release();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return m_hr;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        //
							 | 
						||
| 
								 | 
							
								        //  If we're flushing the sticky return code should be S_FALSE
							 | 
						||
| 
								 | 
							
								        //
							 | 
						||
| 
								 | 
							
								        ASSERT(!m_bFlushing);
							 | 
						||
| 
								 | 
							
								        m_bFlushed = FALSE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ASSERT(m_nBatched < m_lBatchSize);
							 | 
						||
| 
								 | 
							
								        ASSERT(m_nBatched == 0 || m_bBatchExact);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //  Loop processing the samples in batches
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        LONG iLost = 0;
							 | 
						||
| 
								 | 
							
								        long iDone = 0;
							 | 
						||
| 
								 | 
							
								        for (iDone = 0;
							 | 
						||
| 
								 | 
							
								             iDone < nSamples || (m_nBatched != 0 && m_bSendAnyway);
							 | 
						||
| 
								 | 
							
								            ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//pragma message (REMIND("Implement threshold scheme"))
							 | 
						||
| 
								 | 
							
								            ASSERT(m_nBatched < m_lBatchSize);
							 | 
						||
| 
								 | 
							
								            if (iDone < nSamples) {
							 | 
						||
| 
								 | 
							
								                m_ppSamples[m_nBatched++] = ppSamples[iDone++];
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (m_nBatched == m_lBatchSize ||
							 | 
						||
| 
								 | 
							
								                nSamples == 0 && (m_bSendAnyway || !m_bBatchExact)) {
							 | 
						||
| 
								 | 
							
								                LONG nDone;
							 | 
						||
| 
								 | 
							
								                DbgLog((LOG_TRACE, 4, TEXT("Batching %d samples"),
							 | 
						||
| 
								 | 
							
								                       m_nBatched));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (m_hr == S_OK) {
							 | 
						||
| 
								 | 
							
								                    m_hr = m_pInputPin->ReceiveMultiple(m_ppSamples,
							 | 
						||
| 
								 | 
							
								                                                        m_nBatched,
							 | 
						||
| 
								 | 
							
								                                                        &nDone);
							 | 
						||
| 
								 | 
							
								                } else {
							 | 
						||
| 
								 | 
							
								                    nDone = 0;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                iLost += m_nBatched - nDone;
							 | 
						||
| 
								 | 
							
								                for (LONG i = 0; i < m_nBatched; i++) {
							 | 
						||
| 
								 | 
							
								                    m_ppSamples[i]->Release();
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                m_nBatched = 0;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        *nSamplesProcessed = iDone - iLost;
							 | 
						||
| 
								 | 
							
								        if (*nSamplesProcessed < 0) {
							 | 
						||
| 
								 | 
							
								            *nSamplesProcessed = 0;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return m_hr;
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        /*  We're sending to our thread */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (m_hr != S_OK) {
							 | 
						||
| 
								 | 
							
								            *nSamplesProcessed = 0;
							 | 
						||
| 
								 | 
							
								            DbgLog((LOG_TRACE, 3, TEXT("COutputQueue (queued) : Discarding %d samples code 0x%8.8X"),
							 | 
						||
| 
								 | 
							
								                    nSamples, m_hr));
							 | 
						||
| 
								 | 
							
								            for (int i = 0; i < nSamples; i++) {
							 | 
						||
| 
								 | 
							
								                ppSamples[i]->Release();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return m_hr;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        m_bFlushed = FALSE;
							 | 
						||
| 
								 | 
							
								        for (long i = 0; i < nSamples; i++) {
							 | 
						||
| 
								 | 
							
								            QueueSample(ppSamples[i]);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        *nSamplesProcessed = nSamples;
							 | 
						||
| 
								 | 
							
								        if (!m_bBatchExact ||
							 | 
						||
| 
								 | 
							
								            m_nBatched + m_List->GetCount() >= m_lBatchSize) {
							 | 
						||
| 
								 | 
							
								            NotifyThread();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return S_OK;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//  Get ready for new data - cancels sticky m_hr
							 | 
						||
| 
								 | 
							
								void COutputQueue::Reset()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (!IsQueued()) {
							 | 
						||
| 
								 | 
							
								        m_hr = S_OK;
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            CAutoLock lck(this);
							 | 
						||
| 
								 | 
							
								            QueueSample(RESET_PACKET);
							 | 
						||
| 
								 | 
							
								            NotifyThread();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        m_evFlushComplete.Wait();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//  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;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//  Notify the thread if there is something to do
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  The critical section MUST be held when this is called
							 | 
						||
| 
								 | 
							
								void COutputQueue::NotifyThread()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    //  Optimize - no need to signal if it's not waiting
							 | 
						||
| 
								 | 
							
								    ASSERT(IsQueued());
							 | 
						||
| 
								 | 
							
								    if (m_lWaiting) {
							 | 
						||
| 
								 | 
							
								        ReleaseSemaphore(m_hSem, m_lWaiting, NULL);
							 | 
						||
| 
								 | 
							
								        m_lWaiting = 0;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//  See if there's any work to do
							 | 
						||
| 
								 | 
							
								//  Returns
							 | 
						||
| 
								 | 
							
								//      TRUE  if there is nothing on the queue and nothing in the batch
							 | 
						||
| 
								 | 
							
								//            and all data has been sent
							 | 
						||
| 
								 | 
							
								//      FALSE otherwise
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								BOOL COutputQueue::IsIdle()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    CAutoLock lck(this);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //  We're idle if
							 | 
						||
| 
								 | 
							
								    //      there is no thread (!IsQueued()) OR
							 | 
						||
| 
								 | 
							
								    //      the thread is waiting for more work  (m_lWaiting != 0)
							 | 
						||
| 
								 | 
							
								    //  AND
							 | 
						||
| 
								 | 
							
								    //      there's nothing in the current batch (m_nBatched == 0)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (IsQueued() && m_lWaiting == 0 || m_nBatched != 0) {
							 | 
						||
| 
								 | 
							
								        return FALSE;
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //  If we're idle it shouldn't be possible for there
							 | 
						||
| 
								 | 
							
								        //  to be anything on the work queue
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ASSERT(!IsQueued() || m_List->GetCount() == 0);
							 | 
						||
| 
								 | 
							
								        return TRUE;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void COutputQueue::SetPopEvent(HANDLE hEvent)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    m_hEventPop = hEvent;
							 | 
						||
| 
								 | 
							
								}
							 |