summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--media/base/synchronizer.cc93
-rw-r--r--media/base/synchronizer.h59
-rw-r--r--media/build/media.vcproj8
-rw-r--r--media/media_lib.scons2
4 files changed, 162 insertions, 0 deletions
diff --git a/media/base/synchronizer.cc b/media/base/synchronizer.cc
new file mode 100644
index 0000000..f233c7b
--- /dev/null
+++ b/media/base/synchronizer.cc
@@ -0,0 +1,93 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "media/base/synchronizer.h"
+
+namespace media {
+
+const int64 Synchronizer::kMinFrameDelayUs = 0;
+const int64 Synchronizer::kMaxFrameDelayUs = 250000;
+
+Synchronizer::Synchronizer() {
+}
+
+Synchronizer::~Synchronizer() {
+}
+
+void Synchronizer::StartRendering() {
+ rendering_start_ = base::TimeTicks::Now();
+}
+
+void Synchronizer::StopRendering() {
+ rendering_stop_ = base::TimeTicks::Now();
+}
+
+void Synchronizer::CalculateDelay(base::TimeDelta time,
+ const StreamSample* now,
+ const StreamSample* next,
+ base::TimeDelta* delay_out,
+ bool* should_skip_out) {
+ // How long rendering took.
+ base::TimeDelta render_delta = rendering_stop_ - rendering_start_;
+
+ // The duration to display the sample |now|.
+ base::TimeDelta duration =
+ base::TimeDelta::FromMicroseconds(now->GetDuration());
+
+ // The presentation timestamp (pts) of the sample |now|.
+ base::TimeDelta now_pts =
+ base::TimeDelta::FromMicroseconds(now->GetTimestamp());
+
+ // The presentation timestamp (pts) of the next sample.
+ base::TimeDelta next_pts;
+
+ // If we were provided the next sample in the stream |next|, use it to
+ // calculate the actual sample duration as opposed to the expected duration
+ // provided by the current sample |now|.
+ //
+ // We also use |next| to get the exact next timestamp as opposed to assuming
+ // it will be |now| + |now|'s duration, which may not always be true.
+ if (next) {
+ next_pts = base::TimeDelta::FromMicroseconds(next->GetTimestamp());
+ duration = next_pts - now_pts;
+
+ // Timestamps appear out of order, so skip this frame.
+ if (duration.InMicroseconds() < 0) {
+ *delay_out = base::TimeDelta();
+ *should_skip_out = true;
+ return;
+ }
+ } else {
+ // Assume next presentation timestamp is |now| + |now|'s duration.
+ next_pts = now_pts + duration;
+ }
+
+ base::TimeDelta sleep;
+ if (time == last_time_) {
+ // The audio time has not changed. To avoid sudden bursts of video after
+ // we get audio timing information, we try and guess the current time
+ // using the duration of the frame.
+ sleep = duration - render_delta;
+ if (sleep.InMicroseconds() < kMinFrameDelayUs) {
+ sleep = base::TimeDelta::FromMicroseconds(kMinFrameDelayUs);
+ }
+ } else {
+ // The audio time has changed. The amount of time to delay is equal to
+ // the time until the next sample from now minus how long it takes to
+ // render, clamped to within the min/max frame delay constants.
+ sleep = next_pts - time - render_delta;
+ if (sleep.InMicroseconds() < kMinFrameDelayUs) {
+ sleep = base::TimeDelta::FromMicroseconds(kMinFrameDelayUs);
+ } else if (sleep.InMicroseconds() > kMaxFrameDelayUs) {
+ sleep = base::TimeDelta::FromMicroseconds(kMaxFrameDelayUs);
+ }
+ }
+ last_time_ = time;
+
+ *delay_out = sleep;
+ *should_skip_out = false;
+}
+
+} // namespace media
diff --git a/media/base/synchronizer.h b/media/base/synchronizer.h
new file mode 100644
index 0000000..122c32f
--- /dev/null
+++ b/media/base/synchronizer.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Utility class for video renderers to help synchronize against a reference
+// clock while also taking rendering duration into account.
+//
+// Video renderers should maintain an instance of this object for the entire
+// lifetime since Synchronizer maintains internal state to improve playback.
+//
+// VideoRenderer usage is as follows:
+// Receive a new frame from the decoder
+// Call StartRendering
+// Perform colour space conversion and render the frame
+// Call StopRendering
+// Call CalculateDelay passing in the rendered frame and optional next frame
+// Issue delayed task or sleep on thread for returned amount of time
+
+#ifndef MEDIA_BASE_SYNCHRONIZER_H_
+#define MEDIA_BASE_SYNCHRONIZER_H_
+
+#include "base/basictypes.h"
+#include "base/time.h"
+#include "media/base/buffers.h"
+
+namespace media {
+
+class Synchronizer {
+ public:
+ Synchronizer();
+ ~Synchronizer();
+
+ // Starts the rendering timer.
+ void StartRendering();
+
+ // Stops the rendering timer.
+ void StopRendering();
+
+ // Calculates the appropriate amount of delay in microseconds given the
+ // current time, the current sample and the next sample (may be NULL,
+ // but is recommended to pass in for smoother playback).
+ void CalculateDelay(base::TimeDelta time, const StreamSample* now,
+ const StreamSample* next, base::TimeDelta* delay_out,
+ bool* should_skip_out);
+
+ private:
+ static const int64 kMinFrameDelayUs;
+ static const int64 kMaxFrameDelayUs;
+
+ base::TimeTicks rendering_start_;
+ base::TimeTicks rendering_stop_;
+ base::TimeDelta last_time_;
+
+ DISALLOW_COPY_AND_ASSIGN(Synchronizer);
+};
+
+} // namespace media
+
+#endif // MEDIA_BASE_SYNCHRONIZER_H_
diff --git a/media/build/media.vcproj b/media/build/media.vcproj
index 36d944d..36e1395 100644
--- a/media/build/media.vcproj
+++ b/media/build/media.vcproj
@@ -176,6 +176,14 @@
RelativePath="..\base\pipeline_impl.h"
>
</File>
+ <File
+ RelativePath="..\base\synchronizer.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\base\synchronizer.h"
+ >
+ </File>
</Filter>
<Filter
Name="audio"
diff --git a/media/media_lib.scons b/media/media_lib.scons
index 690f902..bb5b7a4 100644
--- a/media/media_lib.scons
+++ b/media/media_lib.scons
@@ -38,6 +38,8 @@ input_files = ChromeFileList([
'base/pipeline.h',
'base/pipeline_impl.cc',
'base/pipeline_impl.h',
+ 'base/synchronizer.cc',
+ 'base/synchronizer.h',
]),
MSVSFilter('audio', [
'audio/win/audio_manager_win.h',