Bug 1235301 part 2 - implement FrameStepVideoSink; r?jwwang
MozReview-Commit-ID: xQFISwRMYz
new file mode 100644
--- /dev/null
+++ b/dom/media/mediasink/FrameStepVideoSink.cpp
@@ -0,0 +1,180 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ImageContainer.h"
+#include "FrameStepVideoSink.h"
+#include "MediaQueue.h"
+#include "VideoFrameContainer.h"
+
+using namespace mozilla::layers;
+
+namespace mozilla {
+
+namespace media {
+
+FrameStepVideoSink::FrameStepVideoSink(MediaQueue<MediaData>& aAudioQueue,
+ MediaQueue<MediaData>& aVideoQueue,
+ VideoFrameContainer* aContainer)
+ : mIsStarted(false)
+ , mIsPlaying(false)
+ , mAudioQueue(aAudioQueue)
+ , mVideoQueue(aVideoQueue)
+ , mContainer(aContainer)
+ , mPosition(0)
+{
+}
+
+FrameStepVideoSink::~FrameStepVideoSink()
+{
+}
+
+int64_t
+FrameStepVideoSink::GetEndTime(TrackType aType) const
+{
+ MOZ_ASSERT(mIsStarted, "Must be called after playback starts.");
+
+ if (aType == TrackInfo::kVideoTrack) {
+ return mPosition;
+ }
+ return -1;
+}
+
+int64_t
+FrameStepVideoSink::GetPosition(TimeStamp* aTimeStamp) const
+{
+ MOZ_ASSERT(mIsStarted, "Must be called after playback starts.");
+ if (aTimeStamp) {
+ *aTimeStamp = TimeStamp::Now();
+ }
+ return mPosition;
+}
+
+void
+FrameStepVideoSink::SetPlaying(bool aPlaying)
+{
+ mIsPlaying = aPlaying;
+}
+
+void
+FrameStepVideoSink::Start(int64_t aStartTime, const MediaInfo& aInfo)
+{
+ MOZ_ASSERT(!mIsStarted, "playback already started.");
+ mIsStarted = true;
+ mPosition = aStartTime;
+}
+
+void
+FrameStepVideoSink::Stop()
+{
+ MOZ_ASSERT(mIsStarted, "playback not started.");
+ mIsStarted = false;
+}
+
+bool
+FrameStepVideoSink::IsStarted() const
+{
+ return mIsStarted;
+}
+
+bool
+FrameStepVideoSink::IsPlaying() const
+{
+ return mIsStarted && mIsPlaying;
+}
+
+void
+FrameStepVideoSink::Shutdown()
+{
+ MOZ_ASSERT(!mIsStarted, "Must be called after playback stopped.");
+}
+
+void
+FrameStepVideoSink::Redraw()
+{
+ if (!mContainer || mVideoQueue.GetSize() == 0) {
+ return;
+ }
+
+ VideoData* frame = mVideoQueue.PeekFront()->As<VideoData>();
+ frame->mSentToCompositor = true;
+ if (!frame->mImage || !frame->mImage->IsValid() || frame->mTime < 0) {
+ return;
+ }
+
+ mContainer->SetCurrentFrame(frame->mDisplay, frame->mImage.get(), TimeStamp::Now());
+}
+
+static int64_t
+FindNextFrame(MediaQueue<MediaData>& aQueue, int64_t aTime)
+{
+ AutoTArray<RefPtr<MediaData>, 16> frames;
+ aQueue.GetFirstElements(aQueue.GetSize(), &frames);
+ for (auto&& frame : frames) {
+ VideoData* v = frame->As<VideoData>();
+ if (v->mTime > aTime) {
+ return v->mTime;
+ }
+ }
+ return -1;
+}
+
+static void
+DropFramesUntil(MediaQueue<MediaData>& aQueue, int64_t aTime) {
+ while (aQueue.GetSize() > 0) {
+ if (aQueue.PeekFront()->mTime < aTime) {
+ RefPtr<MediaData> releaseMe = aQueue.PopFront();
+ continue;
+ }
+ break;
+ }
+}
+
+static void
+DropAllFrames(MediaQueue<MediaData>& aQueue) {
+ while(aQueue.GetSize() > 0) {
+ RefPtr<MediaData> releaseMe = aQueue.PopFront();
+ }
+ return;
+}
+
+bool
+FrameStepVideoSink::AdvanceFrame()
+{
+ int64_t newPos = FindNextFrame(mVideoQueue, mPosition);
+ if (newPos < 0) {
+ if (mVideoQueue.IsFinished()) {
+ DropAllFrames(mVideoQueue);
+ DropAllFrames(mAudioQueue);
+ }
+ return false;
+ }
+
+ mPosition = newPos;
+ DropFramesUntil(mVideoQueue, newPos);
+ DropFramesUntil(mAudioQueue, newPos);
+ Redraw();
+
+ return true;
+}
+
+MediaQueue<MediaData>&
+FrameStepVideoSink::VideoQueue() {
+ return mVideoQueue;
+}
+
+bool
+FrameStepVideoSink::HasUnplayedFrames(TrackType aType) const
+{
+ int64_t newPos = FindNextFrame(mVideoQueue, mPosition);
+ if (newPos < 0) {
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace media
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/mediasink/FrameStepVideoSink.h
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef FrameStepVideoSink_h_
+#define FrameStepVideoSink_h_
+
+#include "mozilla/MozPromise.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/TimeStamp.h"
+
+#include "MediaSink.h"
+
+namespace mozilla {
+
+class VideoFrameContainer;
+template <class T> class MediaQueue;
+
+namespace media {
+
+class FrameStepVideoSink : public MediaSink {
+public:
+ FrameStepVideoSink(MediaQueue<MediaData>& aAudioQueue,
+ MediaQueue<MediaData>& aVideoQueue,
+ VideoFrameContainer* aContainer);
+
+ const PlaybackParams& GetPlaybackParams() const override {
+ return mParams;
+ }
+
+ void SetPlaybackParams(const PlaybackParams& aParams) override {
+ mParams = aParams;
+ }
+
+ RefPtr<GenericPromise> OnEnded(TrackType aType) override {
+ return nullptr;
+ }
+
+ int64_t GetEndTime(TrackType aType) const override;
+
+ int64_t GetPosition(TimeStamp* aTimeStamp = nullptr) const override;
+
+ bool HasUnplayedFrames(TrackType aType) const override;
+
+ void SetPlaybackRate(double aPlaybackRate) override {}
+
+ void SetVolume(double aVolume) override {}
+
+ void SetPreservesPitch(bool aPreservesPitch) override {}
+
+ void SetPlaying(bool aPlaying) override;
+
+ void Redraw() override;
+
+ void Start(int64_t aStartTime, const MediaInfo& aInfo) override;
+
+ void Stop() override;
+
+ bool IsStarted() const override;
+
+ bool IsPlaying() const override;
+
+ void Shutdown() override;
+
+ bool AdvanceFrame() override;
+
+ MediaQueue<MediaData>& VideoQueue();
+
+private:
+ virtual ~FrameStepVideoSink();
+
+ PlaybackParams mParams;
+ bool mIsStarted;
+ bool mIsPlaying;
+ MediaQueue<MediaData>& mAudioQueue;
+ MediaQueue<MediaData>& mVideoQueue;
+ VideoFrameContainer* mContainer;
+ int64_t mPosition;
+};
+
+} // namespace media
+} // namespace mozilla
+
+#endif // FrameStepVideoSink_h_
--- a/dom/media/mediasink/MediaSink.h
+++ b/dom/media/mediasink/MediaSink.h
@@ -114,16 +114,20 @@ public:
// Can be called in any state.
virtual bool IsPlaying() const = 0;
// Called on the state machine thread to shut down the sink. All resources
// allocated by this sink should be released.
// Must be called after playback stopped.
virtual void Shutdown() {}
+ // Advance playback position and draw next frame.
+ // Must be called after playback starts.
+ virtual bool AdvanceFrame() { return false; }
+
protected:
virtual ~MediaSink() {}
};
} // namespace media
} // namespace mozilla
#endif //MediaSink_h_
--- a/dom/media/mediasink/moz.build
+++ b/dom/media/mediasink/moz.build
@@ -3,13 +3,14 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
UNIFIED_SOURCES += [
'AudioSinkWrapper.cpp',
'DecodedAudioDataSink.cpp',
'DecodedStream.cpp',
+ 'FrameStepVideoSink.cpp',
'OutputStreamManager.cpp',
'VideoSink.cpp',
]
FINAL_LIBRARY = 'xul'