Merge mozilla-central to fx-team

This commit is contained in:
Carsten "Tomcat" Book 2015-07-06 13:07:21 +02:00
commit b85c9f03f4
78 changed files with 2218 additions and 1855 deletions

View File

@ -6,7 +6,13 @@
#include "DecodedStream.h"
#include "MediaStreamGraph.h"
#include "mozilla/ReentrantMonitor.h"
#include "AudioSegment.h"
#include "VideoSegment.h"
#include "MediaQueue.h"
#include "MediaData.h"
#include "MediaInfo.h"
#include "SharedBuffer.h"
#include "VideoUtils.h"
namespace mozilla {
@ -82,7 +88,7 @@ UpdateStreamBlocking(MediaStream* aStream, bool aBlocking)
}
}
DecodedStreamData::DecodedStreamData(SourceMediaStream* aStream)
DecodedStreamData::DecodedStreamData(SourceMediaStream* aStream, bool aPlaying)
: mAudioFramesWritten(0)
, mNextVideoTime(-1)
, mNextAudioTime(-1)
@ -91,13 +97,16 @@ DecodedStreamData::DecodedStreamData(SourceMediaStream* aStream)
, mHaveSentFinishAudio(false)
, mHaveSentFinishVideo(false)
, mStream(aStream)
, mPlaying(false)
, mPlaying(aPlaying)
, mEOSVideoCompensation(false)
{
mListener = new DecodedStreamGraphListener(mStream);
mStream->AddListener(mListener);
// Block the stream as mPlaying is initially false.
UpdateStreamBlocking(mStream, true);
// Block the stream if we are not playing.
if (!aPlaying) {
UpdateStreamBlocking(mStream, true);
}
}
DecodedStreamData::~DecodedStreamData()
@ -152,26 +161,9 @@ private:
void DoNotifyFinished()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mDecodedStream) {
return;
}
// Remove the finished stream so it won't block the decoded stream.
ReentrantMonitorAutoEnter mon(mDecodedStream->GetReentrantMonitor());
auto& streams = mDecodedStream->OutputStreams();
// Don't read |mDecodedStream| in the loop since removing the element will lead
// to ~OutputStreamData() which will call Forget() to reset |mDecodedStream|.
for (int32_t i = streams.Length() - 1; i >= 0; --i) {
auto& os = streams[i];
MediaStream* p = os.mStream.get();
if (p == mStream.get()) {
if (os.mPort) {
os.mPort->Destroy();
os.mPort = nullptr;
}
streams.RemoveElementAt(i);
break;
}
if (mDecodedStream) {
// Remove the finished stream so it won't block the decoded stream.
mDecodedStream->Remove(mStream);
}
}
@ -195,17 +187,11 @@ OutputStreamData::Init(DecodedStream* aDecodedStream, ProcessedMediaStream* aStr
DecodedStream::DecodedStream()
: mMonitor("DecodedStream::mMonitor")
, mPlaying(false)
{
//
}
DecodedStreamData*
DecodedStream::GetData() const
{
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
return mData.get();
}
void
DecodedStream::DestroyData()
{
@ -241,6 +227,16 @@ DecodedStream::DestroyData()
mData = nullptr;
}
void
DecodedStream::RecreateData()
{
nsRefPtr<DecodedStream> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self] () -> void {
self->RecreateData(nullptr);
});
AbstractThread::MainThread()->Dispatch(r.forget());
}
void
DecodedStream::RecreateData(MediaStreamGraph* aGraph)
{
@ -254,7 +250,7 @@ DecodedStream::RecreateData(MediaStreamGraph* aGraph)
}
auto source = aGraph->CreateSourceStream(nullptr);
DestroyData();
mData.reset(new DecodedStreamData(source));
mData.reset(new DecodedStreamData(source, mPlaying));
// Note that the delay between removing ports in DestroyDecodedStream
// and adding new ones won't cause a glitch since all graph operations
@ -270,6 +266,7 @@ DecodedStream::RecreateData(MediaStreamGraph* aGraph)
nsTArray<OutputStreamData>&
DecodedStream::OutputStreams()
{
MOZ_ASSERT(NS_IsMainThread());
GetReentrantMonitor().AssertCurrentThreadIn();
return mOutputStreams;
}
@ -302,6 +299,10 @@ DecodedStream::Connect(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
MOZ_ASSERT(NS_IsMainThread());
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
if (!mData) {
RecreateData(aStream->Graph());
}
OutputStreamData* os = OutputStreams().AppendElement();
os->Init(this, aStream);
Connect(os);
@ -311,12 +312,362 @@ DecodedStream::Connect(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
}
}
void
DecodedStream::Remove(MediaStream* aStream)
{
MOZ_ASSERT(NS_IsMainThread());
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
auto& streams = OutputStreams();
for (int32_t i = streams.Length() - 1; i >= 0; --i) {
auto& os = streams[i];
MediaStream* p = os.mStream.get();
if (p == aStream) {
if (os.mPort) {
os.mPort->Destroy();
os.mPort = nullptr;
}
streams.RemoveElementAt(i);
break;
}
}
}
void
DecodedStream::SetPlaying(bool aPlaying)
{
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
MOZ_ASSERT(mData);
mData->SetPlaying(aPlaying);
mPlaying = aPlaying;
if (mData) {
mData->SetPlaying(aPlaying);
}
}
bool
DecodedStream::HaveEnoughAudio(const MediaInfo& aInfo) const
{
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
if (mData->mStreamInitialized && !mData->mHaveSentFinishAudio) {
MOZ_ASSERT(aInfo.HasAudio());
TrackID audioTrackId = aInfo.mAudio.mTrackId;
if (!mData->mStream->HaveEnoughBuffered(audioTrackId)) {
return false;
}
}
return true;
}
bool
DecodedStream::HaveEnoughVideo(const MediaInfo& aInfo) const
{
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
if (mData->mStreamInitialized && !mData->mHaveSentFinishVideo) {
MOZ_ASSERT(aInfo.HasVideo());
TrackID videoTrackId = aInfo.mVideo.mTrackId;
if (!mData->mStream->HaveEnoughBuffered(videoTrackId)) {
return false;
}
}
return true;
}
void
DecodedStream::InitTracks(int64_t aStartTime, const MediaInfo& aInfo)
{
GetReentrantMonitor().AssertCurrentThreadIn();
if (mData->mStreamInitialized) {
return;
}
SourceMediaStream* sourceStream = mData->mStream;
if (aInfo.HasAudio()) {
TrackID audioTrackId = aInfo.mAudio.mTrackId;
AudioSegment* audio = new AudioSegment();
sourceStream->AddAudioTrack(audioTrackId, aInfo.mAudio.mRate, 0, audio,
SourceMediaStream::ADDTRACK_QUEUED);
mData->mNextAudioTime = aStartTime;
}
if (aInfo.HasVideo()) {
TrackID videoTrackId = aInfo.mVideo.mTrackId;
VideoSegment* video = new VideoSegment();
sourceStream->AddTrack(videoTrackId, 0, video,
SourceMediaStream::ADDTRACK_QUEUED);
mData->mNextVideoTime = aStartTime;
}
sourceStream->FinishAddTracks();
mData->mStreamInitialized = true;
}
static void
SendStreamAudio(DecodedStreamData* aStream, int64_t aStartTime,
AudioData* aAudio, AudioSegment* aOutput,
uint32_t aRate, double aVolume)
{
// This logic has to mimic AudioSink closely to make sure we write
// the exact same silences
CheckedInt64 audioWrittenOffset = aStream->mAudioFramesWritten +
UsecsToFrames(aStartTime, aRate);
CheckedInt64 frameOffset = UsecsToFrames(aAudio->mTime, aRate);
if (!audioWrittenOffset.isValid() ||
!frameOffset.isValid() ||
// ignore packet that we've already processed
frameOffset.value() + aAudio->mFrames <= audioWrittenOffset.value()) {
return;
}
if (audioWrittenOffset.value() < frameOffset.value()) {
int64_t silentFrames = frameOffset.value() - audioWrittenOffset.value();
// Write silence to catch up
AudioSegment silence;
silence.InsertNullDataAtStart(silentFrames);
aStream->mAudioFramesWritten += silentFrames;
audioWrittenOffset += silentFrames;
aOutput->AppendFrom(&silence);
}
MOZ_ASSERT(audioWrittenOffset.value() >= frameOffset.value());
int64_t offset = audioWrittenOffset.value() - frameOffset.value();
size_t framesToWrite = aAudio->mFrames - offset;
aAudio->EnsureAudioBuffer();
nsRefPtr<SharedBuffer> buffer = aAudio->mAudioBuffer;
AudioDataValue* bufferData = static_cast<AudioDataValue*>(buffer->Data());
nsAutoTArray<const AudioDataValue*, 2> channels;
for (uint32_t i = 0; i < aAudio->mChannels; ++i) {
channels.AppendElement(bufferData + i * aAudio->mFrames + offset);
}
aOutput->AppendFrames(buffer.forget(), channels, framesToWrite);
aStream->mAudioFramesWritten += framesToWrite;
aOutput->ApplyVolume(aVolume);
aStream->mNextAudioTime = aAudio->GetEndTime();
}
void
DecodedStream::SendAudio(int64_t aStartTime,
const MediaInfo& aInfo,
MediaQueue<AudioData>& aQueue,
double aVolume, bool aIsSameOrigin)
{
GetReentrantMonitor().AssertCurrentThreadIn();
if (!aInfo.HasAudio()) {
return;
}
AudioSegment output;
uint32_t rate = aInfo.mAudio.mRate;
nsAutoTArray<nsRefPtr<AudioData>,10> audio;
TrackID audioTrackId = aInfo.mAudio.mTrackId;
SourceMediaStream* sourceStream = mData->mStream;
// It's OK to hold references to the AudioData because AudioData
// is ref-counted.
aQueue.GetElementsAfter(mData->mNextAudioTime, &audio);
for (uint32_t i = 0; i < audio.Length(); ++i) {
SendStreamAudio(mData.get(), aStartTime, audio[i], &output, rate, aVolume);
}
if (!aIsSameOrigin) {
output.ReplaceWithDisabled();
}
// |mNextAudioTime| is updated as we process each audio sample in
// SendStreamAudio(). This is consistent with how |mNextVideoTime|
// is updated for video samples.
if (output.GetDuration() > 0) {
sourceStream->AppendToTrack(audioTrackId, &output);
}
if (aQueue.IsFinished() && !mData->mHaveSentFinishAudio) {
sourceStream->EndTrack(audioTrackId);
mData->mHaveSentFinishAudio = true;
}
}
static void
WriteVideoToMediaStream(MediaStream* aStream,
layers::Image* aImage,
int64_t aEndMicroseconds,
int64_t aStartMicroseconds,
const mozilla::gfx::IntSize& aIntrinsicSize,
VideoSegment* aOutput)
{
nsRefPtr<layers::Image> image = aImage;
StreamTime duration =
aStream->MicrosecondsToStreamTimeRoundDown(aEndMicroseconds) -
aStream->MicrosecondsToStreamTimeRoundDown(aStartMicroseconds);
aOutput->AppendFrame(image.forget(), duration, aIntrinsicSize);
}
static bool
ZeroDurationAtLastChunk(VideoSegment& aInput)
{
// Get the last video frame's start time in VideoSegment aInput.
// If the start time is equal to the duration of aInput, means the last video
// frame's duration is zero.
StreamTime lastVideoStratTime;
aInput.GetLastFrame(&lastVideoStratTime);
return lastVideoStratTime == aInput.GetDuration();
}
void
DecodedStream::SendVideo(int64_t aStartTime,
const MediaInfo& aInfo,
MediaQueue<VideoData>& aQueue,
bool aIsSameOrigin)
{
GetReentrantMonitor().AssertCurrentThreadIn();
if (!aInfo.HasVideo()) {
return;
}
VideoSegment output;
TrackID videoTrackId = aInfo.mVideo.mTrackId;
nsAutoTArray<nsRefPtr<VideoData>, 10> video;
SourceMediaStream* sourceStream = mData->mStream;
// It's OK to hold references to the VideoData because VideoData
// is ref-counted.
aQueue.GetElementsAfter(mData->mNextVideoTime, &video);
for (uint32_t i = 0; i < video.Length(); ++i) {
VideoData* v = video[i];
if (mData->mNextVideoTime < v->mTime) {
// Write last video frame to catch up. mLastVideoImage can be null here
// which is fine, it just means there's no video.
// TODO: |mLastVideoImage| should come from the last image rendered
// by the state machine. This will avoid the black frame when capture
// happens in the middle of playback (especially in th middle of a
// video frame). E.g. if we have a video frame that is 30 sec long
// and capture happens at 15 sec, we'll have to append a black frame
// that is 15 sec long.
WriteVideoToMediaStream(sourceStream, mData->mLastVideoImage, v->mTime,
mData->mNextVideoTime, mData->mLastVideoImageDisplaySize, &output);
mData->mNextVideoTime = v->mTime;
}
if (mData->mNextVideoTime < v->GetEndTime()) {
WriteVideoToMediaStream(sourceStream, v->mImage,
v->GetEndTime(), mData->mNextVideoTime, v->mDisplay, &output);
mData->mNextVideoTime = v->GetEndTime();
mData->mLastVideoImage = v->mImage;
mData->mLastVideoImageDisplaySize = v->mDisplay;
}
}
// Check the output is not empty.
if (output.GetLastFrame()) {
mData->mEOSVideoCompensation = ZeroDurationAtLastChunk(output);
}
if (!aIsSameOrigin) {
output.ReplaceWithDisabled();
}
if (output.GetDuration() > 0) {
sourceStream->AppendToTrack(videoTrackId, &output);
}
if (aQueue.IsFinished() && !mData->mHaveSentFinishVideo) {
if (mData->mEOSVideoCompensation) {
VideoSegment endSegment;
// Calculate the deviation clock time from DecodedStream.
int64_t deviation_usec = sourceStream->StreamTimeToMicroseconds(1);
WriteVideoToMediaStream(sourceStream, mData->mLastVideoImage,
mData->mNextVideoTime + deviation_usec, mData->mNextVideoTime,
mData->mLastVideoImageDisplaySize, &endSegment);
mData->mNextVideoTime += deviation_usec;
MOZ_ASSERT(endSegment.GetDuration() > 0);
if (!aIsSameOrigin) {
endSegment.ReplaceWithDisabled();
}
sourceStream->AppendToTrack(videoTrackId, &endSegment);
}
sourceStream->EndTrack(videoTrackId);
mData->mHaveSentFinishVideo = true;
}
}
void
DecodedStream::AdvanceTracks(int64_t aStartTime, const MediaInfo& aInfo)
{
GetReentrantMonitor().AssertCurrentThreadIn();
StreamTime endPosition = 0;
if (aInfo.HasAudio()) {
StreamTime audioEnd = mData->mStream->TicksToTimeRoundDown(
aInfo.mAudio.mRate, mData->mAudioFramesWritten);
endPosition = std::max(endPosition, audioEnd);
}
if (aInfo.HasVideo()) {
StreamTime videoEnd = mData->mStream->MicrosecondsToStreamTimeRoundDown(
mData->mNextVideoTime - aStartTime);
endPosition = std::max(endPosition, videoEnd);
}
if (!mData->mHaveSentFinish) {
mData->mStream->AdvanceKnownTracksTime(endPosition);
}
}
bool
DecodedStream::SendData(int64_t aStartTime,
const MediaInfo& aInfo,
MediaQueue<AudioData>& aAudioQueue,
MediaQueue<VideoData>& aVideoQueue,
double aVolume, bool aIsSameOrigin)
{
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
InitTracks(aStartTime, aInfo);
SendAudio(aStartTime, aInfo, aAudioQueue, aVolume, aIsSameOrigin);
SendVideo(aStartTime, aInfo, aVideoQueue, aIsSameOrigin);
AdvanceTracks(aStartTime, aInfo);
bool finished = (!aInfo.HasAudio() || aAudioQueue.IsFinished()) &&
(!aInfo.HasVideo() || aVideoQueue.IsFinished());
if (finished && !mData->mHaveSentFinish) {
mData->mHaveSentFinish = true;
mData->mStream->Finish();
}
return finished;
}
CheckedInt64
DecodedStream::AudioEndTime(int64_t aStartTime, uint32_t aRate) const
{
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
return aStartTime + FramesToUsecs(mData->mAudioFramesWritten, aRate);
}
int64_t
DecodedStream::GetPosition() const
{
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
return mData->GetPosition();
}
bool
DecodedStream::IsFinished() const
{
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
return mData->IsFinished();
}
} // namespace mozilla

View File

@ -9,11 +9,19 @@
#include "nsRefPtr.h"
#include "nsTArray.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/ReentrantMonitor.h"
namespace mozilla {
class AudioData;
class VideoData;
class MediaInfo;
class AudioSegment;
class MediaStream;
class MediaInputPort;
class SourceMediaStream;
class ProcessedMediaStream;
@ -23,6 +31,8 @@ class OutputStreamListener;
class ReentrantMonitor;
class MediaStreamGraph;
template <class T> class MediaQueue;
namespace layers {
class Image;
}
@ -37,7 +47,7 @@ class Image;
*/
class DecodedStreamData {
public:
explicit DecodedStreamData(SourceMediaStream* aStream);
DecodedStreamData(SourceMediaStream* aStream, bool aPlaying);
~DecodedStreamData();
bool IsFinished() const;
int64_t GetPosition() const;
@ -84,18 +94,47 @@ public:
};
class DecodedStream {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecodedStream);
public:
DecodedStream();
DecodedStreamData* GetData() const;
void DestroyData();
void RecreateData(MediaStreamGraph* aGraph);
nsTArray<OutputStreamData>& OutputStreams();
ReentrantMonitor& GetReentrantMonitor() const;
void RecreateData();
void Connect(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
void Remove(MediaStream* aStream);
void SetPlaying(bool aPlaying);
bool HaveEnoughAudio(const MediaInfo& aInfo) const;
bool HaveEnoughVideo(const MediaInfo& aInfo) const;
CheckedInt64 AudioEndTime(int64_t aStartTime, uint32_t aRate) const;
int64_t GetPosition() const;
bool IsFinished() const;
// Return true if stream is finished.
bool SendData(int64_t aStartTime,
const MediaInfo& aInfo,
MediaQueue<AudioData>& aAudioQueue,
MediaQueue<VideoData>& aVideoQueue,
double aVolume, bool aIsSameOrigin);
protected:
virtual ~DecodedStream() {}
private:
ReentrantMonitor& GetReentrantMonitor() const;
void RecreateData(MediaStreamGraph* aGraph);
void Connect(OutputStreamData* aStream);
nsTArray<OutputStreamData>& OutputStreams();
void InitTracks(int64_t aStartTime, const MediaInfo& aInfo);
void AdvanceTracks(int64_t aStartTime, const MediaInfo& aInfo);
void SendAudio(int64_t aStartTime,
const MediaInfo& aInfo,
MediaQueue<AudioData>& aQueue,
double aVolume, bool aIsSameOrigin);
void SendVideo(int64_t aStartTime,
const MediaInfo& aInfo,
MediaQueue<VideoData>& aQueue,
bool aIsSameOrigin);
UniquePtr<DecodedStreamData> mData;
// Data about MediaStreams that are being fed by the decoder.
@ -109,6 +148,8 @@ private:
// Please move all capture-stream related code from MDSM into DecodedStream
// and apply "dispatch + mirroring" to get rid of this monitor in the future.
mutable ReentrantMonitor mMonitor;
bool mPlaying;
};
} // namespace mozilla

View File

@ -296,7 +296,8 @@ public:
// Make sure ResetDecode hasn't been called in the mean time.
if (!mReader->mBaseVideoPromise.IsEmpty()) {
mReader->RequestVideoData(/* aSkip = */ true, mTimeThreshold);
mReader->RequestVideoData(/* aSkip = */ true, mTimeThreshold,
/* aForceDecodeAhead = */ false);
}
return NS_OK;
@ -333,7 +334,8 @@ private:
nsRefPtr<MediaDecoderReader::VideoDataPromise>
MediaDecoderReader::RequestVideoData(bool aSkipToNextKeyframe,
int64_t aTimeThreshold)
int64_t aTimeThreshold,
bool aForceDecodeAhead)
{
nsRefPtr<VideoDataPromise> p = mBaseVideoPromise.Ensure(__func__);
bool skip = aSkipToNextKeyframe;

View File

@ -147,7 +147,7 @@ public:
// If aSkipToKeyframe is true, the decode should skip ahead to the
// the next keyframe at or after aTimeThreshold microseconds.
virtual nsRefPtr<VideoDataPromise>
RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold);
RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold, bool aForceDecodeAhead);
friend class ReRequestVideoWithSkipTask;
friend class ReRequestAudioTask;

View File

@ -45,7 +45,6 @@
namespace mozilla {
using namespace mozilla::dom;
using namespace mozilla::gfx;
using namespace mozilla::layers;
using namespace mozilla::media;
@ -171,6 +170,7 @@ static int64_t DurationToUsecs(TimeDuration aDuration) {
static const uint32_t MIN_VIDEO_QUEUE_SIZE = 3;
static const uint32_t MAX_VIDEO_QUEUE_SIZE = 10;
static const uint32_t SCARCE_VIDEO_QUEUE_SIZE = 1;
static uint32_t sVideoQueueDefaultSize = MAX_VIDEO_QUEUE_SIZE;
static uint32_t sVideoQueueHWAccelSize = MIN_VIDEO_QUEUE_SIZE;
@ -239,7 +239,8 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mDecodingFrozenAtStateDecoding(false),
mSentLoadedMetadataEvent(false),
mSentFirstFrameLoadedEvent(false),
mSentPlaybackEndedEvent(false)
mSentPlaybackEndedEvent(false),
mDecodedStream(new DecodedStream())
{
MOZ_COUNT_CTOR(MediaDecoderStateMachine);
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
@ -357,236 +358,21 @@ int64_t MediaDecoderStateMachine::GetDecodedAudioDuration()
return audioDecoded;
}
void MediaDecoderStateMachine::SendStreamAudio(AudioData* aAudio,
DecodedStreamData* aStream,
AudioSegment* aOutput)
{
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
// This logic has to mimic AudioSink closely to make sure we write
// the exact same silences
CheckedInt64 audioWrittenOffset = aStream->mAudioFramesWritten +
UsecsToFrames(mStreamStartTime, mInfo.mAudio.mRate);
CheckedInt64 frameOffset = UsecsToFrames(aAudio->mTime, mInfo.mAudio.mRate);
if (!audioWrittenOffset.isValid() ||
!frameOffset.isValid() ||
// ignore packet that we've already processed
frameOffset.value() + aAudio->mFrames <= audioWrittenOffset.value()) {
return;
}
if (audioWrittenOffset.value() < frameOffset.value()) {
int64_t silentFrames = frameOffset.value() - audioWrittenOffset.value();
// Write silence to catch up
VERBOSE_LOG("writing %lld frames of silence to MediaStream", silentFrames);
AudioSegment silence;
silence.InsertNullDataAtStart(silentFrames);
aStream->mAudioFramesWritten += silentFrames;
audioWrittenOffset += silentFrames;
aOutput->AppendFrom(&silence);
}
MOZ_ASSERT(audioWrittenOffset.value() >= frameOffset.value());
int64_t offset = audioWrittenOffset.value() - frameOffset.value();
size_t framesToWrite = aAudio->mFrames - offset;
aAudio->EnsureAudioBuffer();
nsRefPtr<SharedBuffer> buffer = aAudio->mAudioBuffer;
AudioDataValue* bufferData = static_cast<AudioDataValue*>(buffer->Data());
nsAutoTArray<const AudioDataValue*,2> channels;
for (uint32_t i = 0; i < aAudio->mChannels; ++i) {
channels.AppendElement(bufferData + i*aAudio->mFrames + offset);
}
aOutput->AppendFrames(buffer.forget(), channels, framesToWrite);
VERBOSE_LOG("writing %u frames of data to MediaStream for AudioData at %lld",
static_cast<unsigned>(framesToWrite),
aAudio->mTime);
aStream->mAudioFramesWritten += framesToWrite;
aOutput->ApplyVolume(mVolume);
aStream->mNextAudioTime = aAudio->GetEndTime();
}
static void WriteVideoToMediaStream(MediaStream* aStream,
layers::Image* aImage,
int64_t aEndMicroseconds,
int64_t aStartMicroseconds,
const IntSize& aIntrinsicSize,
VideoSegment* aOutput)
{
nsRefPtr<layers::Image> image = aImage;
StreamTime duration =
aStream->MicrosecondsToStreamTimeRoundDown(aEndMicroseconds) -
aStream->MicrosecondsToStreamTimeRoundDown(aStartMicroseconds);
aOutput->AppendFrame(image.forget(), duration, aIntrinsicSize);
}
static bool ZeroDurationAtLastChunk(VideoSegment& aInput)
{
// Get the last video frame's start time in VideoSegment aInput.
// If the start time is equal to the duration of aInput, means the last video
// frame's duration is zero.
StreamTime lastVideoStratTime;
aInput.GetLastFrame(&lastVideoStratTime);
return lastVideoStratTime == aInput.GetDuration();
}
void MediaDecoderStateMachine::SendStreamData()
{
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
MOZ_ASSERT(!mAudioSink, "Should've been stopped in RunStateMachine()");
MOZ_ASSERT(mStreamStartTime != -1);
DecodedStreamData* stream = GetDecodedStream();
bool finished = mDecodedStream->SendData(
mStreamStartTime, mInfo, AudioQueue(), VideoQueue(),
mVolume, mDecoder->IsSameOriginMedia());
bool finished =
(!mInfo.HasAudio() || AudioQueue().IsFinished()) &&
(!mInfo.HasVideo() || VideoQueue().IsFinished());
{
SourceMediaStream* mediaStream = stream->mStream;
StreamTime endPosition = 0;
const bool isSameOrigin = mDecoder->IsSameOriginMedia();
if (!stream->mStreamInitialized) {
if (mInfo.HasAudio()) {
TrackID audioTrackId = mInfo.mAudio.mTrackId;
AudioSegment* audio = new AudioSegment();
mediaStream->AddAudioTrack(audioTrackId, mInfo.mAudio.mRate, 0, audio,
SourceMediaStream::ADDTRACK_QUEUED);
stream->mNextAudioTime = mStreamStartTime;
}
if (mInfo.HasVideo()) {
TrackID videoTrackId = mInfo.mVideo.mTrackId;
VideoSegment* video = new VideoSegment();
mediaStream->AddTrack(videoTrackId, 0, video,
SourceMediaStream::ADDTRACK_QUEUED);
stream->mNextVideoTime = mStreamStartTime;
}
mediaStream->FinishAddTracks();
stream->mStreamInitialized = true;
}
if (mInfo.HasAudio()) {
MOZ_ASSERT(stream->mNextAudioTime != -1, "Should've been initialized");
TrackID audioTrackId = mInfo.mAudio.mTrackId;
nsAutoTArray<nsRefPtr<AudioData>,10> audio;
// It's OK to hold references to the AudioData because AudioData
// is ref-counted.
AudioQueue().GetElementsAfter(stream->mNextAudioTime, &audio);
AudioSegment output;
for (uint32_t i = 0; i < audio.Length(); ++i) {
SendStreamAudio(audio[i], stream, &output);
}
if (!isSameOrigin) {
output.ReplaceWithDisabled();
}
// |mNextAudioTime| is updated as we process each audio sample in
// SendStreamAudio(). This is consistent with how |mNextVideoTime|
// is updated for video samples.
if (output.GetDuration() > 0) {
mediaStream->AppendToTrack(audioTrackId, &output);
}
if (AudioQueue().IsFinished() && !stream->mHaveSentFinishAudio) {
mediaStream->EndTrack(audioTrackId);
stream->mHaveSentFinishAudio = true;
}
endPosition = std::max(endPosition,
mediaStream->TicksToTimeRoundDown(mInfo.mAudio.mRate,
stream->mAudioFramesWritten));
CheckedInt64 playedUsecs = mStreamStartTime +
FramesToUsecs(stream->mAudioFramesWritten, mInfo.mAudio.mRate);
if (playedUsecs.isValid()) {
OnAudioEndTimeUpdate(playedUsecs.value());
}
}
if (mInfo.HasVideo()) {
MOZ_ASSERT(stream->mNextVideoTime != -1, "Should've been initialized");
TrackID videoTrackId = mInfo.mVideo.mTrackId;
nsAutoTArray<nsRefPtr<VideoData>,10> video;
// It's OK to hold references to the VideoData because VideoData
// is ref-counted.
VideoQueue().GetElementsAfter(stream->mNextVideoTime, &video);
VideoSegment output;
for (uint32_t i = 0; i < video.Length(); ++i) {
VideoData* v = video[i];
if (stream->mNextVideoTime < v->mTime) {
VERBOSE_LOG("writing last video to MediaStream %p for %lldus",
mediaStream, v->mTime - stream->mNextVideoTime);
// Write last video frame to catch up. mLastVideoImage can be null here
// which is fine, it just means there's no video.
// TODO: |mLastVideoImage| should come from the last image rendered
// by the state machine. This will avoid the black frame when capture
// happens in the middle of playback (especially in th middle of a
// video frame). E.g. if we have a video frame that is 30 sec long
// and capture happens at 15 sec, we'll have to append a black frame
// that is 15 sec long.
WriteVideoToMediaStream(mediaStream, stream->mLastVideoImage,
v->mTime, stream->mNextVideoTime, stream->mLastVideoImageDisplaySize,
&output);
stream->mNextVideoTime = v->mTime;
}
if (stream->mNextVideoTime < v->GetEndTime()) {
VERBOSE_LOG("writing video frame %lldus to MediaStream %p for %lldus",
v->mTime, mediaStream, v->GetEndTime() - stream->mNextVideoTime);
WriteVideoToMediaStream(mediaStream, v->mImage,
v->GetEndTime(), stream->mNextVideoTime, v->mDisplay,
&output);
stream->mNextVideoTime = v->GetEndTime();
stream->mLastVideoImage = v->mImage;
stream->mLastVideoImageDisplaySize = v->mDisplay;
} else {
VERBOSE_LOG("skipping writing video frame %lldus (end %lldus) to MediaStream",
v->mTime, v->GetEndTime());
}
}
// Check the output is not empty.
if (output.GetLastFrame()) {
stream->mEOSVideoCompensation = ZeroDurationAtLastChunk(output);
}
if (!isSameOrigin) {
output.ReplaceWithDisabled();
}
if (output.GetDuration() > 0) {
mediaStream->AppendToTrack(videoTrackId, &output);
}
if (VideoQueue().IsFinished() && !stream->mHaveSentFinishVideo) {
if (stream->mEOSVideoCompensation) {
VideoSegment endSegment;
// Calculate the deviation clock time from DecodedStream.
int64_t deviation_usec = mediaStream->StreamTimeToMicroseconds(1);
WriteVideoToMediaStream(mediaStream, stream->mLastVideoImage,
stream->mNextVideoTime + deviation_usec, stream->mNextVideoTime,
stream->mLastVideoImageDisplaySize, &endSegment);
stream->mNextVideoTime += deviation_usec;
MOZ_ASSERT(endSegment.GetDuration() > 0);
if (!isSameOrigin) {
endSegment.ReplaceWithDisabled();
}
mediaStream->AppendToTrack(videoTrackId, &endSegment);
}
mediaStream->EndTrack(videoTrackId);
stream->mHaveSentFinishVideo = true;
}
endPosition = std::max(endPosition,
mediaStream->MicrosecondsToStreamTimeRoundDown(
stream->mNextVideoTime - mStreamStartTime));
}
if (!stream->mHaveSentFinish) {
stream->mStream->AdvanceKnownTracksTime(endPosition);
}
if (finished && !stream->mHaveSentFinish) {
stream->mHaveSentFinish = true;
stream->mStream->Finish();
if (mInfo.HasAudio()) {
CheckedInt64 playedUsecs = mDecodedStream->AudioEndTime(
mStreamStartTime, mInfo.mAudio.mRate);
if (playedUsecs.isValid()) {
OnAudioEndTimeUpdate(playedUsecs.value());
}
}
@ -620,21 +406,8 @@ bool MediaDecoderStateMachine::HaveEnoughDecodedAudio(int64_t aAmpleAudioUSecs)
GetDecodedAudioDuration() < aAmpleAudioUSecs) {
return false;
}
if (!mAudioCaptured) {
return true;
}
DecodedStreamData* stream = GetDecodedStream();
if (stream && stream->mStreamInitialized && !stream->mHaveSentFinishAudio) {
MOZ_ASSERT(mInfo.HasAudio());
TrackID audioTrackId = mInfo.mAudio.mTrackId;
if (!stream->mStream->HaveEnoughBuffered(audioTrackId)) {
return false;
}
}
return true;
return !mAudioCaptured || mDecodedStream->HaveEnoughAudio(mInfo);
}
bool MediaDecoderStateMachine::HaveEnoughDecodedVideo()
@ -646,17 +419,7 @@ bool MediaDecoderStateMachine::HaveEnoughDecodedVideo()
return false;
}
DecodedStreamData* stream = GetDecodedStream();
if (stream && stream->mStreamInitialized && !stream->mHaveSentFinishVideo) {
MOZ_ASSERT(mInfo.HasVideo());
TrackID videoTrackId = mInfo.mVideo.mTrackId;
if (!stream->mStream->HaveEnoughBuffered(videoTrackId)) {
return false;
}
}
return true;
return !mAudioCaptured || mDecodedStream->HaveEnoughVideo(mInfo);
}
bool
@ -1801,9 +1564,7 @@ MediaDecoderStateMachine::InitiateSeek()
mCurrentSeek.mTarget.mTime = seekTime;
if (mAudioCaptured) {
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethodWithArgs<MediaStreamGraph*>(
this, &MediaDecoderStateMachine::RecreateDecodedStream, nullptr);
AbstractThread::MainThread()->Dispatch(r.forget());
mDecodedStream->RecreateData();
}
mDropAudioUntilNextDiscontinuity = HasAudio();
@ -1939,6 +1700,7 @@ MediaDecoderStateMachine::EnsureVideoDecodeTaskQueued()
bool skipToNextKeyFrame = NeedToSkipToNextKeyframe();
int64_t currentTime = mState == DECODER_STATE_SEEKING ? 0 : GetMediaTime();
bool forceDecodeAhead = static_cast<uint32_t>(VideoQueue().GetSize()) <= SCARCE_VIDEO_QUEUE_SIZE;
// Time the video decode, so that if it's slow, we can increase our low
// audio threshold to reduce the chance of an audio underrun while we're
@ -1951,7 +1713,7 @@ MediaDecoderStateMachine::EnsureVideoDecodeTaskQueued()
mVideoDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::RequestVideoData,
skipToNextKeyFrame, currentTime)
skipToNextKeyFrame, currentTime, forceDecodeAhead)
->Then(TaskQueue(), __func__, this,
&MediaDecoderStateMachine::OnVideoDecoded,
&MediaDecoderStateMachine::OnVideoNotDecoded));
@ -2269,7 +2031,7 @@ MediaDecoderStateMachine::DecodeFirstFrame()
mVideoDecodeStartTime = TimeStamp::Now();
mVideoDataRequest.Begin(
ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::RequestVideoData, false, int64_t(0))
&MediaDecoderReader::RequestVideoData, false, int64_t(0), false)
->Then(TaskQueue(), __func__, mStartTimeRendezvous.get(),
&StartTimeRendezvous::ProcessFirstSample<VideoDataPromise>,
&StartTimeRendezvous::FirstSampleRejected<VideoData>)
@ -2623,7 +2385,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
// end of the media, and so that we update the readyState.
if (VideoQueue().GetSize() > 0 ||
(HasAudio() && !mAudioCompleted) ||
(mAudioCaptured && !GetDecodedStream()->IsFinished()))
(mAudioCaptured && !mDecodedStream->IsFinished()))
{
// Start playback if necessary to play the remaining media.
MaybeStartPlayback();
@ -2782,8 +2544,7 @@ int64_t MediaDecoderStateMachine::GetStreamClock() const
{
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
MOZ_ASSERT(mStreamStartTime != -1);
return mStreamStartTime + GetDecodedStream()->GetPosition();
return mStreamStartTime + mDecodedStream->GetPosition();
}
int64_t MediaDecoderStateMachine::GetVideoStreamPosition() const
@ -3167,9 +2928,11 @@ void MediaDecoderStateMachine::SetPlayStartTime(const TimeStamp& aTimeStamp)
if (mAudioSink) {
mAudioSink->SetPlaying(!mPlayStartTime.IsNull());
} else if (mAudioCaptured) {
mDecodedStream.SetPlaying(!mPlayStartTime.IsNull());
}
// Have DecodedStream remember the playing state so it doesn't need to
// ask MDSM about IsPlaying(). Note we have to do this even before capture
// happens since capture could happen in the middle of playback.
mDecodedStream->SetPlaying(!mPlayStartTime.IsNull());
}
void MediaDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder()
@ -3350,11 +3113,6 @@ uint32_t MediaDecoderStateMachine::GetAmpleVideoFrames() const
: std::max<uint32_t>(sVideoQueueDefaultSize, MIN_VIDEO_QUEUE_SIZE);
}
DecodedStreamData* MediaDecoderStateMachine::GetDecodedStream() const
{
return mDecodedStream.GetData();
}
void MediaDecoderStateMachine::DispatchAudioCaptured()
{
nsRefPtr<MediaDecoderStateMachine> self = this;
@ -3365,9 +3123,6 @@ void MediaDecoderStateMachine::DispatchAudioCaptured()
if (!self->mAudioCaptured) {
// Stop the audio sink if it's running.
self->StopAudioThread();
// GetMediaTime() could return -1 because we haven't decoded
// the 1st frame. But this is OK since we will update mStreamStartTime
// again in SetStartTime().
self->mStreamStartTime = self->GetMediaTime();
// Reset mAudioEndTime which will be updated as we send audio data to
// stream. Otherwise it will remain -1 if we don't have audio.
@ -3384,28 +3139,10 @@ void MediaDecoderStateMachine::AddOutputStream(ProcessedMediaStream* aStream,
{
MOZ_ASSERT(NS_IsMainThread());
DECODER_LOG("AddOutputStream aStream=%p!", aStream);
if (!GetDecodedStream()) {
RecreateDecodedStream(aStream->Graph());
}
mDecodedStream.Connect(aStream, aFinishWhenEnded);
mDecodedStream->Connect(aStream, aFinishWhenEnded);
DispatchAudioCaptured();
}
void MediaDecoderStateMachine::RecreateDecodedStream(MediaStreamGraph* aGraph)
{
MOZ_ASSERT(NS_IsMainThread());
mDecodedStream.RecreateData(aGraph);
nsRefPtr<MediaDecoderStateMachine> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self] () -> void
{
ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor());
self->mDecodedStream.SetPlaying(self->IsPlaying());
});
TaskQueue()->Dispatch(r.forget());
}
} // namespace mozilla
// avoid redefined macro in unified build

View File

@ -145,8 +145,6 @@ public:
DECODER_STATE_ERROR
};
DecodedStreamData* GetDecodedStream() const;
void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
// Set/Unset dormant state.
@ -160,11 +158,6 @@ private:
void DispatchAudioCaptured();
// Recreates mDecodedStream. Call this to create mDecodedStream at first,
// and when seeking, to ensure a new stream is set up with fresh buffers.
// Decoder monitor must be held.
void RecreateDecodedStream(MediaStreamGraph* aGraph);
void Shutdown();
public:
@ -320,7 +313,7 @@ public:
if (mReader) {
mReader->BreakCycles();
}
mDecodedStream.DestroyData();
mDecodedStream->DestroyData();
mDecoder = nullptr;
}
@ -635,11 +628,6 @@ protected:
// The decoder monitor must be held.
void CheckIfDecodeComplete();
// Copy audio from an AudioData packet to aOutput. This may require
// inserting silence depending on the timing of the audio packet.
void SendStreamAudio(AudioData* aAudio, DecodedStreamData* aStream,
AudioSegment* aOutput);
// Performs one "cycle" of the state machine. Polls the state, and may send
// a video frame to be displayed, and generally manages the decode. Called
// periodically via timer to ensure the video stays in sync.
@ -1361,7 +1349,7 @@ protected:
// Only written on the main thread while holding the monitor. Therefore it
// can be read on any thread while holding the monitor, or on the main thread
// without holding the monitor.
DecodedStream mDecodedStream;
nsRefPtr<DecodedStream> mDecodedStream;
};
} // namespace mozilla;

View File

@ -521,7 +521,8 @@ MediaFormatReader::ShouldSkip(bool aSkipToNextKeyframe, media::TimeUnit aTimeThr
nsRefPtr<MediaDecoderReader::VideoDataPromise>
MediaFormatReader::RequestVideoData(bool aSkipToNextKeyframe,
int64_t aTimeThreshold)
int64_t aTimeThreshold,
bool aForceDecodeAhead)
{
MOZ_ASSERT(OnTaskQueue());
MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(), "No sample requests allowed while seeking");
@ -553,6 +554,7 @@ MediaFormatReader::RequestVideoData(bool aSkipToNextKeyframe,
MOZ_ASSERT(HasVideo() && mPlatform && mVideo.mDecoder);
mVideo.mForceDecodeAhead = aForceDecodeAhead;
media::TimeUnit timeThreshold{media::TimeUnit::FromMicroseconds(aTimeThreshold)};
if (ShouldSkip(aSkipToNextKeyframe, timeThreshold)) {
Flush(TrackInfo::kVideoTrack);
@ -751,11 +753,12 @@ MediaFormatReader::NeedInput(DecoderData& aDecoder)
// which overrides our "few more samples" threshold.
return
!aDecoder.mError &&
aDecoder.HasPromise() &&
(aDecoder.HasPromise() || aDecoder.mForceDecodeAhead) &&
!aDecoder.mDemuxRequest.Exists() &&
aDecoder.mOutput.IsEmpty() &&
(aDecoder.mInputExhausted || !aDecoder.mQueuedSamples.IsEmpty() ||
aDecoder.mTimeThreshold.isSome() ||
aDecoder.mForceDecodeAhead ||
aDecoder.mNumSamplesInput - aDecoder.mNumSamplesOutput < aDecoder.mDecodeAhead);
}

View File

@ -34,7 +34,7 @@ public:
size_t SizeOfAudioQueueInFrames() override;
nsRefPtr<VideoDataPromise>
RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold) override;
RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold, bool aForceDecodeAhead) override;
nsRefPtr<AudioDataPromise> RequestAudioData() override;
@ -185,6 +185,7 @@ private:
: mOwner(aOwner)
, mType(aType)
, mDecodeAhead(aDecodeAhead)
, mForceDecodeAhead(false)
, mUpdateScheduled(false)
, mDemuxEOS(false)
, mDemuxEOSServiced(false)
@ -215,6 +216,7 @@ private:
// Only accessed from reader's task queue.
uint32_t mDecodeAhead;
bool mForceDecodeAhead;
bool mUpdateScheduled;
bool mDemuxEOS;
bool mDemuxEOSServiced;
@ -266,6 +268,7 @@ private:
void ResetState()
{
MOZ_ASSERT(mOwner->OnTaskQueue());
mForceDecodeAhead = false;
mDemuxEOS = false;
mDemuxEOSServiced = false;
mWaitingForData = false;

View File

@ -910,6 +910,22 @@ protected:
Arg2Type mArg2;
};
template<typename PromiseType, typename ThisType, typename Arg1Type, typename Arg2Type, typename Arg3Type>
class MethodCallWithThreeArgs : public MethodCallBase<PromiseType>
{
public:
typedef nsRefPtr<PromiseType>(ThisType::*Type)(Arg1Type, Arg2Type, Arg3Type);
MethodCallWithThreeArgs(ThisType* aThisVal, Type aMethod, Arg1Type aArg1, Arg2Type aArg2, Arg3Type aArg3)
: mThisVal(aThisVal), mMethod(aMethod), mArg1(aArg1), mArg2(aArg2), mArg3(aArg3) {}
nsRefPtr<PromiseType> Invoke() override { return ((*mThisVal).*mMethod)(mArg1, mArg2, mArg3); }
protected:
nsRefPtr<ThisType> mThisVal;
Type mMethod;
Arg1Type mArg1;
Arg2Type mArg2;
Arg3Type mArg3;
};
template<typename PromiseType>
class ProxyRunnable : public nsRunnable
{
@ -973,6 +989,16 @@ ProxyMediaCall(AbstractThread* aTarget, ThisType* aThisVal, const char* aCallerN
return detail::ProxyInternal(aTarget, methodCall, aCallerName);
}
template<typename PromiseType, typename ThisType, typename Arg1Type, typename Arg2Type, typename Arg3Type>
static nsRefPtr<PromiseType>
ProxyMediaCall(AbstractThread* aTarget, ThisType* aThisVal, const char* aCallerName,
nsRefPtr<PromiseType>(ThisType::*aMethod)(Arg1Type, Arg2Type, Arg3Type), Arg1Type aArg1, Arg2Type aArg2, Arg3Type aArg3)
{
typedef detail::MethodCallWithThreeArgs<PromiseType, ThisType, Arg1Type, Arg2Type, Arg3Type> MethodCallType;
MethodCallType* methodCall = new MethodCallType(aThisVal, aMethod, aArg1, aArg2, aArg3);
return detail::ProxyInternal(aTarget, methodCall, aCallerName);
}
#undef PROMISE_LOG
} // namespace mozilla

View File

@ -606,7 +606,8 @@ MP4Reader::ShouldSkip(bool aSkipToNextKeyframe, int64_t aTimeThreshold)
nsRefPtr<MediaDecoderReader::VideoDataPromise>
MP4Reader::RequestVideoData(bool aSkipToNextKeyframe,
int64_t aTimeThreshold)
int64_t aTimeThreshold,
bool aForceDecodeAhead)
{
MOZ_ASSERT(OnTaskQueue());
VLOG("skip=%d time=%lld", aSkipToNextKeyframe, aTimeThreshold);
@ -624,6 +625,7 @@ MP4Reader::RequestVideoData(bool aSkipToNextKeyframe,
MOZ_ASSERT(HasVideo() && mPlatform && mVideo.mDecoder);
bool eos = false;
mVideo.mForceDecodeAhead = aForceDecodeAhead;
if (ShouldSkip(aSkipToNextKeyframe, aTimeThreshold)) {
uint32_t parsed = 0;
eos = !SkipVideoDemuxToNextKeyFrame(aTimeThreshold, parsed);
@ -695,9 +697,10 @@ MP4Reader::NeedInput(DecoderData& aDecoder)
return
!aDecoder.mError &&
!aDecoder.mDemuxEOS &&
aDecoder.HasPromise() &&
(aDecoder.HasPromise() || aDecoder.mForceDecodeAhead) &&
aDecoder.mOutput.IsEmpty() &&
(aDecoder.mInputExhausted ||
aDecoder.mForceDecodeAhead ||
aDecoder.mNumSamplesInput - aDecoder.mNumSamplesOutput < aDecoder.mDecodeAhead);
}
@ -969,6 +972,7 @@ MP4Reader::Flush(TrackType aTrack)
data.mDecoder->Flush();
{
MonitorAutoLock mon(data.mMonitor);
data.mForceDecodeAhead = false;
data.mIsFlushing = false;
data.mDrainComplete = false;
data.mOutput.Clear();

View File

@ -38,7 +38,7 @@ public:
virtual size_t SizeOfAudioQueueInFrames() override;
virtual nsRefPtr<VideoDataPromise>
RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold) override;
RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold, bool aForceDecodeAhead) override;
virtual nsRefPtr<AudioDataPromise> RequestAudioData() override;
@ -167,6 +167,7 @@ private:
, mNumSamplesInput(0)
, mNumSamplesOutput(0)
, mDecodeAhead(aDecodeAhead)
, mForceDecodeAhead(false)
, mActive(false)
, mInputExhausted(false)
, mError(false)
@ -203,6 +204,7 @@ private:
uint64_t mNumSamplesInput;
uint64_t mNumSamplesOutput;
uint32_t mDecodeAhead;
bool mForceDecodeAhead;
// Whether this stream exists in the media.
bool mActive;
bool mInputExhausted;

View File

@ -45,6 +45,7 @@ MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder)
: MediaDecoderReader(aDecoder)
, mLastAudioTime(0)
, mLastVideoTime(0)
, mForceVideoDecodeAhead(false)
, mOriginalSeekTime(-1)
, mPendingSeekTime(-1)
, mWaitingForSeekData(false)
@ -305,7 +306,9 @@ MediaSourceReader::OnAudioNotDecoded(NotDecodedReason aReason)
}
nsRefPtr<MediaDecoderReader::VideoDataPromise>
MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold)
MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe,
int64_t aTimeThreshold,
bool aForceDecodeAhead)
{
MOZ_ASSERT(OnTaskQueue());
MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(), "No sample requests allowed while seeking");
@ -329,6 +332,7 @@ MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThres
return p;
}
MOZ_DIAGNOSTIC_ASSERT(!mVideoSeekRequest.Exists());
mForceVideoDecodeAhead = aForceDecodeAhead;
SwitchSourceResult ret = SwitchVideoSource(&mLastVideoTime);
switch (ret) {
@ -361,7 +365,9 @@ MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThres
void
MediaSourceReader::DoVideoRequest()
{
mVideoRequest.Begin(GetVideoReader()->RequestVideoData(mDropVideoBeforeThreshold, GetReaderVideoTime(mTimeThreshold))
mVideoRequest.Begin(GetVideoReader()->RequestVideoData(mDropVideoBeforeThreshold,
GetReaderVideoTime(mTimeThreshold),
mForceVideoDecodeAhead)
->Then(TaskQueue(), __func__, this,
&MediaSourceReader::OnVideoDecoded,
&MediaSourceReader::OnVideoNotDecoded));
@ -885,6 +891,9 @@ MediaSourceReader::ResetDecode()
mWaitingForSeekData = false;
mPendingSeekTime = -1;
// Reset force video decode ahead.
mForceVideoDecodeAhead = false;
// Reset all the readers.
if (GetAudioReader()) {
GetAudioReader()->ResetDecode();

View File

@ -49,7 +49,7 @@ public:
nsRefPtr<AudioDataPromise> RequestAudioData() override;
nsRefPtr<VideoDataPromise>
RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold) override;
RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold, bool aForceDecodeAhead) override;
virtual size_t SizeOfVideoQueueInFrames() override;
virtual size_t SizeOfAudioQueueInFrames() override;
@ -255,6 +255,8 @@ private:
int64_t mLastAudioTime;
int64_t mLastVideoTime;
bool mForceVideoDecodeAhead;
MediaPromiseRequestHolder<SeekPromise> mAudioSeekRequest;
MediaPromiseRequestHolder<SeekPromise> mVideoSeekRequest;
MediaPromiseHolder<SeekPromise> mSeekPromise;

View File

@ -65,7 +65,6 @@ if CONFIG['MOZ_WEBRTC']:
if CONFIG['MOZ_OMX_DECODER']:
DIRS += ['omx']
DIRS += ['omx/mediaresourcemanager']
if CONFIG['MOZ_EME']:
DIRS += ['eme']

View File

@ -99,36 +99,40 @@ MediaCodecProxy::MediaCodecProxy(sp<ALooper> aLooper,
, mPendingRequestMediaResource(false)
{
MOZ_ASSERT(mCodecLooper != nullptr, "ALooper should not be nullptr.");
mResourceHandler = new MediaResourceHandler(this);
}
MediaCodecProxy::~MediaCodecProxy()
{
releaseCodec();
SetMediaCodecFree();
ReleaseMediaCodec();
}
bool
MediaCodecProxy::AskMediaCodecAndWait()
{
if (mResourceHandler == nullptr) {
if (mResourceClient || mCodec.get()) {
return false;
}
if (strncasecmp(mCodecMime.get(), "video/", 6) == 0) {
mResourceHandler->requestResource(mCodecEncoder
? IMediaResourceManagerService::HW_VIDEO_ENCODER
: IMediaResourceManagerService::HW_VIDEO_DECODER);
mozilla::MediaSystemResourceType type =
mCodecEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
mozilla::MediaSystemResourceType::VIDEO_DECODER;
mResourceClient = new mozilla::MediaSystemResourceClient(type);
mResourceClient->SetListener(this);
} else if (strncasecmp(mCodecMime.get(), "audio/", 6) == 0) {
if (allocateCodec()) {
return true;
}
} else {
}
if (!mResourceClient) {
return false;
}
mozilla::MonitorAutoLock mon(mMediaCodecLock);
mPendingRequestMediaResource = true;
// request video codec
mResourceClient->Acquire();
while (mPendingRequestMediaResource) {
mMediaCodecLock.Wait();
@ -141,21 +145,30 @@ MediaCodecProxy::AskMediaCodecAndWait()
bool
MediaCodecProxy::AsyncAskMediaCodec()
{
if ((strncasecmp(mCodecMime.get(), "video/", 6) != 0) ||
(mResourceHandler == nullptr)) {
if (mResourceClient || mCodec.get()) {
return false;
}
if (strncasecmp(mCodecMime.get(), "video/", 6) != 0) {
return false;
}
// request video codec
mResourceHandler->requestResource(mCodecEncoder
? IMediaResourceManagerService::HW_VIDEO_ENCODER
: IMediaResourceManagerService::HW_VIDEO_DECODER);
mozilla::MediaSystemResourceType type =
mCodecEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
mozilla::MediaSystemResourceType::VIDEO_DECODER;
mResourceClient = new mozilla::MediaSystemResourceClient(type);
mResourceClient->SetListener(this);
mResourceClient->Acquire();
return true;
}
void
MediaCodecProxy::SetMediaCodecFree()
MediaCodecProxy::ReleaseMediaCodec()
{
if (mResourceHandler == nullptr) {
releaseCodec();
if (!mResourceClient) {
return;
}
@ -165,8 +178,10 @@ MediaCodecProxy::SetMediaCodecFree()
mon.NotifyAll();
}
mResourceHandler->cancelResource();
mResourceHandler = nullptr;
if (mResourceClient) {
mResourceClient->ReleaseResource();
mResourceClient = nullptr;
}
}
bool
@ -477,15 +492,14 @@ MediaCodecProxy::getCapability(uint32_t *aCapability)
return OK;
}
// Called on a Binder thread
// Called on ImageBridge thread
void
MediaCodecProxy::resourceReserved()
MediaCodecProxy::ResourceReserved()
{
MCP_LOG("resourceReserved");
// Create MediaCodec
releaseCodec();
if (!allocateCodec()) {
SetMediaCodecFree();
ReleaseMediaCodec();
// Notification
sp<CodecResourceListener> listener = mListener.promote();
if (listener != nullptr) {
@ -506,10 +520,11 @@ MediaCodecProxy::resourceReserved()
}
}
// Called on ImageBridge thread
void
MediaCodecProxy::resourceCanceled()
MediaCodecProxy::ResourceReserveFailed()
{
SetMediaCodecFree();
ReleaseMediaCodec();
// Notification
sp<CodecResourceListener> listener = mListener.promote();
if (listener != nullptr) {
@ -640,8 +655,7 @@ status_t MediaCodecProxy::Output(MediaBuffer** aBuffer, int64_t aTimeoutUs)
void MediaCodecProxy::ReleaseMediaResources()
{
releaseCodec();
SetMediaCodecFree();
ReleaseMediaCodec();
}
void MediaCodecProxy::ReleaseMediaBuffer(MediaBuffer* aBuffer) {

View File

@ -11,8 +11,10 @@
#include <stagefright/MediaCodec.h>
#include <stagefright/MediaBuffer.h>
#include <utils/threads.h>
#include "MediaResourceHandler.h"
#include "mozilla/media/MediaSystemResourceClient.h"
#include "mozilla/Monitor.h"
#include "nsRefPtr.h"
namespace android {
// This class is intended to be a proxy for MediaCodec with codec resource
@ -21,7 +23,8 @@ namespace android {
// MediaCodecReader.cpp. Another useage is to use configure(), Prepare(),
// Input(), and Output(). It is used in GonkVideoDecoderManager.cpp which
// doesn't need to handle the buffers for codec.
class MediaCodecProxy : public MediaResourceHandler::ResourceListener
class MediaCodecProxy : public RefBase
, public mozilla::MediaSystemResourceReservationListener
{
public:
/* Codec resource notification listener.
@ -137,6 +140,7 @@ public:
// It asks for the OMX codec and blocked until the resource is grant to be
// allocated.
// Audio codec allocation should use this.
bool AskMediaCodecAndWait();
// It asks for the OMX codec asynchronously.
@ -144,15 +148,14 @@ public:
bool AsyncAskMediaCodec();
// Free the OMX codec so others can allocate it.
void SetMediaCodecFree();
void ReleaseMediaCodec();
protected:
virtual ~MediaCodecProxy();
// MediaResourceHandler::EventListener::resourceReserved()
virtual void resourceReserved();
// MediaResourceHandler::EventListener::resourceCanceled()
virtual void resourceCanceled();
// MediaResourceReservationListener
void ResourceReserved() override;
void ResourceReserveFailed() override;
private:
// Forbidden
@ -180,7 +183,7 @@ private:
wp<CodecResourceListener> mListener;
// Media Resource Management
sp<MediaResourceHandler> mResourceHandler;
nsRefPtr<mozilla::MediaSystemResourceClient> mResourceClient;
// MediaCodec instance
mutable RWLock mCodecLock;

View File

@ -353,7 +353,8 @@ MediaCodecReader::RequestAudioData()
nsRefPtr<MediaDecoderReader::VideoDataPromise>
MediaCodecReader::RequestVideoData(bool aSkipToNextKeyframe,
int64_t aTimeThreshold)
int64_t aTimeThreshold,
bool aForceDecodeAhead)
{
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(HasVideo());

View File

@ -83,7 +83,8 @@ public:
// Disptach a DecodeVideoFrameTask to decode video data.
virtual nsRefPtr<VideoDataPromise>
RequestVideoData(bool aSkipToNextKeyframe,
int64_t aTimeThreshold) override;
int64_t aTimeThreshold,
bool aForceDecodeAhead) override;
// Disptach a DecodeAduioDataTask to decode video data.
virtual nsRefPtr<AudioDataPromise> RequestAudioData() override;

View File

@ -28,6 +28,7 @@ MediaOmxCommonDecoder::MediaOmxCommonDecoder()
, mReader(nullptr)
, mCanOffloadAudio(false)
, mFallbackToStateMachine(false)
, mIsCaptured(false)
{
mDormantSupported = true;
if (!gMediaDecoderLog) {
@ -48,8 +49,7 @@ bool
MediaOmxCommonDecoder::CheckDecoderCanOffloadAudio()
{
return (mCanOffloadAudio && !mFallbackToStateMachine &&
!(GetStateMachine() && GetStateMachine()->GetDecodedStream()) &&
mPlaybackRate == 1.0);
!mIsCaptured && mPlaybackRate == 1.0);
}
void
@ -183,6 +183,8 @@ MediaOmxCommonDecoder::AddOutputStream(ProcessedMediaStream* aStream,
{
MOZ_ASSERT(NS_IsMainThread());
mIsCaptured = true;
if (mAudioOffloadPlayer) {
ResumeStateMachine();
}

View File

@ -64,6 +64,9 @@ protected:
// Set when offload playback of current track fails in the middle and need to
// fallback to state machine
bool mFallbackToStateMachine;
// True if the media element is captured.
bool mIsCaptured;
};
} // namespace mozilla

View File

@ -16,8 +16,6 @@
#include "nsDebug.h"
#include "IMediaResourceManagerService.h"
#include "OMXCodecProxy.h"
namespace android {
@ -60,13 +58,13 @@ OMXCodecProxy::OMXCodecProxy(
mFlags(flags),
mNativeWindow(nativeWindow),
mSource(source),
mState(MediaResourceManagerClient::CLIENT_STATE_WAIT_FOR_RESOURCE)
mState(ResourceState::START)
{
}
OMXCodecProxy::~OMXCodecProxy()
{
mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
mState = ResourceState::END;
if (mOMXCodec.get()) {
wp<MediaSource> tmp = mOMXCodec;
@ -79,8 +77,9 @@ OMXCodecProxy::~OMXCodecProxy()
// Complete all pending Binder ipc transactions
IPCThreadState::self()->flushCommands();
if (mManagerService.get() && mClient.get()) {
mManagerService->cancelClient(mClient, IMediaResourceManagerService::HW_VIDEO_DECODER);
if (mResourceClient) {
mResourceClient->ReleaseResource();
mResourceClient = nullptr;
}
mSource.clear();
@ -88,12 +87,6 @@ OMXCodecProxy::~OMXCodecProxy()
mComponentName = nullptr;
}
MediaResourceManagerClient::State OMXCodecProxy::getState()
{
Mutex::Autolock autoLock(mLock);
return mState;
}
void OMXCodecProxy::setListener(const wp<CodecResourceListener>& listener)
{
Mutex::Autolock autoLock(mLock);
@ -120,39 +113,31 @@ void OMXCodecProxy::requestResource()
{
Mutex::Autolock autoLock(mLock);
if (mClient.get()) {
if (mResourceClient) {
return;
}
sp<MediaResourceManagerClient::EventListener> listener = this;
mClient = new MediaResourceManagerClient(listener);
mState = ResourceState::WAITING;
mManagerService = mClient->getMediaResourceManagerService();
if (!mManagerService.get()) {
mClient = nullptr;
return;
}
mManagerService->requestMediaResource(mClient, IMediaResourceManagerService::HW_VIDEO_DECODER, true /* will wait */);
mozilla::MediaSystemResourceType type = mIsEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
mozilla::MediaSystemResourceType::VIDEO_DECODER;
mResourceClient = new mozilla::MediaSystemResourceClient(type);
mResourceClient->SetListener(this);
mResourceClient->Acquire();
}
// called on Binder ipc thread
void OMXCodecProxy::statusChanged(int event)
// Called on ImageBridge thread
void
OMXCodecProxy::ResourceReserved()
{
Mutex::Autolock autoLock(mLock);
if (mState != MediaResourceManagerClient::CLIENT_STATE_WAIT_FOR_RESOURCE) {
return;
}
mState = (MediaResourceManagerClient::State) event;
if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
notifyResourceCanceled();
if (mState != ResourceState::WAITING) {
return;
}
const char *mime;
if (!mSrcMeta->findCString(kKeyMIMEType, &mime)) {
mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
mState = ResourceState::END;
notifyResourceCanceled();
return;
}
@ -161,7 +146,7 @@ void OMXCodecProxy::statusChanged(int event)
sp<MediaSource> codec;
mOMXCodec = OMXCodec::Create(mOMX, mSrcMeta, mIsEncoder, mSource, mComponentName, mFlags, mNativeWindow);
if (mOMXCodec == nullptr) {
mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
mState = ResourceState::END;
notifyResourceCanceled();
return;
}
@ -182,7 +167,7 @@ void OMXCodecProxy::statusChanged(int event)
printf_stderr("Failed to get video size, or it was too large for HW decoder (<w=%d, h=%d> but <maxW=%d, maxH=%d>)",
width, height, maxWidth, maxHeight);
mOMXCodec.clear();
mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
mState = ResourceState::END;
notifyResourceCanceled();
return;
}
@ -190,19 +175,29 @@ void OMXCodecProxy::statusChanged(int event)
if (mOMXCodec->start() != OK) {
NS_WARNING("Couldn't start OMX video source");
mOMXCodec.clear();
mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
mState = ResourceState::END;
notifyResourceCanceled();
return;
}
}
mState = ResourceState::ACQUIRED;
notifyResourceReserved();
}
// Called on ImageBridge thread
void
OMXCodecProxy::ResourceReserveFailed()
{
Mutex::Autolock autoLock(mLock);
mState = ResourceState::NOT_ACQUIRED;
}
status_t OMXCodecProxy::start(MetaData *params)
{
Mutex::Autolock autoLock(mLock);
if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
if (mState != ResourceState::ACQUIRED) {
return NO_INIT;
}
CHECK(mOMXCodec.get() != nullptr);
@ -213,7 +208,7 @@ status_t OMXCodecProxy::stop()
{
Mutex::Autolock autoLock(mLock);
if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
if (mState != ResourceState::ACQUIRED) {
return NO_INIT;
}
CHECK(mOMXCodec.get() != nullptr);
@ -224,7 +219,7 @@ sp<MetaData> OMXCodecProxy::getFormat()
{
Mutex::Autolock autoLock(mLock);
if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
if (mState != ResourceState::ACQUIRED) {
sp<MetaData> meta = new MetaData;
return meta;
}
@ -236,7 +231,7 @@ status_t OMXCodecProxy::read(MediaBuffer **buffer, const ReadOptions *options)
{
Mutex::Autolock autoLock(mLock);
if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
if (mState != ResourceState::ACQUIRED) {
return NO_INIT;
}
CHECK(mOMXCodec.get() != nullptr);
@ -247,7 +242,7 @@ status_t OMXCodecProxy::pause()
{
Mutex::Autolock autoLock(mLock);
if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
if (mState != ResourceState::ACQUIRED) {
return NO_INIT;
}
CHECK(mOMXCodec.get() != nullptr);

View File

@ -13,14 +13,15 @@
#include <stagefright/MediaSource.h>
#include <utils/threads.h>
#include "MediaResourceManagerClient.h"
#include "mozilla/media/MediaSystemResourceClient.h"
#include "nsRefPtr.h"
namespace android {
struct MetaData;
class OMXCodecProxy : public MediaSource,
public MediaResourceManagerClient::EventListener
class OMXCodecProxy : public MediaSource
, public mozilla::MediaSystemResourceReservationListener
{
public:
/* Codec resource notification listener.
@ -38,6 +39,15 @@ public:
virtual void codecCanceled() = 0;
};
// Enumeration for the valid resource allcoation states
enum class ResourceState : int8_t {
START,
WAITING,
ACQUIRED,
NOT_ACQUIRED,
END
};
static sp<OMXCodecProxy> Create(
const sp<IOMX> &omx,
const sp<MetaData> &meta, bool createEncoder,
@ -46,14 +56,13 @@ public:
uint32_t flags = 0,
const sp<ANativeWindow> &nativeWindow = nullptr);
MediaResourceManagerClient::State getState();
void setListener(const wp<CodecResourceListener>& listener);
void requestResource();
// MediaResourceManagerClient::EventListener
virtual void statusChanged(int event);
// MediaSystemResourceReservationListener
void ResourceReserved() override;
void ResourceReserveFailed() override;
// MediaSource
virtual status_t start(MetaData *params = nullptr);
@ -100,10 +109,10 @@ private:
sp<MediaSource> mSource;
sp<MediaSource> mOMXCodec;
sp<MediaResourceManagerClient> mClient;
MediaResourceManagerClient::State mState;
sp<IMediaResourceManagerService> mManagerService;
nsRefPtr<mozilla::MediaSystemResourceClient> mResourceClient;
ResourceState mState;
// Codec Resource Notification Listener
wp<CodecResourceListener> mListener;
};

View File

@ -17,7 +17,7 @@
#include "AudioChannelFormat.h"
#include "GrallocImages.h"
#include <mozilla/Monitor.h>
#include "mozilla/Monitor.h"
#include "mozilla/layers/GrallocTextureClient.h"
using namespace mozilla;
@ -45,27 +45,21 @@ enum BufferState
bool
OMXCodecReservation::ReserveOMXCodec()
{
if (!mManagerService.get()) {
sp<MediaResourceManagerClient::EventListener> listener = this;
mClient = new MediaResourceManagerClient(listener);
mManagerService = mClient->getMediaResourceManagerService();
if (!mManagerService.get()) {
mClient = nullptr;
return true; // not really in use, but not usable
}
if (mClient) {
// Already tried reservation.
return false;
}
return (mManagerService->requestMediaResource(mClient, mType, false) == OK); // don't wait
mClient = new mozilla::MediaSystemResourceClient(mType);
return mClient->AcquireSyncNoWait(); // don't wait if resrouce is not available
}
void
OMXCodecReservation::ReleaseOMXCodec()
{
if (!mManagerService.get() || !mClient.get()) {
if (!mClient) {
return;
}
mManagerService->cancelClient(mClient, mType);
mClient->ReleaseResource();
}
OMXAudioEncoder*

View File

@ -15,22 +15,21 @@
#include "AudioSegment.h"
#include "GonkNativeWindow.h"
#include "GonkNativeWindowClient.h"
#include "IMediaResourceManagerService.h"
#include "MediaResourceManagerClient.h"
#include "mozilla/media/MediaSystemResourceClient.h"
#include "nsRefPtr.h"
#include <speex/speex_resampler.h>
namespace android {
// Wrapper class for managing HW codec reservations
class OMXCodecReservation : public MediaResourceManagerClient::EventListener
class OMXCodecReservation : public RefBase
{
public:
OMXCodecReservation(bool aEncoder)
{
mType = aEncoder ? IMediaResourceManagerService::HW_VIDEO_ENCODER :
IMediaResourceManagerService::HW_VIDEO_DECODER;
mType = aEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
mozilla::MediaSystemResourceType::VIDEO_DECODER;
}
virtual ~OMXCodecReservation()
@ -44,14 +43,10 @@ public:
/** Release the Encode or Decode resource for this instance */
virtual void ReleaseOMXCodec();
// MediaResourceManagerClient::EventListener
virtual void statusChanged(int event) {}
private:
IMediaResourceManagerService::ResourceType mType;
mozilla::MediaSystemResourceType mType;
sp<MediaResourceManagerClient> mClient;
sp<IMediaResourceManagerService> mManagerService;
nsRefPtr<mozilla::MediaSystemResourceClient> mClient;
};

View File

@ -82,10 +82,13 @@ RtspMediaCodecReader::RequestAudioData()
nsRefPtr<MediaDecoderReader::VideoDataPromise>
RtspMediaCodecReader::RequestVideoData(bool aSkipToNextKeyframe,
int64_t aTimeThreshold)
int64_t aTimeThreshold,
bool aForceDecodeAhead)
{
EnsureActive();
return MediaCodecReader::RequestVideoData(aSkipToNextKeyframe, aTimeThreshold);
return MediaCodecReader::RequestVideoData(aSkipToNextKeyframe,
aTimeThreshold,
aForceDecodeAhead);
}
nsRefPtr<MediaDecoderReader::MetadataPromise>

View File

@ -53,7 +53,8 @@ public:
// Disptach a DecodeVideoFrameTask to decode video data.
virtual nsRefPtr<VideoDataPromise>
RequestVideoData(bool aSkipToNextKeyframe,
int64_t aTimeThreshold) override;
int64_t aTimeThreshold,
bool aForceDecodeAhead) override;
// Disptach a DecodeAudioDataTask to decode audio data.
virtual nsRefPtr<AudioDataPromise> RequestAudioData() override;

View File

@ -1,62 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
//#define LOG_NDEBUG 0
#define LOG_TAG "IMediaResourceManagerClient"
#include <utils/Log.h>
#include <stdint.h>
#include <sys/types.h>
#include <binder/Parcel.h>
#include "IMediaResourceManagerClient.h"
namespace android {
enum {
STATUS_CHANGED = IBinder::FIRST_CALL_TRANSACTION
};
class BpMediaResourceManagerClient : public BpInterface<IMediaResourceManagerClient>
{
public:
BpMediaResourceManagerClient(const sp<IBinder>& impl)
: BpInterface<IMediaResourceManagerClient>(impl)
{
}
void statusChanged(int event)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaResourceManagerClient::getInterfaceDescriptor());
data.writeInt32(event);
remote()->transact(STATUS_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
}
};
IMPLEMENT_META_INTERFACE(MediaResourceManagerClient, "android.media.IMediaResourceManagerClient");
// ----------------------------------------------------------------------
status_t BnMediaResourceManagerClient::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case STATUS_CHANGED: {
CHECK_INTERFACE(IMediaResourceManagerClient, data, reply);
int event = data.readInt32();
statusChanged(event);
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
// ----------------------------------------------------------------------------
}; // namespace android

View File

@ -1,43 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 ANDROID_IMEDIARESOURCEMANAGERCLIENT_H
#define ANDROID_IMEDIARESOURCEMANAGERCLIENT_H
#include <utils/RefBase.h>
#include <binder/IInterface.h>
namespace android {
// ----------------------------------------------------------------------------
class IMediaResourceManagerClient : public IInterface
{
public:
DECLARE_META_INTERFACE(MediaResourceManagerClient);
// Notifies a change of media resource request status.
virtual void statusChanged(int event) = 0;
};
// ----------------------------------------------------------------------------
class BnMediaResourceManagerClient : public BnInterface<IMediaResourceManagerClient>
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};
// ----------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_IMEDIARESOURCEMANAGERCLIENT_H

View File

@ -1,118 +0,0 @@
/*
** Copyright 2010, The Android Open Source Project
** Copyright 2013, Mozilla Foundation
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "IMediaResourceManagerDeathNotifier"
#include <utils/Log.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include "IMediaResourceManagerDeathNotifier.h"
#define DN_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
#define DN_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define DN_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define DN_LOGE_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
namespace android {
// client singleton for binder interface to services
Mutex IMediaResourceManagerDeathNotifier::sServiceLock;
sp<IMediaResourceManagerService> IMediaResourceManagerDeathNotifier::sMediaResourceManagerService;
sp<IMediaResourceManagerDeathNotifier::DeathNotifier> IMediaResourceManagerDeathNotifier::sDeathNotifier;
SortedVector< wp<IMediaResourceManagerDeathNotifier> > IMediaResourceManagerDeathNotifier::sObitRecipients;
// establish binder interface to MediaResourceManagerService
/*static*/const sp<IMediaResourceManagerService>&
IMediaResourceManagerDeathNotifier::getMediaResourceManagerService()
{
DN_LOGV("getMediaResourceManagerService");
Mutex::Autolock _l(sServiceLock);
if (sMediaResourceManagerService.get() == 0) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16("media.resource_manager"));
if (binder != 0) {
break;
}
DN_LOGW("Media resource manager service not published, waiting...");
usleep(500000); // 0.5 s
} while(true);
if (sDeathNotifier == NULL) {
sDeathNotifier = new DeathNotifier();
}
binder->linkToDeath(sDeathNotifier);
sMediaResourceManagerService = interface_cast<IMediaResourceManagerService>(binder);
}
DN_LOGE_IF(sMediaResourceManagerService == 0, "no media player service!?");
return sMediaResourceManagerService;
}
/*static*/ void
IMediaResourceManagerDeathNotifier::addObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient)
{
Mutex::Autolock _l(sServiceLock);
sObitRecipients.add(recipient);
}
/*static*/ void
IMediaResourceManagerDeathNotifier::removeObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient)
{
Mutex::Autolock _l(sServiceLock);
sObitRecipients.remove(recipient);
}
void
IMediaResourceManagerDeathNotifier::DeathNotifier::binderDied(const wp<IBinder>& who)
{
DN_LOGW("media resource manager service died");
// Need to do this with the lock held
SortedVector< wp<IMediaResourceManagerDeathNotifier> > list;
{
Mutex::Autolock _l(sServiceLock);
sMediaResourceManagerService.clear();
list = sObitRecipients;
}
// Notify application when media server dies.
// Don't hold the static lock during callback in case app
// makes a call that needs the lock.
size_t count = list.size();
for (size_t iter = 0; iter < count; ++iter) {
sp<IMediaResourceManagerDeathNotifier> notifier = list[iter].promote();
if (notifier != 0) {
notifier->died();
}
}
}
IMediaResourceManagerDeathNotifier::DeathNotifier::~DeathNotifier()
{
Mutex::Autolock _l(sServiceLock);
sObitRecipients.clear();
if (sMediaResourceManagerService != 0) {
sMediaResourceManagerService->asBinder()->unlinkToDeath(this);
}
}
}; // namespace android

View File

@ -1,67 +0,0 @@
/*
** Copyright 2010, The Android Open Source Project
** Copyright 2013, Mozilla Foundation
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#ifndef ANDROID_IMEDIARESOURCEMANAGERDEATHNOTIFIER_H
#define ANDROID_IMEDIARESOURCEMANAGERDEATHNOTIFIER_H
#include <utils/threads.h>
#include <utils/SortedVector.h>
#include "IMediaResourceManagerService.h"
namespace android {
/**
* Handle MediaResourceManagerService's death notification.
* Made from android's IMediaDeathNotifier class.
*/
class IMediaResourceManagerDeathNotifier: virtual public RefBase
{
public:
IMediaResourceManagerDeathNotifier() { addObitRecipient(this); }
virtual ~IMediaResourceManagerDeathNotifier() { removeObitRecipient(this); }
virtual void died() = 0;
static const sp<IMediaResourceManagerService>& getMediaResourceManagerService();
private:
IMediaResourceManagerDeathNotifier &operator=(const IMediaResourceManagerDeathNotifier &);
IMediaResourceManagerDeathNotifier(const IMediaResourceManagerDeathNotifier &);
static void addObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient);
static void removeObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient);
class DeathNotifier: public IBinder::DeathRecipient
{
public:
DeathNotifier() {}
virtual ~DeathNotifier();
virtual void binderDied(const wp<IBinder>& who);
};
friend class DeathNotifier;
static Mutex sServiceLock;
static sp<IMediaResourceManagerService> sMediaResourceManagerService;
static sp<DeathNotifier> sDeathNotifier;
static SortedVector< wp<IMediaResourceManagerDeathNotifier> > sObitRecipients;
};
}; // namespace android
#endif // ANDROID_IMEDIARESOURCEMANAGERDEATHNOTIFIER_H

View File

@ -1,92 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
//#define LOG_NDEBUG 0
#define LOG_TAG "IMediaResourceManagerService"
#include <stdint.h>
#include <sys/types.h>
#include <binder/Parcel.h>
#include <utils/Log.h>
#include "IMediaResourceManagerService.h"
namespace android {
/**
* Function ID used between BpMediaResourceManagerService and
* BnMediaResourceManagerService by using Binder ipc.
*/
enum {
REQUEST_MEDIA_RESOURCE = IBinder::FIRST_CALL_TRANSACTION,
DEREGISTER_CLIENT
};
class BpMediaResourceManagerService : public BpInterface<IMediaResourceManagerService>
{
public:
BpMediaResourceManagerService(const sp<IBinder>& impl)
: BpInterface<IMediaResourceManagerService>(impl)
{
}
virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType, bool willWait)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaResourceManagerService::getInterfaceDescriptor());
data.writeStrongBinder(client->asBinder());
data.writeInt32(resourceType);
data.writeInt32(willWait ? 1 : 0);
remote()->transact(REQUEST_MEDIA_RESOURCE, data, &reply);
return reply.readInt32();
}
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client, int resourceType)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaResourceManagerService::getInterfaceDescriptor());
data.writeStrongBinder(client->asBinder());
data.writeInt32(resourceType);
remote()->transact(DEREGISTER_CLIENT, data, &reply);
return reply.readInt32();
}
};
IMPLEMENT_META_INTERFACE(MediaResourceManagerService, "android.media.IMediaResourceManagerService");
// ----------------------------------------------------------------------
status_t BnMediaResourceManagerService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case REQUEST_MEDIA_RESOURCE: {
CHECK_INTERFACE(IMediaResourceManagerService, data, reply);
sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(data.readStrongBinder());
int resourceType = data.readInt32();
bool willWait = (data.readInt32() == 1);
status_t result = requestMediaResource(client, resourceType, willWait);
reply->writeInt32(result);
return NO_ERROR;
} break;
case DEREGISTER_CLIENT: {
CHECK_INTERFACE(IMediaResourceManagerService, data, reply);
sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(data.readStrongBinder());
int resourceType = data.readInt32();
status_t result = cancelClient(client, resourceType);
reply->writeInt32(result);
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
// ----------------------------------------------------------------------------
}; // namespace android

View File

@ -1,74 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 ANDROID_IMEDIARESOURCEMANAGERSERVICE_H
#define ANDROID_IMEDIARESOURCEMANAGERSERVICE_H
#include <utils/RefBase.h>
#include <binder/IInterface.h>
#include "IMediaResourceManagerClient.h"
namespace android {
// ----------------------------------------------------------------------------
class IMediaResourceManagerService : public IInterface
{
public:
DECLARE_META_INTERFACE(MediaResourceManagerService);
// Enumeration for the resource types
enum ResourceType {
HW_VIDEO_DECODER = 0,
HW_AUDIO_DECODER, // Not supported currently.
HW_VIDEO_ENCODER,
HW_AUDIO_ENCODER, // Not supported currently.
HW_CAMERA, // Not supported currently.
NUM_OF_RESOURCE_TYPES,
INVALID_RESOURCE_TYPE = -1
};
enum ErrorCode {
RESOURCE_NOT_AVAILABLE = -EAGAIN
};
// Request a media resource for IMediaResourceManagerClient.
// client is the binder that service will notify (through
// IMediaResourceManagerClient::statusChanged()) when request status changed.
// resourceType is type of resource that client would like to request.
// willWait indicates that, when the resource is not currently available
// (i.e., already in use by another client), if the client wants to wait. If
// true, client will be put into a (FIFO) waiting list and be notified when
// resource is available.
// For unsupported types, this function returns BAD_TYPE. For supported
// types, it always returns OK when willWait is true; otherwise it will
// return true when resouce is available, or RESOURCE_NOT_AVAILABLE when
// resouce is in use.
virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType, bool willWait) = 0;
// Cancel a media resource request and a resource allocated to IMediaResourceManagerClient.
// Client must call this function after it's done with the media resource requested.
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client, int resourceType) = 0;
};
// ----------------------------------------------------------------------------
class BnMediaResourceManagerService : public BnInterface<IMediaResourceManagerService>
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};
// ----------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_IMEDIARESOURCEMANAGERSERVICE_H

View File

@ -1,95 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "MediaResourceHandler.h"
namespace android {
MediaResourceHandler::MediaResourceHandler(const wp<ResourceListener> &aListener)
: mListener(aListener)
, mType(IMediaResourceManagerService::INVALID_RESOURCE_TYPE)
, mWaitingResource(false)
{
}
MediaResourceHandler::~MediaResourceHandler()
{
cancelResource();
}
bool
MediaResourceHandler::IsWaitingResource()
{
Mutex::Autolock al(mLock);
return mWaitingResource;
}
bool
MediaResourceHandler::requestResource(IMediaResourceManagerService::ResourceType aType)
{
Mutex::Autolock al(mLock);
if (mClient != nullptr && mService != nullptr) {
return false;
}
sp<MediaResourceManagerClient> client = new MediaResourceManagerClient(this);
sp<IMediaResourceManagerService> service = client->getMediaResourceManagerService();
if (service == nullptr) {
return false;
}
if (service->requestMediaResource(client, (int)aType, true) != OK) {
return false;
}
mClient = client;
mService = service;
mType = aType;
mWaitingResource = true;
return true;
}
void
MediaResourceHandler::cancelResource()
{
Mutex::Autolock al(mLock);
if (mClient != nullptr && mService != nullptr) {
mService->cancelClient(mClient, (int)mType);
}
mWaitingResource = false;
mClient = nullptr;
mService = nullptr;
}
// Called on a Binder thread
void
MediaResourceHandler::statusChanged(int aEvent)
{
sp<ResourceListener> listener;
Mutex::Autolock autoLock(mLock);
listener = mListener.promote();
if (listener == nullptr) {
return;
}
mWaitingResource = false;
MediaResourceManagerClient::State state = (MediaResourceManagerClient::State)aEvent;
if (state == MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
listener->resourceReserved();
} else {
listener->resourceCanceled();
}
}
} // namespace android

View File

@ -1,71 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 MEDIA_RESOURCE_HANDLER_H
#define MEDIA_RESOURCE_HANDLER_H
#include <utils/threads.h>
#include <mozilla/Attributes.h>
#include "MediaResourceManagerClient.h"
namespace android {
class MediaResourceHandler : public MediaResourceManagerClient::EventListener
{
public:
/* Resource notification listener.
* All functions are called on the Binder thread.
*/
struct ResourceListener : public virtual RefBase {
/* The resource is reserved and can be granted.
* The client can allocate the requested resource.
*/
virtual void resourceReserved() = 0;
/* The resource is not reserved any more.
* The client should release the resource as soon as possible if the
* resource is still being held.
*/
virtual void resourceCanceled() = 0;
};
MediaResourceHandler(const wp<ResourceListener> &aListener);
virtual ~MediaResourceHandler();
// Request Resource
bool requestResource(IMediaResourceManagerService::ResourceType aType);
// Cancel Resource
void cancelResource();
bool IsWaitingResource();
protected:
// MediaResourceManagerClient::EventListener::statusChanged()
virtual void statusChanged(int event);
private:
// Forbidden
MediaResourceHandler() = delete;
MediaResourceHandler(const MediaResourceHandler &) = delete;
const MediaResourceHandler &operator=(const MediaResourceHandler &) = delete;
// Resource Notification Listener
wp<ResourceListener> mListener;
// Resource Management
Mutex mLock;
sp<IMediaResourceManagerClient> mClient;
sp<IMediaResourceManagerService> mService;
IMediaResourceManagerService::ResourceType mType;
bool mWaitingResource;
};
} // namespace android
#endif // MEDIA_RESOURCE_HANDLER_H

View File

@ -1,40 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaResourceManagerClient"
#include <utils/Log.h>
#include "MediaResourceManagerClient.h"
namespace android {
MediaResourceManagerClient::MediaResourceManagerClient(const wp<EventListener>& listener)
: mEventListener(listener)
{
}
void MediaResourceManagerClient::statusChanged(int event)
{
if (mEventListener != NULL) {
sp<EventListener> listener = mEventListener.promote();
if (listener != NULL) {
listener->statusChanged(event);
}
}
}
void MediaResourceManagerClient::died()
{
sp<EventListener> listener = mEventListener.promote();
if (listener != NULL) {
listener->statusChanged(CLIENT_STATE_SHUTDOWN);
}
}
}; // namespace android

View File

@ -1,45 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 ANDROID_MEDIARESOURCEMANAGERCLIENT_H
#define ANDROID_MEDIARESOURCEMANAGERCLIENT_H
#include "IMediaResourceManagerClient.h"
#include "IMediaResourceManagerDeathNotifier.h"
namespace android {
class MediaResourceManagerClient: public BnMediaResourceManagerClient,
public virtual IMediaResourceManagerDeathNotifier
{
public:
// Enumeration for the valid decoding states
enum State {
CLIENT_STATE_WAIT_FOR_RESOURCE,
CLIENT_STATE_RESOURCE_ASSIGNED,
CLIENT_STATE_SHUTDOWN
};
struct EventListener : public virtual RefBase {
// Notifies a change of media resource request status.
virtual void statusChanged(int event) = 0;
};
MediaResourceManagerClient(const wp<EventListener>& listener);
// DeathRecipient
void died();
// IMediaResourceManagerClient
virtual void statusChanged(int event);
private:
wp<EventListener> mEventListener;
};
}; // namespace android
#endif // ANDROID_IMEDIARESOURCEMANAGERCLIENT_H

View File

@ -1,371 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaResourceManagerService"
#include <mozilla/Assertions.h>
#include <binder/IServiceManager.h>
#include <media/stagefright/foundation/AMessage.h>
#include <utils/Log.h>
#include "MediaResourceManagerClient.h"
#include "MediaResourceManagerService.h"
namespace android {
const char* MediaResourceManagerService::kMsgKeyResourceType = "res-type";
/* static */
void MediaResourceManagerService::instantiate() {
defaultServiceManager()->addService(
String16("media.resource_manager"),
new MediaResourceManagerService());
}
MediaResourceManagerService::MediaResourceManagerService()
{
mLooper = new ALooper;
mLooper->setName("MediaResourceManagerService");
mReflector = new AHandlerReflector<MediaResourceManagerService>(this);
// Register AMessage handler to ALooper.
mLooper->registerHandler(mReflector);
// Start ALooper thread.
mLooper->start();
}
MediaResourceManagerService::~MediaResourceManagerService()
{
// Unregister AMessage handler from ALooper.
mLooper->unregisterHandler(mReflector->id());
// Stop ALooper thread.
mLooper->stop();
}
void MediaResourceManagerService::binderDied(const wp<IBinder>& who)
{
if (who != NULL) {
Mutex::Autolock autoLock(mLock);
sp<IBinder> binder = who.promote();
if (binder != NULL) {
mResources.forgetClient(binder);
}
}
}
status_t MediaResourceManagerService::requestMediaResource(const sp<IMediaResourceManagerClient>& client,
int resourceType, bool willWait)
{
ResourceType type = static_cast<ResourceType>(resourceType);
// Support only HW_VIDEO_DECODER and HW_VIDEO_ENCODER.
switch (type) {
case HW_VIDEO_DECODER:
case HW_VIDEO_ENCODER:
break;
default:
// Type not supported.
return BAD_TYPE;
}
Mutex::Autolock autoLock(mLock);
// Must know if it will be granted or not - if there are enough unfufilled requests to
// use up the resource, fail. Otherwise we know that enqueuing under lock will succeed.
if (!willWait &&
(mResources.findAvailableResource(type, mResources.countRequests(type) + 1) ==
NAME_NOT_FOUND)) {
return RESOURCE_NOT_AVAILABLE;
}
// We could early-return here without enqueuing IF we can do the rest of
// the allocation safely here. However, enqueuing ensures there's only
// one copy of that code, and that any callbacks are made from the same
// context.
sp<IBinder> binder = client->asBinder();
mResources.enqueueRequest(binder, type);
binder->linkToDeath(this);
sp<AMessage> notify = new AMessage(kNotifyRequest, mReflector->id());
notify->setInt32(kMsgKeyResourceType, resourceType);
// Post AMessage to MediaResourceManagerService via ALooper.
notify->post();
return OK;
}
status_t MediaResourceManagerService::cancelClient(const sp<IMediaResourceManagerClient>& client,
int resourceType)
{
Mutex::Autolock autoLock(mLock);
sp<IBinder> binder = client->asBinder();
cancelClientLocked(binder, static_cast<ResourceType>(resourceType));
sp<AMessage> notify = new AMessage(kNotifyRequest, mReflector->id());
notify->setInt32(kMsgKeyResourceType, resourceType);
// Next!
// Note: since we held the lock while releasing and then posting, if there is
// a queue, no willWait==false entries can jump into the queue thinking they'll
// get the resource.
notify->post();
return NO_ERROR;
}
// Extract resource type from message.
static int32_t getResourceType(const sp<AMessage>& message)
{
int32_t resourceType = MediaResourceManagerService::INVALID_RESOURCE_TYPE;
return message->findInt32(MediaResourceManagerService::kMsgKeyResourceType, &resourceType) ?
resourceType : MediaResourceManagerService::INVALID_RESOURCE_TYPE;
}
// Called on ALooper thread.
void MediaResourceManagerService::onMessageReceived(const sp<AMessage> &msg)
{
Mutex::Autolock autoLock(mLock);
ResourceType type = static_cast<ResourceType>(getResourceType(msg));
// Note: a message is sent both for "I added an entry to the queue"
// (which may succeed, typically if the queue is empty), and for "I gave
// up the resource", in which case it's "give to the next waiting client,
// or no one".
// Exit if no resource is available, but leave the client in the waiting
// list.
int found = mResources.findAvailableResource(type);
if (found == NAME_NOT_FOUND) {
return;
}
// Exit if no request.
if (!mResources.hasRequest(type)) {
return;
}
sp<IBinder> req = mResources.nextRequest(type);
mResources.aquireResource(req, type, found);
// Notify resource assignment to the client.
sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(req);
client->statusChanged(MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED);
mResources.dequeueRequest(type);
}
void MediaResourceManagerService::cancelClientLocked(const sp<IBinder>& binder,
ResourceType resourceType)
{
mResources.forgetClient(binder, resourceType);
binder->unlinkToDeath(this);
}
MediaResourceManagerService::ResourceTable::ResourceTable()
{
// Populate types of resources.
for (int type = 0; type < NUM_OF_RESOURCE_TYPES; type++) {
ssize_t index = mMap.add(static_cast<ResourceType>(type), Resources());
Resources& resources = mMap.editValueAt(index);
int available;
switch (type) {
case HW_VIDEO_DECODER:
available = VIDEO_DECODER_COUNT;
break;
case HW_VIDEO_ENCODER:
available = VIDEO_ENCODER_COUNT;
break;
default:
available = 0;
break;
}
resources.mSlots.insertAt(0, available);
}
}
MediaResourceManagerService::ResourceTable::~ResourceTable() {
// Remove resouces.
mMap.clear();
}
bool MediaResourceManagerService::ResourceTable::supportsType(ResourceType type)
{
return mMap.indexOfKey(type) != NAME_NOT_FOUND;
}
ssize_t MediaResourceManagerService::ResourceTable::findAvailableResource(ResourceType type,
size_t numberNeeded)
{
MOZ_ASSERT(numberNeeded > 0);
ssize_t found = mMap.indexOfKey(type);
if (found == NAME_NOT_FOUND) {
// Unsupported type.
return found;
}
const Slots& slots = mMap.valueAt(found).mSlots;
found = NAME_NOT_FOUND;
for (size_t i = 0; i < slots.size(); i++) {
if (slots[i].mClient != nullptr) {
// Already in use.
continue;
}
if (--numberNeeded == 0) {
found = i;
break;
}
}
return found;
}
bool MediaResourceManagerService::ResourceTable::isOwnedByClient(const sp<IBinder>& client,
ResourceType type,
size_t index)
{
ResourceSlot* slot = resourceOfTypeAt(type, index);
return slot && slot->mClient == client;
}
status_t MediaResourceManagerService::ResourceTable::aquireResource(const sp<IBinder>& client,
ResourceType type,
size_t index)
{
ResourceSlot* slot = resourceOfTypeAt(type, index);
// Resouce should not be in use.
MOZ_ASSERT(slot && slot->mClient == nullptr);
if (!slot) {
return NAME_NOT_FOUND;
} else if (slot->mClient != nullptr) {
// Resource already in use by other client.
return PERMISSION_DENIED;
}
slot->mClient = client;
return OK;
}
MediaResourceManagerService::ResourceSlot*
MediaResourceManagerService::ResourceTable::resourceOfTypeAt(ResourceType type,
size_t index)
{
ssize_t found = mMap.indexOfKey(type);
if (found == NAME_NOT_FOUND) {
// Unsupported type.
return nullptr;
}
Slots& slots = mMap.editValueAt(found).mSlots;
MOZ_ASSERT(index < slots.size());
if (index >= slots.size()) {
// Index out of range.
return nullptr;
}
return &(slots.editItemAt(index));
}
bool MediaResourceManagerService::ResourceTable::hasRequest(ResourceType type)
{
ssize_t found = mMap.indexOfKey(type);
if (found == NAME_NOT_FOUND) {
// Unsupported type.
return nullptr;
}
const Fifo& queue = mMap.valueAt(found).mRequestQueue;
return !queue.empty();
}
uint32_t MediaResourceManagerService::ResourceTable::countRequests(ResourceType type)
{
ssize_t found = mMap.indexOfKey(type);
if (found == NAME_NOT_FOUND) {
// Unsupported type.
return 0;
}
const Fifo& queue = mMap.valueAt(found).mRequestQueue;
return queue.size();
}
sp<IBinder> MediaResourceManagerService::ResourceTable::nextRequest(ResourceType type)
{
ssize_t found = mMap.indexOfKey(type);
if (found == NAME_NOT_FOUND) {
// Unsupported type.
return nullptr;
}
const Fifo& queue = mMap.valueAt(found).mRequestQueue;
return *(queue.begin());
}
status_t MediaResourceManagerService::ResourceTable::enqueueRequest(const sp<IBinder>& client,
ResourceType type)
{
ssize_t found = mMap.indexOfKey(type);
if (found == NAME_NOT_FOUND) {
// Unsupported type.
return found;
}
mMap.editValueAt(found).mRequestQueue.push_back(client);
return OK;
}
status_t MediaResourceManagerService::ResourceTable::dequeueRequest(ResourceType type)
{
ssize_t found = mMap.indexOfKey(type);
if (found == NAME_NOT_FOUND) {
// Unsupported type.
return found;
}
Fifo& queue = mMap.editValueAt(found).mRequestQueue;
queue.erase(queue.begin());
return OK;
}
status_t MediaResourceManagerService::ResourceTable::forgetClient(const sp<IBinder>& client)
{
// Traverse all resources.
for (size_t i = 0; i < mMap.size(); i++) {
forgetClient(client, mMap.keyAt(i));
}
return OK;
}
status_t MediaResourceManagerService::ResourceTable::forgetClient(const sp<IBinder>& client, ResourceType type)
{
MOZ_ASSERT(supportsType(type));
Resources& resources = mMap.editValueFor(type);
// Remove pending requests for given client.
Fifo& queue = resources.mRequestQueue;
Fifo::iterator it(queue.begin());
while (it != queue.end()) {
if ((*it).get() == client.get()) {
queue.erase(it);
break;
}
it++;
}
// Revoke ownership for given client.
Slots& slots = resources.mSlots;
for (size_t i = 0; i < slots.size(); i++) {
ResourceSlot& slot = slots.editItemAt(i);
if (client.get() == slot.mClient.get()) {
slot.mClient = nullptr;
}
}
return OK;
}
}; // namespace android

View File

@ -1,135 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 ANDROID_MEDIARESOURCEMANAGERSERVICE_H
#define ANDROID_MEDIARESOURCEMANAGERSERVICE_H
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AHandlerReflector.h>
#include <media/stagefright/foundation/ALooper.h>
#include <utils/KeyedVector.h>
#include <utils/List.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
#include "IMediaResourceManagerClient.h"
#include "IMediaResourceManagerService.h"
namespace android {
/**
* Manage permissions of using media resources(hw decoder, hw encoder, camera)
* XXX Current implementation supports only one hw video codec.
* Need to extend to support multiple instance and other resources.
*/
class MediaResourceManagerService: public BnMediaResourceManagerService,
public IBinder::DeathRecipient
{
public:
// The maximum number of hardware resoureces available.
enum
{
VIDEO_DECODER_COUNT = 1,
VIDEO_ENCODER_COUNT = 1
};
enum
{
kNotifyRequest = 'noti',
};
static const char* kMsgKeyResourceType;
// Instantiate MediaResourceManagerService and register to service manager.
// If service manager is not present, wait until service manager becomes present.
static void instantiate();
// DeathRecipient
virtual void binderDied(const wp<IBinder>& who);
// derived from IMediaResourceManagerService
virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client,
int resourceType, bool willWait);
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client,
int resourceType);
// Receive a message from AHandlerReflector.
// Called on ALooper thread.
void onMessageReceived(const sp<AMessage> &msg);
protected:
MediaResourceManagerService();
virtual ~MediaResourceManagerService();
private:
// Represent a media resouce.
// Hold a IMediaResourceManagerClient that got a media resource as IBinder.
struct ResourceSlot
{
sp<IBinder> mClient;
};
typedef Vector<ResourceSlot> Slots;
typedef List<sp<IBinder> > Fifo;
struct Resources
{
// Queue of media resource requests. Hold IMediaResourceManagerClient that
// requesting a media resource as IBinder.
Fifo mRequestQueue;
// All resources that can be requested. Hold |ResourceSlot|s that track
// their usage.
Slots mSlots;
};
typedef KeyedVector<ResourceType, Resources> ResourcesMap;
// Manages requests from clients and availability of resources.
class ResourceTable
{
ResourceTable();
~ResourceTable();
// Resource operations.
bool supportsType(ResourceType type);
ssize_t findAvailableResource(ResourceType type, size_t number_needed = 1);
bool isOwnedByClient(const sp<IBinder>& client, ResourceType type, size_t index);
status_t aquireResource(const sp<IBinder>& client, ResourceType type, size_t index);
ResourceSlot* resourceOfTypeAt(ResourceType type, size_t index);
// Request operations.
bool hasRequest(ResourceType type);
uint32_t countRequests(ResourceType type);
sp<IBinder> nextRequest(ResourceType type);
status_t enqueueRequest(const sp<IBinder>& client, ResourceType type);
status_t dequeueRequest(ResourceType type);
status_t forgetClient(const sp<IBinder>& client, ResourceType type);
status_t forgetClient(const sp<IBinder>& client);
friend class MediaResourceManagerService;
// A map for all types of supported resources.
ResourcesMap mMap;
};
void cancelClientLocked(const sp<IBinder>& binder, ResourceType resourceType);
// ALooper is a message loop used in stagefright.
// It creates a thread for messages and handles messages in the thread.
// ALooper is a clone of Looper in android Java.
// http://developer.android.com/reference/android/os/Looper.html
sp<ALooper> mLooper;
// deliver a message to a wrapped object(OmxDecoder).
// AHandlerReflector is similar to Handler in android Java.
// http://developer.android.com/reference/android/os/Handler.html
sp<AHandlerReflector<MediaResourceManagerService> > mReflector;
// The lock protects manager operations called from multiple threads.
Mutex mLock;
// Keeps all the records.
ResourceTable mResources;
};
}; // namespace android
#endif // ANDROID_MEDIARESOURCEMANAGERSERVICE_H

View File

@ -1,47 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXPORTS += [
'IMediaResourceManagerClient.h',
'IMediaResourceManagerDeathNotifier.h',
'IMediaResourceManagerService.h',
'MediaResourceHandler.h',
'MediaResourceManagerClient.h',
'MediaResourceManagerService.h',
]
SOURCES += [
'IMediaResourceManagerClient.cpp',
'IMediaResourceManagerDeathNotifier.cpp',
'IMediaResourceManagerService.cpp',
'MediaResourceHandler.cpp',
'MediaResourceManagerClient.cpp',
'MediaResourceManagerService.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
# Suppress some GCC/clang warnings being treated as errors:
# - about multi-character constants which are used in codec-related code
if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
CXXFLAGS += [
'-Wno-error=multichar'
]
CXXFLAGS += [
'-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [
'frameworks/base/include',
'frameworks/base/include/binder',
'frameworks/base/include/utils',
'frameworks/base/include/media/',
'frameworks/base/include/media/stagefright/openmax',
'frameworks/base/media/libstagefright/include',
]
]
FINAL_LIBRARY = 'xul'
FAIL_ON_WARNINGS = True

View File

@ -94,7 +94,6 @@ LOCAL_INCLUDES += [
'/dom/base',
'/dom/html',
'/ipc/chromium/src',
'mediaresourcemanager',
]
CXXFLAGS += [

View File

@ -18,7 +18,6 @@ UNIFIED_SOURCES += [
]
LOCAL_INCLUDES += [
'/dom/media/omx/',
'/dom/media/omx/mediaresourcemanager',
]
include('/ipc/chromium/chromium-config.mozbuild')

View File

@ -0,0 +1,75 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "mozilla/Monitor.h"
#include "mozilla/ReentrantMonitor.h"
#include "MediaSystemResourceClient.h"
namespace mozilla {
Atomic<uint32_t> MediaSystemResourceClient::sSerialCounter(0);
MediaSystemResourceClient::MediaSystemResourceClient(MediaSystemResourceType aReourceType)
: mResourceType(aReourceType)
, mId(++sSerialCounter)
, mListener(nullptr)
, mResourceState(RESOURCE_STATE_START)
, mIsSync(false)
, mAcquireSyncWaitMonitor(nullptr)
, mAcquireSyncWaitDone(nullptr)
{
mManager = MediaSystemResourceManager::Get();
if (mManager) {
mManager->Register(this);
}
}
MediaSystemResourceClient::~MediaSystemResourceClient()
{
ReleaseResource();
if (mManager) {
mManager->Unregister(this);
}
}
bool
MediaSystemResourceClient::SetListener(MediaSystemResourceReservationListener* aListener)
{
if (!mManager) {
return false;
}
return mManager->SetListener(this, aListener);
}
void
MediaSystemResourceClient::Acquire()
{
if (!mManager) {
return;
}
mManager->Acquire(this);
}
bool
MediaSystemResourceClient::AcquireSyncNoWait()
{
if (!mManager) {
return false;
}
return mManager->AcquireSyncNoWait(this);
}
void
MediaSystemResourceClient::ReleaseResource()
{
if (!mManager) {
return;
}
mManager->ReleaseResource(this);
}
} // namespace mozilla

View File

@ -0,0 +1,94 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#if !defined(MediaSystemResourceClient_h_)
#define MediaSystemResourceClient_h_
#include "MediaSystemResourceManager.h"
#include "MediaSystemResourceTypes.h"
#include "mozilla/Atomics.h"
#include "mozilla/media/MediaSystemResourceTypes.h"
#include "mozilla/Monitor.h"
#include "nsRefPtr.h"
namespace mozilla {
class MediaSystemResourceManager;
/**
* This is a base class for listener callbacks.
* This callback is invoked when the media system resource reservation state
* is changed.
*/
class MediaSystemResourceReservationListener {
public:
virtual void ResourceReserved() = 0;
virtual void ResourceReserveFailed() = 0;
};
/**
* MediaSystemResourceClient is used to reserve a media system resource
* like hw decoder. When system has a limitation of a media resource,
* use this class to mediate use rights of the resource.
*/
class MediaSystemResourceClient
{
public:
// Enumeration for the valid decoding states
enum ResourceState {
RESOURCE_STATE_START,
RESOURCE_STATE_WAITING,
RESOURCE_STATE_ACQUIRED,
RESOURCE_STATE_NOT_ACQUIRED,
RESOURCE_STATE_END
};
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaSystemResourceClient)
explicit MediaSystemResourceClient(MediaSystemResourceType aReourceType);
bool SetListener(MediaSystemResourceReservationListener* aListener);
// Try to acquire media resource asynchronously.
// If the resource is used by others, wait until acquired.
void Acquire();
// Try to acquire media resource synchronously. If the resource is not immediately
// available, fail to acquire it.
// return false if resource is not acquired.
// return true if resource is acquired.
//
// This function should not be called on ImageBridge thread.
// It should be used only for compatibility with legacy code.
bool AcquireSyncNoWait();
void ReleaseResource();
private:
~MediaSystemResourceClient();
nsRefPtr<MediaSystemResourceManager> mManager;
const MediaSystemResourceType mResourceType;
const uint32_t mId;
// Modified only by MediaSystemResourceManager.
// Accessed and modified with MediaSystemResourceManager::mReentrantMonitor held.
MediaSystemResourceReservationListener* mListener;
ResourceState mResourceState;
bool mIsSync;
ReentrantMonitor* mAcquireSyncWaitMonitor;
bool* mAcquireSyncWaitDone;
static mozilla::Atomic<uint32_t> sSerialCounter;
friend class MediaSystemResourceManager;
};
} // namespace mozilla
#endif

View File

@ -0,0 +1,425 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "gfxPrefs.h"
#include "MediaSystemResourceManagerChild.h"
#include "MediaTaskQueue.h"
#include "mozilla/layers/ImageBridgeChild.h"
#include "MediaSystemResourceManager.h"
namespace mozilla {
using namespace mozilla::ipc;
using namespace mozilla::layers;
/* static */ StaticRefPtr<MediaSystemResourceManager> MediaSystemResourceManager::sSingleton;
/* static */ MediaSystemResourceManager*
MediaSystemResourceManager::Get()
{
if (sSingleton) {
return sSingleton;
}
MediaSystemResourceManager::Init();
return sSingleton;
}
/* static */ void
MediaSystemResourceManager::Shutdown()
{
MOZ_ASSERT(InImageBridgeChildThread());
if (sSingleton) {
sSingleton->CloseIPC();
sSingleton = nullptr;
}
}
/* static */ bool
MediaSystemResourceManager::IsMediaSystemResourceManagerEnabled()
{
#ifdef MOZ_WIDGET_GONK
return true;
#else
// XXX MediaSystemResourceManager is enabled only when ImageBridge is enabled.
// MediaSystemResourceManager uses ImageBridge's thread.
if (gfxPrefs::AsyncVideoOOPEnabled() &&
gfxPrefs::AsyncVideoEnabled()) {
return true;
} else {
return false;
}
#endif
}
class RunnableCallTask : public Task
{
public:
explicit RunnableCallTask(nsIRunnable* aRunnable)
: mRunnable(aRunnable) {}
void Run() override
{
mRunnable->Run();
}
protected:
nsCOMPtr<nsIRunnable> mRunnable;
};
/* static */ void
MediaSystemResourceManager::Init()
{
MOZ_ASSERT(IsMediaSystemResourceManagerEnabled());
if (!ImageBridgeChild::IsCreated()) {
NS_WARNING("ImageBridge does not exist");
return;
}
if (InImageBridgeChildThread()) {
if (!sSingleton) {
#ifdef DEBUG
static int timesCreated = 0;
timesCreated++;
MOZ_ASSERT(timesCreated == 1);
#endif
sSingleton = new MediaSystemResourceManager();
}
return;
}
ReentrantMonitor barrier("MediaSystemResourceManager::Init");
ReentrantMonitorAutoEnter autoMon(barrier);
bool done = false;
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableFunction([&]() {
if (!sSingleton) {
sSingleton = new MediaSystemResourceManager();
}
ReentrantMonitorAutoEnter autoMon(barrier);
done = true;
barrier.NotifyAll();
});
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
FROM_HERE, new RunnableCallTask(runnable));
// should stop the thread until done.
while (!done) {
barrier.Wait();
}
}
MediaSystemResourceManager::MediaSystemResourceManager()
: mReentrantMonitor("MediaSystemResourceManager.mReentrantMonitor")
, mShutDown(false)
, mChild(nullptr)
{
MOZ_ASSERT(InImageBridgeChildThread());
OpenIPC();
}
MediaSystemResourceManager::~MediaSystemResourceManager()
{
MOZ_ASSERT(IsIpcClosed());
}
void
MediaSystemResourceManager::OpenIPC()
{
MOZ_ASSERT(InImageBridgeChildThread());
MOZ_ASSERT(!mChild);
media::PMediaSystemResourceManagerChild* child =
ImageBridgeChild::GetSingleton()->SendPMediaSystemResourceManagerConstructor();
mChild = static_cast<media::MediaSystemResourceManagerChild*>(child);
mChild->SetManager(this);
}
void
MediaSystemResourceManager::CloseIPC()
{
MOZ_ASSERT(InImageBridgeChildThread());
if (!mChild) {
return;
}
mChild->Destroy();
mChild = nullptr;
mShutDown = true;
}
void
MediaSystemResourceManager::OnIpcClosed()
{
mChild = nullptr;
}
bool
MediaSystemResourceManager::IsIpcClosed()
{
return mChild ? true : false;
}
void
MediaSystemResourceManager::Register(MediaSystemResourceClient* aClient)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MOZ_ASSERT(aClient);
MOZ_ASSERT(!mResourceClients.Get(aClient->mId));
mResourceClients.Put(aClient->mId, aClient);
}
void
MediaSystemResourceManager::Unregister(MediaSystemResourceClient* aClient)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MOZ_ASSERT(aClient);
MOZ_ASSERT(mResourceClients.Get(aClient->mId));
MOZ_ASSERT(mResourceClients.Get(aClient->mId) == aClient);
mResourceClients.Remove(aClient->mId);
}
bool
MediaSystemResourceManager::SetListener(MediaSystemResourceClient* aClient,
MediaSystemResourceReservationListener* aListener)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MOZ_ASSERT(aClient);
MediaSystemResourceClient* client = mResourceClients.Get(aClient->mId);
MOZ_ASSERT(client);
if (!client) {
return false;
}
// State Check
if (aClient->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_START) {
return false;
}
aClient->mListener = aListener;
return true;
}
void
MediaSystemResourceManager::Acquire(MediaSystemResourceClient* aClient)
{
MOZ_ASSERT(aClient);
MOZ_ASSERT(!InImageBridgeChildThread());
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MediaSystemResourceClient* client = mResourceClients.Get(aClient->mId);
MOZ_ASSERT(client);
MOZ_ASSERT(client == aClient);
aClient->mIsSync = false; // async request
if (!client) {
HandleAcquireResult(aClient->mId, false);
return;
}
// State Check
if (aClient->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_START) {
HandleAcquireResult(aClient->mId, false);
return;
}
aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_WAITING;
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableMethod(
this,
&MediaSystemResourceManager::DoAcquire,
aClient->mId));
}
bool
MediaSystemResourceManager::AcquireSyncNoWait(MediaSystemResourceClient* aClient)
{
MOZ_ASSERT(aClient);
MOZ_ASSERT(!InImageBridgeChildThread());
ReentrantMonitor barrier("MediaSystemResourceManager::AcquireSyncNoWait");
ReentrantMonitorAutoEnter autoMon(barrier);
bool done = false;
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MediaSystemResourceClient* client = mResourceClients.Get(aClient->mId);
MOZ_ASSERT(client);
MOZ_ASSERT(client == aClient);
aClient->mIsSync = true; // sync request
if (InImageBridgeChildThread()) {
HandleAcquireResult(aClient->mId, false);
return false;
}
if (!aClient ||
!client ||
client != aClient) {
HandleAcquireResult(aClient->mId, false);
return false;
}
// State Check
if (aClient->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_START) {
HandleAcquireResult(aClient->mId, false);
return false;
}
// Hold barrier Monitor until acquire task end.
aClient->mAcquireSyncWaitMonitor = &barrier;
aClient->mAcquireSyncWaitDone = &done;
aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_WAITING;
}
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableMethod(
this,
&MediaSystemResourceManager::DoAcquire,
aClient->mId));
// should stop the thread until done.
while (!done) {
barrier.Wait();
}
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (aClient->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_ACQUIRED) {
return false;
}
return true;
}
}
void
MediaSystemResourceManager::DoAcquire(uint32_t aId)
{
MOZ_ASSERT(InImageBridgeChildThread());
if (mShutDown || !mChild) {
HandleAcquireResult(aId, false);
return;
}
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MediaSystemResourceClient* client = mResourceClients.Get(aId);
MOZ_ASSERT(client);
if (!client ||
client->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_WAITING) {
HandleAcquireResult(aId, false);
return;
}
MOZ_ASSERT(aId == client->mId);
bool willWait = !client->mAcquireSyncWaitMonitor ? true : false;
mChild->SendAcquire(client->mId,
client->mResourceType,
willWait);
}
}
void
MediaSystemResourceManager::ReleaseResource(MediaSystemResourceClient* aClient)
{
MOZ_ASSERT(aClient);
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MediaSystemResourceClient* client = mResourceClients.Get(aClient->mId);
MOZ_ASSERT(client);
MOZ_ASSERT(client == aClient);
if (!client ||
client != aClient ||
aClient->mResourceState == MediaSystemResourceClient::RESOURCE_STATE_START ||
aClient->mResourceState == MediaSystemResourceClient::RESOURCE_STATE_END) {
aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_END;
return;
}
aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_END;
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableMethod(
this,
&MediaSystemResourceManager::DoRelease,
aClient->mId));
}
}
void
MediaSystemResourceManager::DoRelease(uint32_t aId)
{
MOZ_ASSERT(InImageBridgeChildThread());
if (mShutDown || !mChild) {
return;
}
mChild->SendRelease(aId);
}
void
MediaSystemResourceManager::RecvResponse(uint32_t aId, bool aSuccess)
{
HandleAcquireResult(aId, aSuccess);
}
void
MediaSystemResourceManager::HandleAcquireResult(uint32_t aId, bool aSuccess)
{
if (!InImageBridgeChildThread()) {
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableMethod(
this,
&MediaSystemResourceManager::HandleAcquireResult,
aId,
aSuccess));
return;
}
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MediaSystemResourceClient* client = mResourceClients.Get(aId);
if (!client) {
// Client was already unregistered.
return;
}
if (client->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_WAITING) {
return;
}
// Update state
if (aSuccess) {
client->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_ACQUIRED;
} else {
client->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_NOT_ACQUIRED;
}
if (client->mIsSync) {
if (client->mAcquireSyncWaitMonitor) {
// Notify AcquireSync() complete
MOZ_ASSERT(client->mAcquireSyncWaitDone);
ReentrantMonitorAutoEnter autoMon(*client->mAcquireSyncWaitMonitor);
*client->mAcquireSyncWaitDone = true;
client->mAcquireSyncWaitMonitor->NotifyAll();
client->mAcquireSyncWaitMonitor = nullptr;
client->mAcquireSyncWaitDone = nullptr;
}
} else {
// Notify Acquire() result
if (client->mListener) {
if (aSuccess) {
client->mListener->ResourceReserved();
} else {
client->mListener->ResourceReserveFailed();
}
}
}
}
} // namespace mozilla

View File

@ -0,0 +1,85 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#if !defined(MediaSystemResourceManager_h_)
#define MediaSystemResourceManager_h_
#include <queue>
#include "MediaSystemResourceTypes.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/StaticPtr.h"
#include "nsAutoPtr.h"
#include "nsDataHashtable.h"
#include "nsISupportsImpl.h"
namespace mozilla {
namespace media {
class MediaSystemResourceManagerChild;
}
class MediaSystemResourceClient;
class MediaSystemResourceReservationListener;
class MediaTaskQueue;
class ReentrantMonitor;
/**
* Manage media system resource allocation requests within a process.
*/
class MediaSystemResourceManager
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaSystemResourceManager)
static MediaSystemResourceManager* Get();
static void Init();
static void Shutdown();
void OnIpcClosed();
void Register(MediaSystemResourceClient* aClient);
void Unregister(MediaSystemResourceClient* aClient);
bool SetListener(MediaSystemResourceClient* aClient,
MediaSystemResourceReservationListener* aListener);
void Acquire(MediaSystemResourceClient* aClient);
bool AcquireSyncNoWait(MediaSystemResourceClient* aClient);
void ReleaseResource(MediaSystemResourceClient* aClient);
void RecvResponse(uint32_t aId, bool aSuccess);
private:
MediaSystemResourceManager();
virtual ~MediaSystemResourceManager();
static bool IsMediaSystemResourceManagerEnabled();
void OpenIPC();
void CloseIPC();
bool IsIpcClosed();
void DoAcquire(uint32_t aId);
void DoRelease(uint32_t aId);
void HandleAcquireResult(uint32_t aId, bool aSuccess);
ReentrantMonitor mReentrantMonitor;
bool mShutDown;
media::MediaSystemResourceManagerChild* mChild;
nsDataHashtable<nsUint32HashKey, MediaSystemResourceClient*> mResourceClients;
static StaticRefPtr<MediaSystemResourceManager> sSingleton;
};
} // namespace mozilla
#endif

View File

@ -0,0 +1,53 @@
/* -*- 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/. */
#include "MediaSystemResourceManager.h"
#include "MediaSystemResourceManagerChild.h"
namespace mozilla {
namespace media {
MediaSystemResourceManagerChild::MediaSystemResourceManagerChild()
: mDestroyed(false)
{
}
MediaSystemResourceManagerChild::~MediaSystemResourceManagerChild()
{
}
bool
MediaSystemResourceManagerChild::RecvResponse(const uint32_t& aId,
const bool& aSuccess)
{
if (mManager) {
mManager->RecvResponse(aId, aSuccess);
}
return true;
}
void
MediaSystemResourceManagerChild::ActorDestroy(ActorDestroyReason aActorDestroyReason)
{
MOZ_ASSERT(!mDestroyed);
if (mManager) {
mManager->OnIpcClosed();
}
mDestroyed = true;
}
void
MediaSystemResourceManagerChild::Destroy()
{
if (mDestroyed) {
return;
}
SendRemoveResourceManager();
// WARNING: |this| is dead, hands off
}
} // namespace media
} // namespace mozilla

View File

@ -0,0 +1,66 @@
/* -*- 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/. */
#if !defined(MediaSystemResourceManagerChild_h_)
#define MediaSystemResourceManagerChild_h_
#include "mozilla/media/PMediaSystemResourceManagerChild.h"
#include "nsISupportsImpl.h"
namespace mozilla {
class MediaSystemResourceManager;
namespace ipc {
class BackgroundChildImpl;
}
namespace media {
/**
* Handle MediaSystemResourceManager's IPC
*/
class MediaSystemResourceManagerChild final : public PMediaSystemResourceManagerChild
{
public:
struct ResourceListener {
/* The resource is reserved and can be granted.
* The client can allocate the requested resource.
*/
virtual void resourceReserved() = 0;
/* The resource is not reserved any more.
* The client should release the resource as soon as possible if the
* resource is still being held.
*/
virtual void resourceCanceled() = 0;
};
MediaSystemResourceManagerChild();
virtual ~MediaSystemResourceManagerChild();
void Destroy();
void SetManager(MediaSystemResourceManager* aManager)
{
mManager = aManager;
}
protected:
bool RecvResponse(const uint32_t& aId,
const bool& aSuccess) override;
private:
void ActorDestroy(ActorDestroyReason aActorDestroyReason) override;
bool mDestroyed;
MediaSystemResourceManager* mManager;
friend class mozilla::ipc::BackgroundChildImpl;
};
} // namespatce media
} // namespatce mozilla
#endif

View File

@ -0,0 +1,77 @@
/* -*- 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/. */
#include "mozilla/unused.h"
#include "MediaSystemResourceManagerParent.h"
namespace mozilla {
namespace media {
using namespace ipc;
MediaSystemResourceManagerParent::MediaSystemResourceManagerParent()
: mDestroyed(false)
{
mMediaSystemResourceService = MediaSystemResourceService::Get();
}
MediaSystemResourceManagerParent::~MediaSystemResourceManagerParent()
{
MOZ_ASSERT(mDestroyed);
}
bool
MediaSystemResourceManagerParent::RecvAcquire(const uint32_t& aId,
const MediaSystemResourceType& aResourceType,
const bool& aWillWait)
{
MediaSystemResourceRequest* request = mResourceRequests.Get(aId);
MOZ_ASSERT(!request);
if (request) {
// Send fail response
mozilla::unused << SendResponse(aId, false /* fail */);
return true;
}
request = new MediaSystemResourceRequest(aId, aResourceType);
mResourceRequests.Put(aId, request);
mMediaSystemResourceService->Acquire(this, aId, aResourceType, aWillWait);
return true;
}
bool
MediaSystemResourceManagerParent::RecvRelease(const uint32_t& aId)
{
MediaSystemResourceRequest* request = mResourceRequests.Get(aId);
if (!request) {
return true;
}
mMediaSystemResourceService->ReleaseResource(this, aId, request->mResourceType);
mResourceRequests.Remove(aId);
return true;
}
bool
MediaSystemResourceManagerParent::RecvRemoveResourceManager()
{
return PMediaSystemResourceManagerParent::Send__delete__(this);
}
void
MediaSystemResourceManagerParent::ActorDestroy(ActorDestroyReason aReason)
{
MOZ_ASSERT(!mDestroyed);
// Release all resource requests of the MediaSystemResourceManagerParent.
// Clears all remaining pointers to this object.
mMediaSystemResourceService->ReleaseResource(this);
mDestroyed = true;
}
} // namespace media
} // namespace mozilla

View File

@ -0,0 +1,57 @@
/* -*- 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/. */
#if !defined(MediaSystemResourceManagerParent_h_)
#define MediaSystemResourceManagerParent_h_
#include "MediaSystemResourceManager.h"
#include "MediaSystemResourceService.h"
#include "MediaSystemResourceTypes.h"
#include "mozilla/media/PMediaSystemResourceManagerParent.h"
namespace mozilla {
namespace media {
/**
* Handle MediaSystemResourceManager's IPC
*/
class MediaSystemResourceManagerParent final : public PMediaSystemResourceManagerParent
{
public:
MediaSystemResourceManagerParent();
virtual ~MediaSystemResourceManagerParent();
protected:
bool RecvAcquire(const uint32_t& aId,
const MediaSystemResourceType& aResourceType,
const bool& aWillWait) override;
bool RecvRelease(const uint32_t& aId) override;
bool RecvRemoveResourceManager() override;
private:
void ActorDestroy(ActorDestroyReason aActorDestroyReason) override;
struct MediaSystemResourceRequest {
MediaSystemResourceRequest()
: mId(-1), mResourceType(MediaSystemResourceType::INVALID_RESOURCE) {}
MediaSystemResourceRequest(uint32_t aId, MediaSystemResourceType aResourceType)
: mId(aId), mResourceType(aResourceType) {}
int32_t mId;
MediaSystemResourceType mResourceType;
};
bool mDestroyed;
nsRefPtr<MediaSystemResourceService> mMediaSystemResourceService;
nsClassHashtable<nsUint32HashKey, MediaSystemResourceRequest> mResourceRequests;
};
} // namespatce media
} // namespatce mozilla
#endif

View File

@ -0,0 +1,25 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#if !defined(MediaSystemResourceMessageUtils_h_)
#define MediaSystemResourceMessageUtils_h_
#include "ipc/IPCMessageUtils.h"
#include "MediaSystemResourceTypes.h"
namespace IPC {
template <>
struct ParamTraits<mozilla::MediaSystemResourceType>
: public ContiguousEnumSerializer<
mozilla::MediaSystemResourceType,
mozilla::MediaSystemResourceType::VIDEO_DECODER,
mozilla::MediaSystemResourceType::INVALID_RESOURCE>
{};
} // namespace IPC
#endif

View File

@ -0,0 +1,273 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "MediaSystemResourceManagerParent.h"
#include "mozilla/layers/CompositorParent.h"
#include "mozilla/unused.h"
#include "MediaSystemResourceService.h"
using namespace mozilla::layers;
namespace mozilla {
/* static */ StaticRefPtr<MediaSystemResourceService> MediaSystemResourceService::sSingleton;
/* static */ MediaSystemResourceService*
MediaSystemResourceService::Get()
{
if (sSingleton) {
return sSingleton;
}
Init();
return sSingleton;
}
/* static */ void
MediaSystemResourceService::Init()
{
if (!sSingleton) {
sSingleton = new MediaSystemResourceService();
}
}
/* static */ void
MediaSystemResourceService::Shutdown()
{
if (sSingleton) {
sSingleton->Destroy();
sSingleton = nullptr;
}
}
MediaSystemResourceService::MediaSystemResourceService()
: mDestroyed(false)
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
#ifdef MOZ_WIDGET_GONK
// The maximum number of hardware resoureces available.
// XXX need to hange to a dynamic way.
enum
{
VIDEO_DECODER_COUNT = 1,
VIDEO_ENCODER_COUNT = 1
};
MediaSystemResource* resource;
resource = new MediaSystemResource(VIDEO_DECODER_COUNT);
mResources.Put(static_cast<uint32_t>(MediaSystemResourceType::VIDEO_DECODER), resource);
resource = new MediaSystemResource(VIDEO_ENCODER_COUNT);
mResources.Put(static_cast<uint32_t>(MediaSystemResourceType::VIDEO_ENCODER), resource);
#endif
}
MediaSystemResourceService::~MediaSystemResourceService()
{
}
void
MediaSystemResourceService::Destroy()
{
mDestroyed = true;
}
void
MediaSystemResourceService::Acquire(media::MediaSystemResourceManagerParent* aParent,
uint32_t aId,
MediaSystemResourceType aResourceType,
bool aWillWait)
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
MOZ_ASSERT(aParent);
if (mDestroyed) {
return;
}
MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
if (!resource ||
resource->mResourceCount == 0) {
// Resource does not exit
// Send fail response
mozilla::unused << aParent->SendResponse(aId, false /* fail */);
return;
}
// Try to acquire a resource
if (resource->mAcquiredRequests.size() < resource->mResourceCount) {
// Resource is available
resource->mAcquiredRequests.push_back(
MediaSystemResourceRequest(aParent, aId));
// Send success response
mozilla::unused << aParent->SendResponse(aId, true /* success */);
return;
} else if (!aWillWait) {
// Resource is not available and do not wait.
// Send fail response
mozilla::unused << aParent->SendResponse(aId, false /* fail */);
return;
}
// Wait until acquire.
resource->mWaitingRequests.push_back(
MediaSystemResourceRequest(aParent, aId));
}
void
MediaSystemResourceService::ReleaseResource(media::MediaSystemResourceManagerParent* aParent,
uint32_t aId,
MediaSystemResourceType aResourceType)
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
MOZ_ASSERT(aParent);
if (mDestroyed) {
return;
}
MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
if (!resource ||
resource->mResourceCount == 0) {
// Resource does not exit
return;
}
RemoveRequest(aParent, aId, aResourceType);
UpdateRequests(aResourceType);
}
struct ReleaseResourceData
{
MediaSystemResourceService* mSelf;
media::MediaSystemResourceManagerParent* mParent;
};
/*static*/PLDHashOperator
MediaSystemResourceService::ReleaseResourceForKey(const uint32_t& aKey,
nsAutoPtr<MediaSystemResource>& aData,
void* aClosure)
{
ReleaseResourceData* closure = static_cast<ReleaseResourceData*>(aClosure);
closure->mSelf->RemoveRequests(closure->mParent, static_cast<MediaSystemResourceType>(aKey));
closure->mSelf->UpdateRequests(static_cast<MediaSystemResourceType>(aKey));
return PLDHashOperator::PL_DHASH_NEXT;
}
void
MediaSystemResourceService::ReleaseResource(media::MediaSystemResourceManagerParent* aParent)
{
MOZ_ASSERT(aParent);
if (mDestroyed) {
return;
}
ReleaseResourceData data = { this, aParent };
mResources.Enumerate(ReleaseResourceForKey, &data);
}
void
MediaSystemResourceService::RemoveRequest(media::MediaSystemResourceManagerParent* aParent,
uint32_t aId,
MediaSystemResourceType aResourceType)
{
MOZ_ASSERT(aParent);
MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
if (!resource) {
return;
}
std::deque<MediaSystemResourceRequest>::iterator it;
std::deque<MediaSystemResourceRequest>& acquiredRequests =
resource->mAcquiredRequests;
for (it = acquiredRequests.begin(); it != acquiredRequests.end(); it++) {
if (((*it).mParent == aParent) && ((*it).mId == aId)) {
acquiredRequests.erase(it);
return;
}
}
std::deque<MediaSystemResourceRequest>& waitingRequests =
resource->mWaitingRequests;
for (it = waitingRequests.begin(); it != waitingRequests.end(); it++) {
if (((*it).mParent == aParent) && ((*it).mId == aId)) {
waitingRequests.erase(it);
return;
}
}
}
void
MediaSystemResourceService::RemoveRequests(media::MediaSystemResourceManagerParent* aParent,
MediaSystemResourceType aResourceType)
{
MOZ_ASSERT(aParent);
MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
if (!resource ||
resource->mResourceCount == 0) {
// Resource does not exit
return;
}
std::deque<MediaSystemResourceRequest>::iterator it;
std::deque<MediaSystemResourceRequest>& acquiredRequests =
resource->mAcquiredRequests;
for (it = acquiredRequests.begin(); it != acquiredRequests.end();) {
if ((*it).mParent == aParent) {
it = acquiredRequests.erase(it);
} else {
it++;
}
}
std::deque<MediaSystemResourceRequest>& waitingRequests =
resource->mWaitingRequests;
for (it = waitingRequests.begin(); it != waitingRequests.end();) {
if ((*it).mParent == aParent) {
it = waitingRequests.erase(it);
return;
} else {
it++;
}
}
}
void
MediaSystemResourceService::UpdateRequests(MediaSystemResourceType aResourceType)
{
MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
if (!resource ||
resource->mResourceCount == 0) {
// Resource does not exit
return;
}
std::deque<MediaSystemResourceRequest>& acquiredRequests =
resource->mAcquiredRequests;
std::deque<MediaSystemResourceRequest>& waitingRequests =
resource->mWaitingRequests;
while ((acquiredRequests.size() < resource->mResourceCount) &&
(waitingRequests.size() > 0)) {
MediaSystemResourceRequest& request = waitingRequests.front();
MOZ_ASSERT(request.mParent);
// Send response
mozilla::unused << request.mParent->SendResponse(request.mId, true /* success */);
// Move request to mAcquiredRequests
acquiredRequests.push_back(waitingRequests.front());
waitingRequests.pop_front();
}
}
} // namespace mozilla

View File

@ -0,0 +1,93 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#if !defined(MediaSystemResourceService_h_)
#define MediaSystemResourceService_h_
#include <deque>
#include "MediaSystemResourceTypes.h"
#include "mozilla/StaticPtr.h"
#include "nsClassHashtable.h"
namespace mozilla {
namespace media {
class MediaSystemResourceManagerParent;
}
/**
* Manage media system resource allocation requests within system.
*/
class MediaSystemResourceService
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaSystemResourceService)
static MediaSystemResourceService* Get();
static void Init();
static void Shutdown();
void Acquire(media::MediaSystemResourceManagerParent* aParent,
uint32_t aId,
MediaSystemResourceType aResourceType,
bool aWillWait);
void ReleaseResource(media::MediaSystemResourceManagerParent* aParent,
uint32_t aId,
MediaSystemResourceType aResourceType);
void ReleaseResource(media::MediaSystemResourceManagerParent* aParent);
private:
MediaSystemResourceService();
~MediaSystemResourceService();
struct MediaSystemResourceRequest {
MediaSystemResourceRequest()
: mParent(nullptr), mId(-1) {}
MediaSystemResourceRequest(media::MediaSystemResourceManagerParent* aParent, uint32_t aId)
: mParent(aParent), mId(aId) {}
media::MediaSystemResourceManagerParent* mParent;
uint32_t mId;
};
struct MediaSystemResource {
MediaSystemResource()
: mResourceCount(0) {}
explicit MediaSystemResource(uint32_t aResourceCount)
: mResourceCount(aResourceCount) {}
std::deque<MediaSystemResourceRequest> mWaitingRequests;
std::deque<MediaSystemResourceRequest> mAcquiredRequests;
uint32_t mResourceCount;
};
void Destroy();
void RemoveRequest(media::MediaSystemResourceManagerParent* aParent,
uint32_t aId,
MediaSystemResourceType aResourceType);
void RemoveRequests(media::MediaSystemResourceManagerParent* aParent,
MediaSystemResourceType aResourceType);
void UpdateRequests(MediaSystemResourceType aResourceType);
static PLDHashOperator ReleaseResourceForKey(const uint32_t& aKey,
nsAutoPtr<MediaSystemResource>& aData,
void* aClosure);
bool mDestroyed;
nsClassHashtable<nsUint32HashKey, MediaSystemResource> mResources;
static StaticRefPtr<MediaSystemResourceService> sSingleton;
};
} // namespace mozilla
#endif

View File

@ -0,0 +1,23 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#if !defined(MediaSystemResourceTypes_h_)
#define MediaSystemResourceTypes_h_
namespace mozilla {
enum class MediaSystemResourceType : uint32_t {
VIDEO_DECODER = 0,
AUDIO_DECODER, // Not supported currently.
VIDEO_ENCODER,
AUDIO_ENCODER, // Not supported currently.
CAMERA, // Not supported currently.
INVALID_RESOURCE,
};
} // namespace mozilla
#endif

View File

@ -0,0 +1,37 @@
/* -*- 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/. */
include protocol PImageBridge;
include "mozilla/media/MediaSystemResourceMessageUtils.h";
using mozilla::MediaSystemResourceType from "mozilla/media/MediaSystemResourceTypes.h";
namespace mozilla {
namespace media {
/*
* The PMediaSystemResourceManager is a sub-protocol in PImageBridge
*/
sync protocol PMediaSystemResourceManager
{
manager PImageBridge;
child:
async Response(uint32_t aId, bool aSuccess);
async __delete__();
parent:
async Acquire(uint32_t aId, MediaSystemResourceType aResourceType, bool aWillWait);
async Release(uint32_t aId);
/**
* Asynchronously tell the parent side to remove the PMediaSystemResourceManager.
*/
async RemoveResourceManager();
};
} // namespace media
} // namespace mozilla

View File

@ -38,15 +38,28 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
]
EXPORTS.mozilla.media += ['MediaChild.h',
'MediaParent.h',
'MediaUtils.h'
'MediaParent.h',
'MediaSystemResourceClient.h',
'MediaSystemResourceManager.h',
'MediaSystemResourceManagerChild.h',
'MediaSystemResourceManagerParent.h',
'MediaSystemResourceMessageUtils.h',
'MediaSystemResourceService.h',
'MediaSystemResourceTypes.h',
'MediaUtils.h'
]
UNIFIED_SOURCES += ['MediaChild.cpp',
'MediaParent.cpp',
'MediaUtils.cpp'
'MediaSystemResourceClient.cpp',
'MediaSystemResourceManager.cpp',
'MediaSystemResourceManagerChild.cpp',
'MediaSystemResourceManagerParent.cpp',
'MediaSystemResourceService.cpp',
'MediaUtils.cpp',
]
IPDL_SOURCES += [
'PMedia.ipdl',
'PMediaSystemResourceManager.ipdl',
]
# /dom/base needed for nsGlobalWindow.h in MediaChild.cpp
LOCAL_INCLUDES += [

View File

@ -105,6 +105,11 @@ AudioContext::AudioContext(nsPIDOMWindow* aWindow,
// bound to the window.
mDestination = new AudioDestinationNode(this, aIsOffline, aChannel,
aNumberOfChannels, aLength, aSampleRate);
}
void
AudioContext::Init()
{
// We skip calling SetIsOnlyNodeForContext and the creation of the
// audioChannelAgent during mDestination's constructor, because we can only
// call them after mDestination has been set up.
@ -145,6 +150,7 @@ AudioContext::Constructor(const GlobalObject& aGlobal,
nsRefPtr<AudioContext> object =
new AudioContext(window, false,
AudioChannelService::GetDefaultAudioChannel());
object->Init();
RegisterWeakMemoryReporter(object);
@ -163,6 +169,7 @@ AudioContext::Constructor(const GlobalObject& aGlobal,
}
nsRefPtr<AudioContext> object = new AudioContext(window, false, aChannel);
object->Init();
RegisterWeakMemoryReporter(object);

View File

@ -101,6 +101,8 @@ class AudioContext final : public DOMEventTargetHelper,
float aSampleRate = 0.0f);
~AudioContext();
void Init();
public:
typedef uint64_t AudioContextId;

View File

@ -598,7 +598,7 @@ AudioDestinationNode::SetMozAudioChannelType(AudioChannel aValue, ErrorResult& a
bool
AudioDestinationNode::CheckAudioChannelPermissions(AudioChannel aValue)
{
if (!Preferences::GetBool("media.useAudioChannelService")) {
if (!UseAudioChannelService()) {
return true;
}

View File

@ -42,6 +42,7 @@
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/layers/PLayerTransactionParent.h"
#include "mozilla/layers/ShadowLayersManager.h" // for ShadowLayersManager
#include "mozilla/media/MediaSystemResourceService.h" // for MediaSystemResourceService
#include "mozilla/mozalloc.h" // for operator new, etc
#include "mozilla/Telemetry.h"
#ifdef MOZ_WIDGET_GTK
@ -593,6 +594,7 @@ void CompositorParent::ShutDown()
MOZ_ASSERT(sCompositorThreadHolder, "The compositor thread has already been shut down!");
ReleaseImageBridgeParentSingleton();
MediaSystemResourceService::Shutdown();
sCompositorThreadHolder = nullptr;
@ -1249,6 +1251,14 @@ CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
mRootLayerTreeID, aPaintSequenceNumber);
}
#ifdef DEBUG
if (aTransactionId <= mPendingTransaction) {
// Logging added to help diagnose why we're triggering the assert below.
// See bug 1145295
printf_stderr("CRASH: aTransactionId %" PRIu64 " <= mPendingTransaction %" PRIu64 "\n",
aTransactionId, mPendingTransaction);
}
#endif
MOZ_ASSERT(aTransactionId > mPendingTransaction);
mPendingTransaction = aTransactionId;

View File

@ -21,6 +21,8 @@
#include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
#include "mozilla/ipc/Transport.h" // for Transport
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager
#include "mozilla/media/MediaSystemResourceManagerChild.h" // for MediaSystemResourceManagerChild
#include "mozilla/layers/CompositableClient.h" // for CompositableChild, etc
#include "mozilla/layers/CompositorParent.h" // for CompositorParent
#include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator
@ -49,6 +51,7 @@ using base::Thread;
using base::ProcessId;
using namespace mozilla::ipc;
using namespace mozilla::gfx;
using namespace mozilla::media;
typedef std::vector<CompositableOperation> OpVector;
@ -171,6 +174,9 @@ static void ImageBridgeShutdownStep1(ReentrantMonitor *aBarrier, bool *aDone)
MOZ_ASSERT(InImageBridgeChildThread(),
"Should be in ImageBridgeChild thread.");
MediaSystemResourceManager::Shutdown();
if (sImageBridgeChildSingleton) {
// Force all managed protocols to shut themselves down cleanly
InfallibleTArray<PCompositableChild*> compositables;
@ -188,6 +194,7 @@ static void ImageBridgeShutdownStep1(ReentrantMonitor *aBarrier, bool *aDone)
// From now on, no message can be sent through the image bridge from the
// client side except the final Stop message.
}
*aDone = true;
aBarrier->NotifyAll();
}
@ -821,6 +828,21 @@ ImageBridgeChild::DeallocPTextureChild(PTextureChild* actor)
return TextureClient::DestroyIPDLActor(actor);
}
PMediaSystemResourceManagerChild*
ImageBridgeChild::AllocPMediaSystemResourceManagerChild()
{
MOZ_ASSERT(!mShuttingDown);
return new mozilla::media::MediaSystemResourceManagerChild();
}
bool
ImageBridgeChild::DeallocPMediaSystemResourceManagerChild(PMediaSystemResourceManagerChild* aActor)
{
MOZ_ASSERT(aActor);
delete static_cast<mozilla::media::MediaSystemResourceManagerChild*>(aActor);
return true;
}
bool
ImageBridgeChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages)
{

View File

@ -189,6 +189,12 @@ public:
virtual bool
DeallocPTextureChild(PTextureChild* actor) override;
PMediaSystemResourceManagerChild*
AllocPMediaSystemResourceManagerChild() override;
bool
DeallocPMediaSystemResourceManagerChild(PMediaSystemResourceManagerChild* aActor) override;
virtual bool
RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages) override;

View File

@ -17,6 +17,7 @@
#include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/ipc/Transport.h" // for Transport
#include "mozilla/media/MediaSystemResourceManagerParent.h" // for MediaSystemResourceManagerParent
#include "mozilla/layers/CompositableTransactionParent.h"
#include "mozilla/layers/CompositorParent.h" // for CompositorParent
#include "mozilla/layers/LayerManagerComposite.h"
@ -42,6 +43,7 @@ namespace layers {
using namespace mozilla::ipc;
using namespace mozilla::gfx;
using namespace mozilla::media;
std::map<base::ProcessId, ImageBridgeParent*> ImageBridgeParent::sImageBridges;
@ -259,6 +261,20 @@ ImageBridgeParent::DeallocPTextureParent(PTextureParent* actor)
return TextureHost::DestroyIPDLActor(actor);
}
PMediaSystemResourceManagerParent*
ImageBridgeParent::AllocPMediaSystemResourceManagerParent()
{
return new mozilla::media::MediaSystemResourceManagerParent();
}
bool
ImageBridgeParent::DeallocPMediaSystemResourceManagerParent(PMediaSystemResourceManagerParent* aActor)
{
MOZ_ASSERT(aActor);
delete static_cast<mozilla::media::MediaSystemResourceManagerParent*>(aActor);
return true;
}
void
ImageBridgeParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage)
{

View File

@ -81,6 +81,9 @@ public:
const TextureFlags& aFlags) override;
virtual bool DeallocPTextureParent(PTextureParent* actor) override;
PMediaSystemResourceManagerParent* AllocPMediaSystemResourceManagerParent() override;
bool DeallocPMediaSystemResourceManagerParent(PMediaSystemResourceManagerParent* aActor) override;
virtual bool
RecvChildAsyncMessages(InfallibleTArray<AsyncChildMessageData>&& aMessages) override;

View File

@ -9,6 +9,7 @@ include protocol PCompositable;
include protocol PLayer;
include protocol PTexture;
include ProtocolTypes;
include protocol PMediaSystemResourceManager;
include "mozilla/GfxMessageUtils.h";
@ -29,6 +30,7 @@ sync protocol PImageBridge
{
manages PCompositable;
manages PTexture;
manages PMediaSystemResourceManager;
child:
async ParentAsyncMessages(AsyncParentMessageData[] aMessages);
@ -54,6 +56,7 @@ parent:
sync PCompositable(TextureInfo aInfo) returns (uint64_t id);
async PTexture(SurfaceDescriptor aSharedData, TextureFlags aTextureFlags);
async PMediaSystemResourceManager();
async ChildAsyncMessages(AsyncChildMessageData[] aMessages);
};

View File

@ -1390,58 +1390,6 @@ gfxPlatform::MakePlatformFont(const nsAString& aFontName,
return nullptr;
}
static void
AppendGenericFontFromPref(nsString& aFonts, nsIAtom *aLangGroup, const char *aGenericName)
{
NS_ENSURE_TRUE_VOID(Preferences::GetRootBranch());
nsAutoCString prefName, langGroupString;
aLangGroup->ToUTF8String(langGroupString);
nsAutoCString genericDotLang;
if (aGenericName) {
genericDotLang.Assign(aGenericName);
} else {
prefName.AssignLiteral("font.default.");
prefName.Append(langGroupString);
genericDotLang = Preferences::GetCString(prefName.get());
}
genericDotLang.Append('.');
genericDotLang.Append(langGroupString);
// fetch font.name.xxx value
prefName.AssignLiteral("font.name.");
prefName.Append(genericDotLang);
nsAdoptingString nameValue = Preferences::GetString(prefName.get());
if (nameValue) {
if (!aFonts.IsEmpty())
aFonts.AppendLiteral(", ");
aFonts += nameValue;
}
// fetch font.name-list.xxx value
prefName.AssignLiteral("font.name-list.");
prefName.Append(genericDotLang);
nsAdoptingString nameListValue = Preferences::GetString(prefName.get());
if (nameListValue && !nameListValue.Equals(nameValue)) {
if (!aFonts.IsEmpty())
aFonts.AppendLiteral(", ");
aFonts += nameListValue;
}
}
void
gfxPlatform::GetPrefFonts(nsIAtom *aLanguage, nsString& aFonts, bool aAppendUnicode)
{
aFonts.Truncate();
AppendGenericFontFromPref(aFonts, aLanguage, nullptr);
if (aAppendUnicode)
AppendGenericFontFromPref(aFonts, nsGkAtoms::Unicode, nullptr);
}
bool gfxPlatform::ForEachPrefFont(eFontPrefLang aLangArray[], uint32_t aLangArrayLen, PrefFontCallback aCallback,
void *aClosure)
{

View File

@ -454,8 +454,6 @@ public:
virtual bool DidRenderingDeviceReset(DeviceResetReason* aResetReason = nullptr) { return false; }
void GetPrefFonts(nsIAtom *aLanguage, nsString& array, bool aAppendUnicode = true);
// in some situations, need to make decisions about ambiguous characters, may need to look at multiple pref langs
void GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang);

View File

@ -2983,16 +2983,40 @@ void gfxFontGroup::ComputeRanges(nsTArray<gfxTextRange>& aRanges,
aRanges[lastRangeIndex].end = aLength;
#if 0
// dump out font matching info
if (mStyle.systemFont) return;
for (size_t i = 0, i_end = aRanges.Length(); i < i_end; i++) {
const gfxTextRange& r = aRanges[i];
printf("fontmatch %zd:%zd font: %s (%d)\n",
r.start, r.end,
(r.font.get() ?
NS_ConvertUTF16toUTF8(r.font->GetName()).get() : "<null>"),
r.matchType);
#ifndef RELEASE_BUILD
PRLogModuleInfo *log = (mStyle.systemFont ?
gfxPlatform::GetLog(eGfxLog_textrunui) :
gfxPlatform::GetLog(eGfxLog_textrun));
if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Debug))) {
nsAutoCString lang;
mStyle.language->ToUTF8String(lang);
nsAutoString families;
mFamilyList.ToString(families);
// collect the font matched for each range
nsAutoCString fontMatches;
for (size_t i = 0, i_end = aRanges.Length(); i < i_end; i++) {
const gfxTextRange& r = aRanges[i];
fontMatches.AppendPrintf(" [%u:%u] %.200s (%s)", r.start, r.end,
(r.font.get() ?
NS_ConvertUTF16toUTF8(r.font->GetName()).get() : "<null>"),
(r.matchType == gfxTextRange::kFontGroup ?
"list" :
(r.matchType == gfxTextRange::kPrefsFallback) ?
"prefs" : "sys"));
}
MOZ_LOG(log, LogLevel::Debug,\
("(%s-fontmatching) fontgroup: [%s] default: %s lang: %s script: %d"
"%s\n",
(mStyle.systemFont ? "textrunui" : "textrun"),
NS_ConvertUTF16toUTF8(families).get(),
(mFamilyList.GetDefaultFontType() == eFamily_serif ?
"serif" :
(mFamilyList.GetDefaultFontType() == eFamily_sans_serif ?
"sans-serif" : "none")),
lang.get(), aRunScript,
fontMatches.get()));
}
#endif
}

View File

@ -831,18 +831,6 @@ public:
int32_t aRunScript, gfxFont *aPrevMatchedFont,
uint8_t *aMatchType);
// search through pref fonts for a character, return nullptr if no matching pref font
virtual already_AddRefed<gfxFont> WhichPrefFontSupportsChar(uint32_t aCh);
already_AddRefed<gfxFont>
WhichSystemFontSupportsChar(uint32_t aCh, uint32_t aNextCh,
int32_t aRunScript);
template<typename T>
void ComputeRanges(nsTArray<gfxTextRange>& mRanges,
const T *aString, uint32_t aLength,
int32_t aRunScript, uint16_t aOrientation);
gfxUserFontSet* GetUserFontSet();
// With downloadable fonts, the composition of the font group can change as fonts are downloaded
@ -891,6 +879,18 @@ public:
nsTArray<nsString>& aGenericFamilies);
protected:
// search through pref fonts for a character, return nullptr if no matching pref font
already_AddRefed<gfxFont> WhichPrefFontSupportsChar(uint32_t aCh);
already_AddRefed<gfxFont>
WhichSystemFontSupportsChar(uint32_t aCh, uint32_t aNextCh,
int32_t aRunScript);
template<typename T>
void ComputeRanges(nsTArray<gfxTextRange>& mRanges,
const T *aString, uint32_t aLength,
int32_t aRunScript, uint16_t aOrientation);
class FamilyFace {
public:
FamilyFace() : mFamily(nullptr), mFontEntry(nullptr),

View File

@ -2309,6 +2309,10 @@ ReportCompartmentStats(const JS::CompartmentStats& cStats,
cStats.regexpCompartment,
"The regexp compartment and regexp data.");
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("saved-stacks-set"),
cStats.savedStacksSet,
"The saved stacks set.");
if (sundriesGCHeap > 0) {
// We deliberately don't use ZCREPORT_GC_BYTES here.
REPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("sundries/gc-heap"),
@ -2501,9 +2505,8 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats& rtStats,
"Memory being used by the GC's nursery.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/nursery-malloced-buffers"),
KIND_NONHEAP, rtStats.runtime.gc.nurseryMallocedBuffers,
"Out-of-line slots and elements belonging to objects in the "
"nursery.");
KIND_HEAP, rtStats.runtime.gc.nurseryMallocedBuffers,
"Out-of-line slots and elements belonging to objects in the nursery.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/store-buffer/vals"),
KIND_HEAP, rtStats.runtime.gc.storeBufferVals,
@ -2549,7 +2552,7 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats& rtStats,
REPORT_BYTES(rtPath2 + NS_LITERAL_CSTRING("runtime/gc/nursery-decommitted"),
KIND_NONHEAP, rtStats.runtime.gc.nurseryDecommitted,
"Memory allocated to the GC's nursery this is decommitted, i.e. it takes up "
"Memory allocated to the GC's nursery that is decommitted, i.e. it takes up "
"address space but no physical memory or swap space.");
REPORT_GC_BYTES(rtPath + NS_LITERAL_CSTRING("gc-heap/unused-chunks"),

View File

@ -844,7 +844,7 @@ public:
{
return mHelper.ComputeFrameMetrics(aLayer, aContainerReferenceFrame, aParameters, aIsForCaret);
}
virtual const mozilla::DisplayItemClip* ComputeScrollClip(bool aIsForCaret) const
virtual const mozilla::DisplayItemClip* ComputeScrollClip(bool aIsForCaret) const override
{
return mHelper.ComputeScrollClip(aIsForCaret);
}
@ -1244,7 +1244,7 @@ public:
{
return mHelper.ComputeFrameMetrics(aLayer, aContainerReferenceFrame, aParameters, aIsForCaret);
}
virtual const mozilla::DisplayItemClip* ComputeScrollClip(bool aIsForCaret) const
virtual const mozilla::DisplayItemClip* ComputeScrollClip(bool aIsForCaret) const override
{
return mHelper.ComputeScrollClip(aIsForCaret);
}

View File

@ -5720,7 +5720,7 @@ nsTableFrame::CalcBCBorders()
// segments that are on the table border edges need
// to be initialized only once
bool tableBorderReset[4];
for (uint32_t sideX = eLogicalSideBStart; sideX <= eLogicalSideIStart; sideX++) {
for (uint32_t sideX = 0; sideX < ArrayLength(tableBorderReset); sideX++) {
tableBorderReset[sideX] = false;
}

View File

@ -93,7 +93,11 @@ BrowserCLH.prototype = {
};
let flags = "chrome,dialog=no,all";
browserWin = openWindow(null, "chrome://browser/content/browser.xul", "_blank", flags, args);
let chromeURL = "chrome://browser/content/browser.xul";
try {
chromeURL = Services.prefs.getCharPref("toolkit.defaultChromeURI");
} catch(e) {}
browserWin = openWindow(null, chromeURL, "_blank", flags, args);
}
aCmdLine.preventDefault = true;

View File

@ -79,7 +79,6 @@ include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'/dom/media/omx/mediaresourcemanager',
'/dom/system/android',
'/gfx/skia/trunk/include/config',
'/gfx/skia/trunk/include/core',

View File

@ -42,7 +42,7 @@ public:
return "FakeSurfaceComposer";
}
// Instantiate MediaResourceManagerService and register to service manager.
// Instantiate FakeSurfaceComposer and register to service manager.
// If service manager is not present, wait until service manager becomes present.
static void instantiate();

View File

@ -36,9 +36,6 @@
#include "GonkPermission.h"
#include "libdisplay/BootAnimation.h"
#include "nscore.h"
#ifdef MOZ_OMX_DECODER
#include "MediaResourceManagerService.h"
#endif
#include "mozilla/TouchEvents.h"
#include "mozilla/FileUtils.h"
#include "mozilla/Hal.h"
@ -890,9 +887,6 @@ nsAppShell::Init()
printf("*** This is stdout. Most of the useful output will be in logcat.\n");
printf("***\n");
printf("*****************************************************************\n");
#ifdef MOZ_OMX_DECODER
android::MediaResourceManagerService::instantiate();
#endif
#if ANDROID_VERSION >= 18 && (defined(MOZ_OMX_DECODER) || defined(MOZ_B2G_CAMERA))
android::FakeSurfaceComposer::instantiate();
#endif

View File

@ -6,8 +6,10 @@
#define GTKWINDOW_WRAPPER_H
#define gtk_window_group_get_current_grab gtk_window_group_get_current_grab_
#define gtk_window_get_window_type gtk_window_get_window_type_
#include_next <gtk/gtkwindow.h>
#undef gtk_window_group_get_current_grab
#undef gtk_window_get_window_type
static inline GtkWidget *
gtk_window_group_get_current_grab(GtkWindowGroup *window_group)
@ -17,4 +19,12 @@ gtk_window_group_get_current_grab(GtkWindowGroup *window_group)
return GTK_WIDGET(window_group->grabs->data);
}
static inline GtkWindowType
gtk_window_get_window_type(GtkWindow *window)
{
gint type;
g_object_get(window, "type", &type, (void*)NULL);
return (GtkWindowType)type;
}
#endif /* GTKWINDOW_WRAPPER_H */

View File

@ -1520,7 +1520,8 @@ nsWindow::GetClientOffset()
{
PROFILER_LABEL("nsWindow", "GetClientOffset", js::ProfileEntry::Category::GRAPHICS);
if (!mIsTopLevel) {
if (!mIsTopLevel || !mShell || !mGdkWindow ||
gtk_window_get_window_type(GTK_WINDOW(mShell)) == GTK_WINDOW_POPUP) {
return nsIntPoint(0, 0);
}
@ -1530,10 +1531,8 @@ nsWindow::GetClientOffset()
int format_returned;
int length_returned;
long *frame_extents;
GdkWindow* window;
if (!mShell || !(window = gtk_widget_get_window(mShell)) ||
!gdk_property_get(window,
if (!gdk_property_get(mGdkWindow,
gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE),
cardinal_atom,
0, // offset
@ -2360,13 +2359,9 @@ nsWindow::OnConfigureEvent(GtkWidget *aWidget, GdkEventConfigure *aEvent)
// This event indicates that the window position may have changed.
// mBounds.Size() is updated in OnSizeAllocate().
// (The gtk_window_get_window_type() function is only available from
// version 2.20.)
NS_ASSERTION(GTK_IS_WINDOW(aWidget),
"Configure event on widget that is not a GtkWindow");
gint type;
g_object_get(aWidget, "type", &type, nullptr);
if (type == GTK_WINDOW_POPUP) {
if (gtk_window_get_window_type(GTK_WINDOW(aWidget)) == GTK_WINDOW_POPUP) {
// Override-redirect window
//
// These windows should not be moved by the window manager, and so any
@ -3627,7 +3622,7 @@ nsWindow::Create(nsIWidget *aParent,
if (aInitData->mNoAutoHide) {
gint wmd = ConvertBorderStyles(mBorderStyle);
if (wmd != -1)
gdk_window_set_decorations(gtk_widget_get_window(mShell), (GdkWMDecoration) wmd);
gdk_window_set_decorations(mGdkWindow, (GdkWMDecoration) wmd);
}
// If the popup ignores mouse events, set an empty input shape.
@ -3850,8 +3845,7 @@ nsWindow::SetWindowClass(const nsAString &xulWinType)
res_name[0] = toupper(res_name[0]);
if (!role) role = res_name;
GdkWindow *shellWindow = gtk_widget_get_window(GTK_WIDGET(mShell));
gdk_window_set_role(shellWindow, role);
gdk_window_set_role(mGdkWindow, role);
#ifdef MOZ_X11
GdkDisplay *display = gdk_display_get_default();
@ -3867,7 +3861,7 @@ nsWindow::SetWindowClass(const nsAString &xulWinType)
// Can't use gtk_window_set_wmclass() for this; it prints
// a warning & refuses to make the change.
XSetClassHint(GDK_DISPLAY_XDISPLAY(display),
gdk_x11_window_get_xid(shellWindow),
gdk_x11_window_get_xid(mGdkWindow),
class_hint);
XFree(class_hint);
}
@ -4300,9 +4294,8 @@ nsWindow::ApplyTransparencyBitmap()
// We use X11 calls where possible, because GDK handles expose events
// for shaped windows in a way that's incompatible with us (Bug 635903).
// It doesn't occur when the shapes are set through X.
GdkWindow *shellWindow = gtk_widget_get_window(mShell);
Display* xDisplay = GDK_WINDOW_XDISPLAY(shellWindow);
Window xDrawable = GDK_WINDOW_XID(shellWindow);
Display* xDisplay = GDK_WINDOW_XDISPLAY(mGdkWindow);
Window xDrawable = GDK_WINDOW_XID(mGdkWindow);
Pixmap maskPixmap = XCreateBitmapFromData(xDisplay,
xDrawable,
mTransparencyBitmap,
@ -4315,7 +4308,7 @@ nsWindow::ApplyTransparencyBitmap()
#else
#if (MOZ_WIDGET_GTK == 2)
gtk_widget_reset_shapes(mShell);
GdkBitmap* maskBitmap = gdk_bitmap_create_from_data(gtk_widget_get_window(mShell),
GdkBitmap* maskBitmap = gdk_bitmap_create_from_data(mGdkWindow,
mTransparencyBitmap,
mTransparencyBitmapWidth, mTransparencyBitmapHeight);
if (!maskBitmap)
@ -4356,12 +4349,11 @@ nsWindow::ClearTransparencyBitmap()
return;
#ifdef MOZ_X11
GdkWindow *window = gtk_widget_get_window(mShell);
if (!window)
if (!mGdkWindow)
return;
Display* xDisplay = GDK_WINDOW_XDISPLAY(window);
Window xWindow = gdk_x11_window_get_xid(window);
Display* xDisplay = GDK_WINDOW_XDISPLAY(mGdkWindow);
Window xWindow = gdk_x11_window_get_xid(mGdkWindow);
XShapeCombineMask(xDisplay, xWindow, ShapeBounding, 0, 0, None, ShapeSet);
#endif
@ -4735,9 +4727,8 @@ nsWindow::HideWindowChrome(bool aShouldHide)
// confused if we change the window decorations while the window
// is visible.
bool wasVisible = false;
GdkWindow *shellWindow = gtk_widget_get_window(mShell);
if (gdk_window_is_visible(shellWindow)) {
gdk_window_hide(shellWindow);
if (gdk_window_is_visible(mGdkWindow)) {
gdk_window_hide(mGdkWindow);
wasVisible = true;
}
@ -4748,10 +4739,10 @@ nsWindow::HideWindowChrome(bool aShouldHide)
wmd = ConvertBorderStyles(mBorderStyle);
if (wmd != -1)
gdk_window_set_decorations(shellWindow, (GdkWMDecoration) wmd);
gdk_window_set_decorations(mGdkWindow, (GdkWMDecoration) wmd);
if (wasVisible)
gdk_window_show(shellWindow);
gdk_window_show(mGdkWindow);
// For some window managers, adding or removing window decorations
// requires unmapping and remapping our toplevel window. Go ahead

View File

@ -61,7 +61,8 @@ LOCAL_INCLUDES += [
# BHR disabled for Release builds because of bug 965392.
# BHR disabled for debug builds because of bug 979069.
if CONFIG['MOZ_UPDATE_CHANNEL'] not in ('release') and not CONFIG['MOZ_DEBUG']:
# BHR disabled on gonk because of bug 1180533
if CONFIG['MOZ_UPDATE_CHANNEL'] not in ('release') and not CONFIG['MOZ_DEBUG'] and not CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
DEFINES['MOZ_ENABLE_BACKGROUND_HANG_MONITOR'] = 1
FAIL_ON_WARNINGS = True