Beispiel #1
0
HRESULT Filter::Run(REFERENCE_TIME start)
{
    Lock lock;

    HRESULT hr = lock.Seize(this);

    if (FAILED(hr))
        return hr;

    //odbgstream os;
    //os << "mkvsplit::Filter::Run" << endl;

    switch (m_state)
    {
        case State_Stopped:
            OnStart();
            break;

        case State_Paused:
        case State_Running:
        default:
            break;
    }

    m_start = start;
    m_state = State_Running;

    return S_OK;
}
Beispiel #2
0
HRESULT Filter::Stop() {
  // Stop is a synchronous operation: when it completes,
  // the filter is stopped.
  Lock lock;

  HRESULT hr = lock.Seize(this);

  if (FAILED(hr))
    return hr;

  // odbgstream os;
  // os << "mkvsplit::Filter::Stop" << endl;

  switch (m_state) {
    case kStatePaused:
    case kStatePausedWaitingForKeyframe:
    case kStateRunning:
    case kStateRunningWaitingForKeyframe:
      m_state = kStateStopped;
      OnStop();  // decommit outpin's allocator
      break;

    case kStateStopped:
      break;

    default:
      assert(false);
      break;
  }

  return S_OK;
}
Beispiel #3
0
HRESULT Filter::Stop()
{
    //Stop is a synchronous operation: when it completes,
    //the filter is stopped.

    //odbgstream os;

    Lock lock;

    HRESULT hr = lock.Seize(this);

    if (FAILED(hr))
        return hr;

    //odbgstream os;
    //os << "mkvsplit::Filter::Stop" << endl;

    switch (m_state)
    {
        case State_Paused:
        case State_Running:
            m_state = State_Stopped;
            OnStop();    //decommit outpin's allocator
            break;

        case State_Stopped:
        default:
            break;
    }

    return S_OK;
}
Beispiel #4
0
HRESULT Filter::Pause()
{
    //Unlike Stop(), Pause() can be asynchronous (that's why you have
    //GetState()).

    Lock lock;

    HRESULT hr = lock.Seize(this);

    if (FAILED(hr))
        return hr;

    //odbgstream os;
    //os << "mkvsplit::Filter::Pause" << endl;

    switch (m_state)
    {
        case State_Stopped:
            OnStart();  //commit outpin's allocator
            break;

        case State_Running:
        case State_Paused:
        default:
            break;
    }

    m_state = State_Paused;
    return S_OK;
}
Beispiel #5
0
HRESULT Filter::EnumPins(IEnumPins** pp)
{
    Lock lock;

    HRESULT hr = lock.Seize(this);

    if (FAILED(hr))
        return hr;

    const ULONG outpins_count = static_cast<ULONG>(m_outpins.size());
    const ULONG n = 1 + outpins_count;

    //odbgstream os;
    //os << "WebmSplit::filter::enumpins: n=" << n << endl;

    const size_t cb = n * sizeof(IPin*);
    IPin** const pins = (IPin**)_alloca(cb);

    IPin** pin = pins;

    *pin++ = &m_inpin;

    typedef outpins_t::iterator iter_t;

    iter_t i = m_outpins.begin();
    const iter_t j = m_outpins.end();

    while (i != j)
        *pin++ = *i++;

    return CEnumPins::CreateInstance(pins, n, pp);
}
HRESULT Filter::Run(REFERENCE_TIME start)
{
    Lock lock;

    HRESULT hr = lock.Seize(this);

    if (FAILED(hr))
        return hr;

#ifdef _DEBUG
    odbgstream os;
    os << "webmvorbisencoder::Filter::Run" << endl;
#endif

    switch (m_state)
    {
        case State_Stopped:
            OnStart();
            break;

        case State_Paused:
        case State_Running:
        default:
            break;
    }

    m_start = start;
    m_state = State_Running;

    return S_OK;
}
Beispiel #7
0
HRESULT Filter::Pause()
{
    //Unlike Stop(), Pause() can be asynchronous (that's why you have
    //GetState()).  We could use that here to build the samples index.

    Lock lock;

    HRESULT hr = lock.Seize(this);

    if (FAILED(hr))
        return hr;

    //odbgstream os;
    //os << "WebmSplit::Filter::Pause" << endl;

    switch (m_state)
    {
        case State_Stopped:
            OnStart();
            break;

        case State_Running:
        case State_Paused:
        default:
            break;
    }

    m_state = State_Paused;
    return S_OK;
}
Beispiel #8
0
HRESULT Filter::JoinFilterGraph(
    IFilterGraph *pGraph,
    LPCWSTR name)
{
    Lock lock;

    HRESULT hr = lock.Seize(this);

    if (FAILED(hr))
        return hr;

    //NOTE:
    //No, do not adjust reference counts here!
    //Read the docs for the reasons why.
    //ENDNOTE.

    m_info.pGraph = pGraph;

    if (name == 0)
        m_info.achName[0] = L'\0';
    else
    {
        enum { size = sizeof(m_info.achName)/sizeof(WCHAR) };
        const errno_t e = wcscpy_s(m_info.achName, size, name);
        e;
        assert(e == 0);  //TODO
    }

    return S_OK;
}
Beispiel #9
0
HRESULT Filter::ApplyPostProcessing() {
  Lock lock;

  HRESULT hr = lock.Seize(this);

  if (FAILED(hr))
    return hr;

  if (m_state != State_Paused)
    return VFW_E_NOT_PAUSED;

  return m_inpin.OnApplyPostProcessing();
}
Beispiel #10
0
HRESULT Filter::GetState(DWORD, FILTER_STATE* p) {
  if (p == 0)
    return E_POINTER;

  Lock lock;

  const HRESULT hr = lock.Seize(this);

  if (FAILED(hr))
    return hr;

  *p = GetStateLocked();
  return S_OK;
}
Beispiel #11
0
HRESULT Filter::SetFlags(int Flags) {
  Lock lock;

  HRESULT hr = lock.Seize(this);

  if (FAILED(hr))
    return hr;

  if (Flags & ~0x07)
    return E_INVALIDARG;

  m_cfg.flags = Flags;

  return S_OK;
}
Beispiel #12
0
HRESULT Filter::EnumPins(IEnumPins** pp) {
  Lock lock;

  HRESULT hr = lock.Seize(this);

  if (FAILED(hr))
    return hr;

  IPin* pins[2];

  pins[0] = &m_inpin;
  pins[1] = &m_outpin;

  return CEnumPins::CreateInstance(pins, 2, pp);
}
Beispiel #13
0
HRESULT Filter::GetFlags(int* pFlags) {
  if (pFlags == 0)
    return E_POINTER;

  Lock lock;

  HRESULT hr = lock.Seize(this);

  if (FAILED(hr))
    return hr;

  *pFlags = m_cfg.flags;

  return S_OK;
}
Beispiel #14
0
HRESULT Filter::GetNoiseLevel(int* pLevel) {
  if (pLevel == 0)
    return E_POINTER;

  Lock lock;

  HRESULT hr = lock.Seize(this);

  if (FAILED(hr))
    return hr;

  *pLevel = m_cfg.noise;

  return S_OK;
}
HRESULT Filter::Stop()
{
    //Stop is a synchronous operation: when it completes,
    //the filter is stopped.

    //odbgstream os;

    Lock lock;

    HRESULT hr = lock.Seize(this);

    if (FAILED(hr))
        return hr;

#ifdef _DEBUG
    odbgstream os;
    os << "webmvorbisencoder::Filter::Stop(begin)" << endl;
#endif

    switch (m_state)
    {
        case State_Paused:
        case State_Running:
            m_state = State_Stopped;

            //Stop inpin first, to signal thread to terminate.
            m_inpin.Stop();

            hr = lock.Release();
            assert(SUCCEEDED(hr));

            //Now stop outpin, to terminate its thread too.
            m_outpin.Stop();

            break;

        case State_Stopped:
        default:
            break;
    }

#ifdef _DEBUG
    os << "webmvorbisencoder::Filter::Stop(end)" << endl;
#endif

    return S_OK;
}
Beispiel #16
0
HRESULT Filter::SetNoiseLevel(int level) {
  Lock lock;

  HRESULT hr = lock.Seize(this);

  if (FAILED(hr))
    return hr;

  if (level < 0)
    return E_INVALIDARG;

  if (level > 16)
    return E_INVALIDARG;

  m_cfg.noise = level;

  return S_OK;
}
Beispiel #17
0
HRESULT Filter::SetSyncSource(IReferenceClock* clock) {
  Lock lock;

  HRESULT hr = lock.Seize(this);

  if (FAILED(hr))
    return hr;

  if (m_clock)
    m_clock->Release();

  m_clock = clock;

  if (m_clock)
    m_clock->AddRef();

  return S_OK;
}
Beispiel #18
0
HRESULT Filter::GetSyncSource(IReferenceClock** pclock) {
  if (pclock == 0)
    return E_POINTER;

  Lock lock;

  HRESULT hr = lock.Seize(this);

  if (FAILED(hr))
    return hr;

  IReferenceClock*& clock = *pclock;

  clock = m_clock;

  if (clock)
    clock->AddRef();

  return S_OK;
}
Beispiel #19
0
HRESULT Filter::Pause()
{
    //Unlike Stop(), Pause() can be asynchronous (that's why you have
    //GetState()).

    Lock lock;

    HRESULT hr = lock.Seize(this);

    if (FAILED(hr))
        return hr;

    //odbgstream os;
    //os << "mkvsplit::Filter::Pause" << endl;

    switch (m_state)
    {
        case kStateStopped:
            OnStart();  //commit outpin's allocator
            m_state = kStatePausedWaitingForKeyframe;
            break;

        case kStateRunning:
            m_state = kStatePaused;
            break;

        case kStateRunningWaitingForKeyframe:
            m_state = kStatePausedWaitingForKeyframe;
            break;

        case kStatePausedWaitingForKeyframe:
        case kStatePaused:
            break;

        default:
            assert(false);
            break;
    }

    return S_OK;
}
Beispiel #20
0
HRESULT Filter::Run(REFERENCE_TIME start)
{
    Lock lock;

    HRESULT hr = lock.Seize(this);

    if (FAILED(hr))
        return hr;

    //odbgstream os;
    //os << "mkvsplit::Filter::Run" << endl;

    switch (m_state)
    {
        case kStateStopped:
            OnStart();
            m_state = kStateRunningWaitingForKeyframe;
            break;

        case kStatePausedWaitingForKeyframe:
            m_state = kStateRunningWaitingForKeyframe;
            break;

        case kStatePaused:
            m_state = kStateRunning;
            break;

        case kStateRunningWaitingForKeyframe:
        case kStateRunning:
            break;

        default:
            assert(false);
            break;
    }

    m_start = start;
    return S_OK;
}
Beispiel #21
0
HRESULT Filter::QueryFilterInfo(FILTER_INFO* p)
{
    if (p == 0)
        return E_POINTER;

    Lock lock;

    HRESULT hr = lock.Seize(this);

    if (FAILED(hr))
        return hr;

    enum { size = sizeof(p->achName)/sizeof(WCHAR) };
    const errno_t e = wcscpy_s(p->achName, size, m_info.achName);
    e;
    assert(e == 0);

    p->pGraph = m_info.pGraph;

    if (p->pGraph)
        p->pGraph->AddRef();

    return S_OK;
}
Beispiel #22
0
unsigned Filter::Main()
{
    assert(m_pSegment);

    for (;;)
    {
        Sleep(0);

#if 0
        LONGLONG cluster_pos, new_pos;

        const long status = m_pSegment->ParseCluster(cluster_pos, new_pos);

        if (status < 0)  //TODO: how to handle outpin streaming threads?
            return 1;

        Lock lock;

        const HRESULT hr = lock.Seize(this);
        assert(SUCCEEDED(hr));  //TODO

        if (FAILED(hr))
            return 1;

        const bool bDone = m_pSegment->AddCluster(cluster_pos, new_pos);

        //odbgstream os;
        //os << "webmsplit::filter::main: ParseCluster; cluster_pos="
        //   << cluster_pos
        //   << " new_pos="
        //   << new_pos
        //   << " count="
        //   << m_pSegment->GetCount()
        //   << " unparsed="
        //   << m_pSegment->Unparsed()
        //   << endl;
#else
        Lock lock;

        HRESULT hr = lock.Seize(this);

        if (FAILED(hr))
            return 1;

        for (;;)
        {
            LONGLONG pos;
            LONG size;

            const long status = m_pSegment->LoadCluster(pos, size);

            if (status >= 0)
                break;

            if (status != mkvparser::E_BUFFER_NOT_FULL)
                return 1;

            hr = m_inpin.m_reader.Wait(*this, pos, size, INFINITE);

            if (FAILED(hr))  //wait was cancelled
                return 1;
        }

        const bool bDone = m_pSegment->DoneParsing();
#endif

        OnNewCluster();

        if (bDone)
            return 0;

        if (m_state == State_Stopped)
            return 0;
    }
}
Beispiel #23
0
HRESULT Filter::GetState(
    DWORD timeout,
    FILTER_STATE* p)
{
    if (p == 0)
        return E_POINTER;

    //What the GetState.timeout parameter refers to is not to locking
    //the filter, but rather to waiting to determine the current state.
    //A request to Stop is always synchronous (hence no timeout parameter),
    //but a request to Pause can be asynchronous, so the caller can say
    //how long he's willing to wait for the transition (to paused) to
    //complete.

    //TODO: implement a waiting scheme here.  We'll probably have to
    //use SignalObjectAndWait atomically release the mutex and then
    //wait for the condition variable to change.
    //if (hr == VFW_E_TIMEOUT)
    //    return VFW_S_STATE_INTERMEDIATE;

    Lock lock;

    HRESULT hrLock = lock.Seize(this);

    //The lock is only used for synchronization.  If Seize fails,
    //it means there's a serious problem with the filter.

    if (FAILED(hrLock))
        return E_FAIL;

    FILTER_STATE& state = *p;

    if (m_cStarvation < 0)  //not starving
    {
        state = m_state;
        return S_OK;
    }

    assert(m_pSegment);

    long count = m_pSegment->GetCount();

    if (count > m_cStarvation)
    {
        m_cStarvation = -1;

        state = m_state;  //TODO: should be State_Paused?
        return S_OK;
    }

    for (;;)
    {
        lock.Release();

        DWORD index;

        //TODO: this timeout isn't quite correct.  The parameter refers
        //to the total wait time.  As used here in the call to WaitForHandles,
        //it refers to the wait time for this pass through the loop.

        const HRESULT hrWait = CoWaitForMultipleHandles(
                                0,  //wait flags
                                timeout,
                                1,
                                &m_hNewCluster,
                                &index);

        if (SUCCEEDED(hrWait))
            assert(index == 0);
        else if (hrWait != RPC_S_CALLPENDING) //error, despite "S" in name
            return hrWait;

        hrLock = lock.Seize(this);

        if (FAILED(hrLock))
            return E_FAIL;

        count = m_pSegment->GetCount();

        if (count > m_cStarvation)
        {
            m_cStarvation = -1;

            state = m_state;  //TODO: should be State_Paused?
            return S_OK;
        }

        if (FAILED(hrWait))  //there was a timeout before receiving signal
           return VFW_S_STATE_INTERMEDIATE;
    }
}
Beispiel #24
0
HRESULT Filter::Stop()
{
    //Stop is a synchronous operation: when it completes,
    //the filter is stopped.

    Lock lock;

    HRESULT hr = lock.Seize(this);

    if (FAILED(hr))
        return hr;

    switch (m_state)
    {
        case State_Paused:
        case State_Running:

            //Stop is synchronous.  When stop completes, all threads
            //should be stopped.  What does "stopped" mean"  In our
            //case it probably means "terminated".
            //It's a bit tricky here because we hold the filter
            //lock.  If threads need to acquire filter lock
            //then we'll have to release it.  Only the FGM can call
            //Stop, etc, so there's no problem to release lock
            //while Stop is executing, to allow threads to acquire
            //filter lock temporarily.
            //The streaming thread will receiving an indication
            //automatically (assuming it's connected), either via
            //GetBuffer or Receive, so there's nothing this filter
            //needs to do to tell the streaming thread to stop.
            //One implementation strategy is to have build a
            //vector of thread handles, and then wait for a signal
            //on one of them.  When the handle is signalled
            //(meaning that the thread has terminated), then
            //we remove that handle from the vector, close the
            //handle, and the wait again.  Repeat until the
            //all threads have been terminated.
            //We also need to clean up any unused samples,
            //and decommit the allocator.  (In fact, we could
            //decommit the allocator immediately, and then wait
            //for the threads to terminated.)

            m_state = State_Stopped;

            hr = m_inpin.m_reader.BeginFlush();
            assert(SUCCEEDED(hr));

            lock.Release();

            OnStop();

            hr = lock.Seize(this);
            assert(SUCCEEDED(hr));  //TODO

            hr = m_inpin.m_reader.EndFlush();
            assert(SUCCEEDED(hr));

            break;

        case State_Stopped:
        default:
            break;
    }

    return S_OK;
}