Ejemplo n.º 1
0
// Completes a frame-step operation.
HRESULT EVRCustomPresenter::CompleteFrameStep(IMFSample *pSample)
{
  HRESULT hr = S_OK;
  MFTIME hnsSampleTime = 0;
  MFTIME hnsSystemTime = 0;

  // Update our state.
  m_FrameStep.state = FRAMESTEP_COMPLETE;
  m_FrameStep.pSampleNoRef = NULL;

  // Notify the EVR that the frame-step is complete.
  NotifyEvent(EC_STEP_COMPLETE, FALSE, 0); // FALSE = completed (not cancelled)

  // If we are scrubbing (rate == 0), also send the "scrub time" event.
  if (IsScrubbing())
  {
    // Get the time stamp from the sample.
    hr = pSample->GetSampleTime(&hnsSampleTime);
    if (FAILED(hr))
    {
      // No time stamp. Use the current presentation time.
      if (m_pClock)
      {
        hr = m_pClock->GetCorrelatedTime(0, &hnsSampleTime, &hnsSystemTime);
      }
      hr = S_OK; // Not an error condition.
    }

    NotifyEvent(EC_SCRUB_TIME, LODWORD(hnsSampleTime), HIDWORD(hnsSampleTime));
  }

  return hr;
}
Ejemplo n.º 2
0
void Scrubber::OnActivateOrDeactivateApp(wxActivateEvent &event)
{
   if (event.GetActive())
      mScrubHasFocus = IsScrubbing();
   else
      mScrubHasFocus = false;

   event.Skip();
}
Ejemplo n.º 3
0
bool Scrubber::ShouldDrawScrubSpeed()
{
   return IsScrubbing() &&
      mScrubHasFocus && (
      // Draw for (non-scroll) scrub, sometimes, but never for seek
      (!PollIsSeeking() && mScrubSpeedDisplayCountdown > 0)
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
      // Draw always for scroll-scrub and for scroll-seek
       || mSmoothScrollingScrub
#endif
      );
}
Ejemplo n.º 4
0
void Scrubber::StopScrubbing()
{
   mScrubStartPosition = -1;
   mSmoothScrollingScrub = false;
   const auto ctb = mProject->GetControlToolBar();

   if (IsScrubbing())
   {
      if (gAudioIO->IsBusy()) {
         ctb->StopPlaying();
      }
   }
   else {
      // Didn't really play, but did change button apperance
      ctb->SetPlay(false, ControlToolBar::PlayAppearance::Straight);
   }
}
Ejemplo n.º 5
0
// Process a video sample for frame-stepping.
HRESULT EVRCustomPresenter::DeliverFrameStepSample(IMFSample *pSample)
{
  HRESULT hr = S_OK;
  IUnknown *pUnk = NULL;

  // For rate 0, discard any sample that ends earlier than the clock time.
  if (IsScrubbing() && m_pClock && IsSampleTimePassed(m_pClock, pSample))
  {
    // Discard this sample.
  }
  else if (m_FrameStep.state >= FRAMESTEP_SCHEDULED)
  {
    // A frame was already submitted. Put this sample on the frame-step queue, 
    // in case we are asked to step to the next frame. If frame-stepping is
    // cancelled, this sample will be processed normally.
    hr = m_FrameStep.samples.InsertBack(pSample);
    CHECK_HR(hr, "EVRCustomPresenter::DeliverFrameStepSample VideoSampleList::InsertBack() failed");
  }
  else
  {
    // We're ready to frame-step.

    // Decrement the number of steps.
    if (m_FrameStep.steps > 0)
    {
      m_FrameStep.steps--;
    }

    if (m_FrameStep.steps > 0)
    {
      // This is not the last step. Discard this sample.
    }
    else if (m_FrameStep.state == FRAMESTEP_WAITING_START)
    {
      // This is the right frame, but the clock hasn't started yet. Put the
      // sample on the frame-step queue. When the clock starts, the sample
      // will be processed.
      hr = m_FrameStep.samples.InsertBack(pSample);
      CHECK_HR(hr, "EVRCustomPresenter::DeliverFrameStepSample VideoSampleList::InsertBack() failed");
    }
    else
    {
      // This is the right frame *and* the clock has started. Deliver this sample.
      hr = DeliverSample(pSample, FALSE);
      CHECK_HR(hr, "EVRCustomPresenter::DeliverFrameStepSample EVRCustomPresenter::DeliverSample() failed");

      // QI for IUnknown so that we can identify the sample later.
      // (Per COM rules, an object alwayss return the same pointer when QI'ed for IUnknown.)
      hr = pSample->QueryInterface(__uuidof(IUnknown), (void**)&pUnk);
      if (FAILED(hr))
      {
        SAFE_RELEASE(pUnk);
        CHECK_HR(hr, "EVRCustomPresenter::DeliverFrameStempSample IMFSample::QueryInterface() failed");
      }
      // Save this value.
      m_FrameStep.pSampleNoRef = (DWORD_PTR)pUnk; // No add-ref. 

      // NOTE: We do not AddRef the IUnknown pointer, because that would prevent the 
      // sample from invoking the OnSampleFree callback after the sample is presented. 
      // We use this IUnknown pointer purely to identify the sample later; we never
      // attempt to dereference the pointer.

      // Update our state.
      m_FrameStep.state = FRAMESTEP_SCHEDULED;
    }
  }

  SAFE_RELEASE(pUnk);
  return hr;
}
Ejemplo n.º 6
0
bool Scrubber::MaybeStartScrubbing(const wxMouseEvent &event)
{
   if (mScrubStartPosition < 0)
      return false;
   if (IsScrubbing())
      return false;
   else {
      const bool busy = gAudioIO->IsBusy();
      if (busy && gAudioIO->GetNumCaptureChannels() > 0) {
         // Do not stop recording, and don't try to start scrubbing after
         // recording stops
         mScrubStartPosition = -1;
         return false;
      }

      wxCoord position = event.m_x;
      if (abs(mScrubStartPosition - position) >= SCRUBBING_PIXEL_TOLERANCE) {
         const ViewInfo &viewInfo = mProject->GetViewInfo();
         TrackPanel *const trackPanel = mProject->GetTrackPanel();
         ControlToolBar * const ctb = mProject->GetControlToolBar();
         double maxTime = mProject->GetTracks()->GetEndTime();
         const int leftOffset = trackPanel->GetLeftOffset();
         double time0 = std::min(maxTime,
            viewInfo.PositionToTime(mScrubStartPosition, leftOffset)
         );
         double time1 = std::min(maxTime,
            viewInfo.PositionToTime(position, leftOffset)
         );
         if (time1 != time0)
         {
            if (busy)
               ctb->StopPlaying();

            AudioIOStartStreamOptions options(mProject->GetDefaultPlayOptions());
            options.timeTrack = NULL;
            options.scrubDelay = (kTimerInterval / 1000.0);
            options.scrubStartClockTimeMillis = mScrubStartClockTimeMillis;
            options.minScrubStutter = 0.2;
#if 0
            if (!mAlwaysSeeking) {
               // Take the starting speed limit from the transcription toolbar,
               // but it may be varied during the scrub.
               mMaxScrubSpeed = options.maxScrubSpeed =
               p->GetTranscriptionToolBar()->GetPlaySpeed();
            }
#else
            // That idea seems unpopular... just make it one
            mMaxScrubSpeed = options.maxScrubSpeed = 1.0;
#endif
            options.maxScrubTime = mProject->GetTracks()->GetEndTime();
            ControlToolBar::PlayAppearance appearance =
               ControlToolBar::PlayAppearance::Scrub;
            const bool cutPreview = false;
            const bool backwards = time1 < time0;
#ifdef EXPERIMENTAL_SCRUBBING_SCROLL_WHEEL
            static const double maxScrubSpeedBase =
               pow(2.0, 1.0 / ScrubSpeedStepsPerOctave);
            mLogMaxScrubSpeed = floor(0.5 +
               log(mMaxScrubSpeed) / log(maxScrubSpeedBase)
            );
#endif
            mScrubSpeedDisplayCountdown = 0;
            mScrubToken =
               ctb->PlayPlayRegion(SelectedRegion(time0, time1), options,
                                   PlayMode::normalPlay, appearance, backwards);
         }
      }
      else
         // Wait to test again
         mScrubStartClockTimeMillis = ::wxGetLocalTimeMillis();

      if (IsScrubbing())
         mScrubHasFocus = true;

      // Return true whether we started scrub, or are still waiting to decide.
      return true;
   }
}