gecko-dev/dom/media/VideoSegment.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

190 lines
5.6 KiB
C
Raw Normal View History

/* -*- 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.
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 05:24:48 +00:00
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(StreamTime aStart, StreamTime aEnd) {
NS_ASSERTION(aStart >= 0 && aStart < aEnd && aEnd <= mDuration,
"Slice out of bounds");
mDuration = aEnd - aStart;
}
StreamTime GetDuration() const { return mDuration; }
bool CanCombineWithFollowing(const VideoChunk& aOther) const {
return aOther.mFrame == mFrame;
}
bool IsNull() const { return !mFrame.GetImage(); }
void SetNull(StreamTime 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();
}
StreamTime 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, StreamTime aDuration,
const IntSize& aIntrinsicSize,
const PrincipalHandle& aPrincipalHandle,
bool aForceBlack = false,
TimeStamp aTimeStamp = TimeStamp::Now());
void ExtendLastFrameBy(StreamTime aDuration) {
if (aDuration <= 0) {
return;
}
if (mChunks.IsEmpty()) {
mChunks.AppendElement()->SetNull(aDuration);
} else {
mChunks[mChunks.Length() - 1].mDuration += aDuration;
}
mDuration += aDuration;
}
const VideoFrame* GetLastFrame(StreamTime* aStart = nullptr) {
VideoChunk* c = GetLastChunk();
if (!c) {
return nullptr;
}
if (aStart) {
*aStart = mDuration - c->mDuration;
}
return &c->mFrame;
}
VideoChunk* FindChunkContaining(const TimeStamp& aTime) {
Bug 1506093 - Fix DecodedStream A/V sync. r=padenot DecodedStream sends video to its video tracks by initially buffering a set of images, then appending future ones by adding them one by one. A long time ago we refactored how MediaStreamGraph sends images to the screen, i.e., to an ImageContainer. It used to send all future frames to ImageContainer::SetCurrentFrames each time it sent something. After the refactor we just forward any new frame from a direct listener to ImageContainer::SetCurrentFrames. So in case DecodedStream has already sent 10 future frames to its track, and sends another, we end up calling ImageContainer::SetCurrentFrames(frame11). However, this is not how ImageContainer works. The refactor was wrong. Even though the timestamp for frame11 is after a previously buffered frame, it will be ignored. SetCurrentFrames wipes any previously set frames. Hence the word "Current" in its name. This patch largely restores the old behaviour by adding a thin buffering layer between the MSG (in a direct listener) and the ImageContainer. This does not give 100% identical frame sync to VideoSink (how we normally render video), because VideoSink can update the timestamps of already-pushed images by pushing them again. We can't do that here because the SourceMediaStream API only allows appending. It does however get in sync for frames appended after the first frame has been rendered. Differential Revision: https://phabricator.services.mozilla.com/D22897 --HG-- extra : moz-landing-system : lando
2019-03-22 11:41:48 +00:00
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);
Bug 1506093 - Fix DecodedStream A/V sync. r=padenot DecodedStream sends video to its video tracks by initially buffering a set of images, then appending future ones by adding them one by one. A long time ago we refactored how MediaStreamGraph sends images to the screen, i.e., to an ImageContainer. It used to send all future frames to ImageContainer::SetCurrentFrames each time it sent something. After the refactor we just forward any new frame from a direct listener to ImageContainer::SetCurrentFrames. So in case DecodedStream has already sent 10 future frames to its track, and sends another, we end up calling ImageContainer::SetCurrentFrames(frame11). However, this is not how ImageContainer works. The refactor was wrong. Even though the timestamp for frame11 is after a previously buffered frame, it will be ignored. SetCurrentFrames wipes any previously set frames. Hence the word "Current" in its name. This patch largely restores the old behaviour by adding a thin buffering layer between the MSG (in a direct listener) and the ImageContainer. This does not give 100% identical frame sync to VideoSink (how we normally render video), because VideoSink can update the timestamps of already-pushed images by pushing them again. We can't do that here because the SourceMediaStream API only allows appending. It does however get in sync for frames appended after the first frame has been rendered. Differential Revision: https://phabricator.services.mozilla.com/D22897 --HG-- extra : moz-landing-system : lando
2019-03-22 11:41:48 +00:00
if (!chunk) {
return;
}
StreamTime 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);
}
bool IsEmpty() const { return mChunks.IsEmpty(); }
};
} // namespace mozilla
#endif /* MOZILLA_VIDEOSEGMENT_H_ */