summaryrefslogtreecommitdiffstats
path: root/dom/media/VideoSegment.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/VideoSegment.h')
-rw-r--r--dom/media/VideoSegment.h187
1 files changed, 187 insertions, 0 deletions
diff --git a/dom/media/VideoSegment.h b/dom/media/VideoSegment.h
new file mode 100644
index 0000000000..5421112c9f
--- /dev/null
+++ b/dom/media/VideoSegment.h
@@ -0,0 +1,187 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 MOZILLA_VIDEOSEGMENT_H_
+#define MOZILLA_VIDEOSEGMENT_H_
+
+#include "MediaSegment.h"
+#include "nsCOMPtr.h"
+#include "gfxPoint.h"
+#include "ImageContainer.h"
+
+namespace mozilla {
+
+namespace layers {
+class Image;
+} // namespace layers
+
+class VideoFrame {
+ public:
+ typedef mozilla::layers::Image Image;
+
+ VideoFrame(already_AddRefed<Image> aImage,
+ const gfx::IntSize& aIntrinsicSize);
+ VideoFrame();
+ ~VideoFrame();
+
+ bool operator==(const VideoFrame& aFrame) const {
+ return mIntrinsicSize == aFrame.mIntrinsicSize &&
+ mForceBlack == aFrame.mForceBlack &&
+ ((mForceBlack && aFrame.mForceBlack) || mImage == aFrame.mImage) &&
+ mPrincipalHandle == aFrame.mPrincipalHandle;
+ }
+ bool operator!=(const VideoFrame& aFrame) const {
+ return !operator==(aFrame);
+ }
+
+ Image* GetImage() const { return mImage; }
+ void SetForceBlack(bool aForceBlack) { mForceBlack = aForceBlack; }
+ bool GetForceBlack() const { return mForceBlack; }
+ void SetPrincipalHandle(PrincipalHandle aPrincipalHandle) {
+ mPrincipalHandle = std::forward<PrincipalHandle>(aPrincipalHandle);
+ }
+ const PrincipalHandle& GetPrincipalHandle() const { return mPrincipalHandle; }
+ const gfx::IntSize& GetIntrinsicSize() const { return mIntrinsicSize; }
+ void SetNull();
+ void TakeFrom(VideoFrame* aFrame);
+
+ // Create a planar YCbCr black image.
+ static already_AddRefed<Image> CreateBlackImage(const gfx::IntSize& aSize);
+
+ protected:
+ // mImage can be null to indicate "no video" (aka "empty frame"). It can
+ // still have an intrinsic size in this case.
+ RefPtr<Image> mImage;
+ // The desired size to render the video frame at.
+ gfx::IntSize mIntrinsicSize;
+ bool mForceBlack;
+ // principalHandle for the image in this frame.
+ // This can be compared to an nsIPrincipal when back on main thread.
+ PrincipalHandle mPrincipalHandle;
+};
+
+struct VideoChunk {
+ void SliceTo(TrackTime aStart, TrackTime aEnd) {
+ NS_ASSERTION(aStart >= 0 && aStart < aEnd && aEnd <= mDuration,
+ "Slice out of bounds");
+ mDuration = aEnd - aStart;
+ }
+ TrackTime GetDuration() const { return mDuration; }
+ bool CanCombineWithFollowing(const VideoChunk& aOther) const {
+ return aOther.mFrame == mFrame;
+ }
+ bool IsNull() const { return !mFrame.GetImage(); }
+ void SetNull(TrackTime aDuration) {
+ mDuration = aDuration;
+ mFrame.SetNull();
+ mTimeStamp = TimeStamp();
+ }
+ void SetForceBlack(bool aForceBlack) { mFrame.SetForceBlack(aForceBlack); }
+
+ size_t SizeOfExcludingThisIfUnshared(MallocSizeOf aMallocSizeOf) const {
+ // Future:
+ // - mFrame
+ return 0;
+ }
+
+ const PrincipalHandle& GetPrincipalHandle() const {
+ return mFrame.GetPrincipalHandle();
+ }
+
+ TrackTime mDuration;
+ VideoFrame mFrame;
+ TimeStamp mTimeStamp;
+};
+
+class VideoSegment : public MediaSegmentBase<VideoSegment, VideoChunk> {
+ public:
+ typedef mozilla::layers::Image Image;
+ typedef mozilla::gfx::IntSize IntSize;
+
+ VideoSegment();
+ VideoSegment(VideoSegment&& aSegment);
+
+ VideoSegment(const VideoSegment&) = delete;
+ VideoSegment& operator=(const VideoSegment&) = delete;
+
+ ~VideoSegment();
+
+ void AppendFrame(already_AddRefed<Image>&& aImage,
+ const IntSize& aIntrinsicSize,
+ const PrincipalHandle& aPrincipalHandle,
+ bool aForceBlack = false,
+ TimeStamp aTimeStamp = TimeStamp::Now());
+ void ExtendLastFrameBy(TrackTime aDuration) {
+ if (aDuration <= 0) {
+ return;
+ }
+ if (mChunks.IsEmpty()) {
+ mChunks.AppendElement()->SetNull(aDuration);
+ } else {
+ mChunks[mChunks.Length() - 1].mDuration += aDuration;
+ }
+ mDuration += aDuration;
+ }
+ const VideoFrame* GetLastFrame(TrackTime* aStart = nullptr) {
+ VideoChunk* c = GetLastChunk();
+ if (!c) {
+ return nullptr;
+ }
+ if (aStart) {
+ *aStart = mDuration - c->mDuration;
+ }
+ return &c->mFrame;
+ }
+ VideoChunk* FindChunkContaining(const TimeStamp& aTime) {
+ VideoChunk* previousChunk = nullptr;
+ for (VideoChunk& c : mChunks) {
+ if (c.mTimeStamp.IsNull()) {
+ continue;
+ }
+ if (c.mTimeStamp > aTime) {
+ return previousChunk;
+ }
+ previousChunk = &c;
+ }
+ return previousChunk;
+ }
+ void ForgetUpToTime(const TimeStamp& aTime) {
+ VideoChunk* chunk = FindChunkContaining(aTime);
+ if (!chunk) {
+ return;
+ }
+ TrackTime duration = 0;
+ size_t chunksToRemove = 0;
+ for (const VideoChunk& c : mChunks) {
+ if (c.mTimeStamp >= chunk->mTimeStamp) {
+ break;
+ }
+ duration += c.GetDuration();
+ ++chunksToRemove;
+ }
+ mChunks.RemoveElementsAt(0, chunksToRemove);
+ mDuration -= duration;
+ MOZ_ASSERT(mChunks.Capacity() >= DEFAULT_SEGMENT_CAPACITY,
+ "Capacity must be retained after removing chunks");
+ }
+ // Override default impl
+ void ReplaceWithDisabled() override {
+ for (ChunkIterator i(*this); !i.IsEnded(); i.Next()) {
+ VideoChunk& chunk = *i;
+ chunk.SetForceBlack(true);
+ }
+ }
+
+ // Segment-generic methods not in MediaSegmentBase
+ static Type StaticType() { return VIDEO; }
+
+ size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override {
+ return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
+ }
+};
+
+} // namespace mozilla
+
+#endif /* MOZILLA_VIDEOSEGMENT_H_ */