예제 #1
0
파일: outputq.cpp 프로젝트: 1pi/LAVFilters
//
//  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;
}
예제 #2
0
HRESULT TffOutputQueue::ReceiveMultiple(
    IMediaSample **ppSamples,
    long nSamples,
    long *nSamplesProcessed)
{
    CAutoLock lck(this);
    //  Either call directly or queue up the samples

    /*  We're sending to our thread */

    if (m_hr != S_OK) {
        *nSamplesProcessed = 0;
        DPRINTF(_l("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) {
        //DPRINTF(_l("COutputQueue queued a sample"));
        NotifyThread();
    }
    return S_OK;
}
예제 #3
0
bool RuntimeQueue::Block(const ThreadId& targetThread, u64 taskId, rqe& ec)
{
    if(context->shutdownFlag.load())
    {
        ec = RQE::ShuttingDown;
        return false;
    }

    DProfContext __(RQ_API "Blocking task");

    auto          thread_id = targetThread.hash();
    RuntimeQueue* pQueue    = nullptr;

    {
        Lock _(context->globalMod);

        auto q_it = context->queues.find(thread_id);

        if(q_it == context->queues.end())
        {
            ec = RQE::InvalidQueue;
            return false;
        }

        pQueue = &(*q_it).second;
    }

    auto& queue = *pQueue;

    RuntimeTask const* task = nullptr;
    szptr              idx  = 0;

    if(!(task = GetTask(queue.mTasks, taskId, ec, &idx)))
    {
        ec = RQE::InvalidTaskId;
        return false;
    }

    {
        /* We do this check in case we are executing in the queue */
        /* Otherwise we deadlock */
        RecLock ___(queue.mTasksLock);

        if(!queue.mTasks[idx].alive)
        {
            ec = RQE::TaskAlreadyBlocked;
            return false;
        }

        auto currentBase      = RuntimeTask::clock::now();
        auto previousNextTime = queue.timeTillNext(currentBase);

        queue.mTasks[idx].alive = false;

        NotifyThread(context, thread_id, previousNextTime, currentBase);
    }

    return true;
}
예제 #4
0
//  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();
    }
}
예제 #5
0
파일: outputq.cpp 프로젝트: 1pi/LAVFilters
//
//  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;
        }
    }

}
예제 #6
0
bool RuntimeQueue::CancelTask(const ThreadId& targetThread, u64 taskId, rqe& ec)
{
    if(context->shutdownFlag.load())
    {
        ec = RQE::ShuttingDown;
        return false;
    }

    auto          thread_id = targetThread.hash();
    RuntimeQueue* pQueue    = nullptr;

    {
        Lock _(context->globalMod);

        auto q_it = context->queues.find(thread_id);

        if(q_it == context->queues.end())
        {
            ec = RQE::InvalidQueue;
            return false;
        }

        pQueue = &(*q_it).second;
    }

    auto& queue = *pQueue;

    {
        RecLock _(queue.mTasksLock);

        RuntimeTask const* task = nullptr;
        szptr              idx  = 0;

        if(!(task = GetTask(queue.mTasks, taskId, ec, &idx)))
        {
            ec = RQE::InvalidTaskId;
            return false;
        }

        queue.mTasks[idx].alive      = false;
        queue.mTasks[idx].to_dispose = true;

        auto currentBase      = RuntimeTask::clock::now();
        auto previousNextTime = queue.timeTillNext(currentBase);

        NotifyThread(context, thread_id, previousNextTime, currentBase);
    }

    return true;
}
예제 #7
0
파일: outputq.cpp 프로젝트: 1pi/LAVFilters
//  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();
    }
}
예제 #8
0
파일: outputq.cpp 프로젝트: 1pi/LAVFilters
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();
        }
    }
}
예제 #9
0
파일: outputq.cpp 프로젝트: 1pi/LAVFilters
//
//  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();
        }
    }
}
예제 #10
0
u64 RuntimeQueue::Queue(
    RuntimeQueue* queue, RuntimeTask&& task, RuntimeQueue::rqe& ec)
{
    if(context->shutdownFlag.load())
    {
        ec = RQE::ShuttingDown;
        return 0;
    }

    DProfContext _(RQ_API "Adding task to Queue");
    auto&        ref = *queue;

    RecLock __(queue->mTasksLock);

    auto currentBase      = RuntimeTask::clock::now();
    auto previousNextTime = ref.timeTillNext(currentBase);

    auto id = ref.enqueue(std::move(task));

    NotifyThread(
        context, queue->mThreadId.hash(), previousNextTime, currentBase);

    return id;
}
예제 #11
0
bool LqThreadBase::StartThreadAsync() {
    bool Res = true;
    StartThreadLocker.LockWrite();
    if(IsThreadRunning()) {
        StartThreadLocker.UnlockWrite();
        lq_errno_set(EALREADY);
        return false;
    }
    IsShouldEnd = false;
    IsStarted = false;
#ifdef LQPLATFORM_WINDOWS
    unsigned threadID;
    uintptr_t Handler = _beginthreadex(NULL, 0, BeginThreadHelper, this, 0, &threadID);
    CurThreadId = threadID;
    ThreadHandler = Handler;
    if(Handler == -1L) {
        switch(errno) {
            case EAGAIN: lq_errno_set(EAGAIN); break;
            case EINVAL: lq_errno_set(EINVAL); break;
            case EACCES: lq_errno_set(EACCES); break;
        }
#else
    pthread_t threadID = 0;
    int Err = pthread_create(&threadID, NULL, BeginThreadHelper, this);
    CurThreadId = threadID;
    if(Err != 0) {
#endif
        Res = false;
        CurThreadId = -((intptr_t)1);
        ThreadHandler = 0;
    }
    StartThreadLocker.UnlockWrite();
    return Res;
}

bool LqThreadBase::StartThreadSync() {
    bool Res = true;
    StartThreadLocker.LockWrite();
    if(IsThreadRunning()) {
        StartThreadLocker.UnlockWrite();
        lq_errno_set(EALREADY);
        return false;
    }
    IsShouldEnd = false;
    IsStarted = false;
#ifdef LQPLATFORM_WINDOWS
    unsigned threadID;
    uintptr_t Handler = _beginthreadex(NULL, 0, BeginThreadHelper, this, 0, &threadID);
    CurThreadId = threadID;
    ThreadHandler = Handler;
    if(Handler == -1L) {
        switch(errno) {
            case EAGAIN: lq_errno_set(EAGAIN); break;
            case EINVAL: lq_errno_set(EINVAL); break;
            case EACCES: lq_errno_set(EACCES); break;
        }
#else
    pthread_t threadID = 0;
    int Err = pthread_create(&threadID, NULL, BeginThreadHelper, this);
    CurThreadId = threadID;
    if(Err != 0){
#endif
        Res = false;
        CurThreadId = -((intptr_t)1);
        ThreadHandler = 0;
    } else {
        while(!IsStarted)
            LqThreadYield();
    }
    StartThreadLocker.UnlockWrite();
    return Res;
}

bool LqThreadBase::IsThisThread() const {
#ifdef LQPLATFORM_WINDOWS
    return GetCurrentThreadId() == CurThreadId;
#else
    return pthread_equal(pthread_self(), CurThreadId);
#endif
}

bool LqThreadBase::ExitThreadAsync() {
    bool r = true;
    StartThreadLocker.LockWrite();
    if(IsThreadRunning()) {
        IsShouldEnd = true;
        if(!IsThisThread())
            NotifyThread();
    } else {
        lq_errno_set(ENOENT);
        r = false;
    }
    StartThreadLocker.UnlockWrite();
    return r;
}
예제 #12
0
HRESULT COutputQueue::ReceiveMultiple (
    IMediaSample **ppSamples,
    long nSamples,
    long *nSamplesProcessed)
{
    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;
        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;
    }
}