VideoSegment.h (7016B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 4 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef MOZILLA_VIDEOSEGMENT_H_ 7 #define MOZILLA_VIDEOSEGMENT_H_ 8 9 #include "ImageContainer.h" 10 #include "MediaSegment.h" 11 #include "TimeUnits.h" 12 #include "gfxPoint.h" 13 #include "nsCOMPtr.h" 14 15 namespace mozilla { 16 17 namespace layers { 18 class Image; 19 } // namespace layers 20 21 class VideoFrame { 22 public: 23 typedef mozilla::layers::Image Image; 24 25 VideoFrame(already_AddRefed<Image> aImage, 26 const gfx::IntSize& aIntrinsicSize); 27 VideoFrame(); 28 ~VideoFrame(); 29 30 bool operator==(const VideoFrame& aFrame) const { 31 return mIntrinsicSize == aFrame.mIntrinsicSize && 32 mForceBlack == aFrame.mForceBlack && 33 ((mForceBlack && aFrame.mForceBlack) || mImage == aFrame.mImage) && 34 mPrincipalHandle == aFrame.mPrincipalHandle; 35 } 36 bool operator!=(const VideoFrame& aFrame) const { 37 return !operator==(aFrame); 38 } 39 40 Image* GetImage() const { return mImage; } 41 void SetForceBlack(bool aForceBlack) { mForceBlack = aForceBlack; } 42 bool GetForceBlack() const { return mForceBlack; } 43 void SetPrincipalHandle(PrincipalHandle aPrincipalHandle) { 44 mPrincipalHandle = std::forward<PrincipalHandle>(aPrincipalHandle); 45 } 46 const PrincipalHandle& GetPrincipalHandle() const { return mPrincipalHandle; } 47 const gfx::IntSize& GetIntrinsicSize() const { return mIntrinsicSize; } 48 void SetNull(); 49 void TakeFrom(VideoFrame* aFrame); 50 51 // Create a planar YCbCr black image. 52 static already_AddRefed<Image> CreateBlackImage(const gfx::IntSize& aSize); 53 54 protected: 55 // mImage can be null to indicate "no video" (aka "empty frame"). It can 56 // still have an intrinsic size in this case. 57 RefPtr<Image> mImage; 58 // The desired size to render the video frame at. 59 gfx::IntSize mIntrinsicSize; 60 bool mForceBlack; 61 // principalHandle for the image in this frame. 62 // This can be compared to an nsIPrincipal when back on main thread. 63 PrincipalHandle mPrincipalHandle; 64 }; 65 66 struct VideoChunk { 67 void SliceTo(TrackTime aStart, TrackTime aEnd) { 68 NS_ASSERTION(aStart >= 0 && aStart < aEnd && aEnd <= mDuration, 69 "Slice out of bounds"); 70 mDuration = aEnd - aStart; 71 } 72 TrackTime GetDuration() const { return mDuration; } 73 bool CanCombineWithFollowing(const VideoChunk& aOther) const { 74 return aOther.mFrame == mFrame; 75 } 76 bool IsNull() const { return !mFrame.GetImage(); } 77 void SetNull(TrackTime aDuration) { 78 mDuration = aDuration; 79 mFrame.SetNull(); 80 mTimeStamp = TimeStamp(); 81 } 82 void SetForceBlack(bool aForceBlack) { mFrame.SetForceBlack(aForceBlack); } 83 84 size_t SizeOfExcludingThisIfUnshared(MallocSizeOf aMallocSizeOf) const { 85 // Future: 86 // - mFrame 87 return 0; 88 } 89 90 const PrincipalHandle& GetPrincipalHandle() const { 91 return mFrame.GetPrincipalHandle(); 92 } 93 94 TrackTime mDuration; 95 VideoFrame mFrame; 96 TimeStamp mTimeStamp; 97 media::TimeUnit mProcessingDuration; 98 media::TimeUnit mMediaTime; 99 layers::ContainerCaptureTime mWebrtcCaptureTime = AsVariant(Nothing()); 100 layers::ContainerReceiveTime mWebrtcReceiveTime; 101 layers::ContainerRtpTimestamp mRtpTimestamp; 102 }; 103 104 class VideoSegment : public MediaSegmentBase<VideoSegment, VideoChunk> { 105 public: 106 typedef mozilla::layers::Image Image; 107 typedef mozilla::gfx::IntSize IntSize; 108 109 VideoSegment(); 110 VideoSegment(VideoSegment&& aSegment); 111 112 VideoSegment(const VideoSegment&) = delete; 113 VideoSegment& operator=(const VideoSegment&) = delete; 114 115 ~VideoSegment(); 116 117 void AppendFrame(const VideoChunk& aChunk, 118 const Maybe<bool>& aForceBlack = Nothing(), 119 const Maybe<TimeStamp>& aTimeStamp = Nothing()); 120 void AppendFrame( 121 already_AddRefed<Image>&& aImage, const IntSize& aIntrinsicSize, 122 const PrincipalHandle& aPrincipalHandle, bool aForceBlack = false, 123 TimeStamp aTimeStamp = TimeStamp::Now(), 124 media::TimeUnit aProcessingDuration = media::TimeUnit::Invalid(), 125 media::TimeUnit aMediaTime = media::TimeUnit::Invalid()); 126 void AppendWebrtcRemoteFrame(already_AddRefed<Image>&& aImage, 127 const IntSize& aIntrinsicSize, 128 const PrincipalHandle& aPrincipalHandle, 129 bool aForceBlack, TimeStamp aTimeStamp, 130 media::TimeUnit aProcessingDuration, 131 uint32_t aRtpTimestamp, 132 int64_t aWebrtcCaptureTimeNtp, 133 int64_t aWebrtcReceiveTimeUs); 134 void AppendWebrtcLocalFrame(already_AddRefed<Image>&& aImage, 135 const IntSize& aIntrinsicSize, 136 const PrincipalHandle& aPrincipalHandle, 137 bool aForceBlack, TimeStamp aTimeStamp, 138 TimeStamp aWebrtcCaptureTime); 139 void ExtendLastFrameBy(TrackTime aDuration) { 140 if (aDuration <= 0) { 141 return; 142 } 143 if (mChunks.IsEmpty()) { 144 mChunks.AppendElement()->SetNull(aDuration); 145 } else { 146 mChunks[mChunks.Length() - 1].mDuration += aDuration; 147 } 148 mDuration += aDuration; 149 } 150 const VideoFrame* GetLastFrame(TrackTime* aStart = nullptr) { 151 VideoChunk* c = GetLastChunk(); 152 if (!c) { 153 return nullptr; 154 } 155 if (aStart) { 156 *aStart = mDuration - c->mDuration; 157 } 158 return &c->mFrame; 159 } 160 VideoChunk* FindChunkContaining(const TimeStamp& aTime) { 161 VideoChunk* previousChunk = nullptr; 162 for (VideoChunk& c : mChunks) { 163 if (c.mTimeStamp.IsNull()) { 164 continue; 165 } 166 if (c.mTimeStamp > aTime) { 167 return previousChunk; 168 } 169 previousChunk = &c; 170 } 171 return previousChunk; 172 } 173 void ForgetUpToTime(const TimeStamp& aTime) { 174 VideoChunk* chunk = FindChunkContaining(aTime); 175 if (!chunk) { 176 return; 177 } 178 TrackTime duration = 0; 179 size_t chunksToRemove = 0; 180 for (const VideoChunk& c : mChunks) { 181 if (c.mTimeStamp >= chunk->mTimeStamp) { 182 break; 183 } 184 duration += c.GetDuration(); 185 ++chunksToRemove; 186 } 187 mChunks.RemoveElementsAt(0, chunksToRemove); 188 mDuration -= duration; 189 MOZ_ASSERT(mChunks.Capacity() >= DEFAULT_SEGMENT_CAPACITY, 190 "Capacity must be retained after removing chunks"); 191 } 192 // Override default impl 193 void ReplaceWithDisabled() override { 194 for (ChunkIterator i(*this); !i.IsEnded(); i.Next()) { 195 VideoChunk& chunk = *i; 196 chunk.SetForceBlack(true); 197 } 198 } 199 200 // Segment-generic methods not in MediaSegmentBase 201 static Type StaticType() { return VIDEO; } 202 203 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override { 204 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); 205 } 206 }; 207 208 } // namespace mozilla 209 210 #endif /* MOZILLA_VIDEOSEGMENT_H_ */