mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Merge mozilla-central to b2g-inbound
This commit is contained in:
commit
4e63bf8557
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -65,7 +65,6 @@ if CONFIG['MOZ_WEBRTC']:
|
||||
|
||||
if CONFIG['MOZ_OMX_DECODER']:
|
||||
DIRS += ['omx']
|
||||
DIRS += ['omx/mediaresourcemanager']
|
||||
|
||||
if CONFIG['MOZ_EME']:
|
||||
DIRS += ['eme']
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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*
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -94,7 +94,6 @@ LOCAL_INCLUDES += [
|
||||
'/dom/base',
|
||||
'/dom/html',
|
||||
'/ipc/chromium/src',
|
||||
'mediaresourcemanager',
|
||||
]
|
||||
|
||||
CXXFLAGS += [
|
||||
|
@ -18,7 +18,6 @@ UNIFIED_SOURCES += [
|
||||
]
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/media/omx/',
|
||||
'/dom/media/omx/mediaresourcemanager',
|
||||
]
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
|
75
dom/media/systemservices/MediaSystemResourceClient.cpp
Normal file
75
dom/media/systemservices/MediaSystemResourceClient.cpp
Normal 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
|
94
dom/media/systemservices/MediaSystemResourceClient.h
Normal file
94
dom/media/systemservices/MediaSystemResourceClient.h
Normal 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
|
425
dom/media/systemservices/MediaSystemResourceManager.cpp
Normal file
425
dom/media/systemservices/MediaSystemResourceManager.cpp
Normal 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
|
85
dom/media/systemservices/MediaSystemResourceManager.h
Normal file
85
dom/media/systemservices/MediaSystemResourceManager.h
Normal 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
|
53
dom/media/systemservices/MediaSystemResourceManagerChild.cpp
Normal file
53
dom/media/systemservices/MediaSystemResourceManagerChild.cpp
Normal 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
|
66
dom/media/systemservices/MediaSystemResourceManagerChild.h
Normal file
66
dom/media/systemservices/MediaSystemResourceManagerChild.h
Normal 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
|
@ -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
|
57
dom/media/systemservices/MediaSystemResourceManagerParent.h
Normal file
57
dom/media/systemservices/MediaSystemResourceManagerParent.h
Normal 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
|
25
dom/media/systemservices/MediaSystemResourceMessageUtils.h
Normal file
25
dom/media/systemservices/MediaSystemResourceMessageUtils.h
Normal 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
|
273
dom/media/systemservices/MediaSystemResourceService.cpp
Normal file
273
dom/media/systemservices/MediaSystemResourceService.cpp
Normal 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
|
93
dom/media/systemservices/MediaSystemResourceService.h
Normal file
93
dom/media/systemservices/MediaSystemResourceService.h
Normal 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
|
23
dom/media/systemservices/MediaSystemResourceTypes.h
Normal file
23
dom/media/systemservices/MediaSystemResourceTypes.h
Normal 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
|
37
dom/media/systemservices/PMediaSystemResourceManager.ipdl
Normal file
37
dom/media/systemservices/PMediaSystemResourceManager.ipdl
Normal 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
|
||||
|
@ -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 += [
|
||||
|
@ -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);
|
||||
|
||||
|
@ -101,6 +101,8 @@ class AudioContext final : public DOMEventTargetHelper,
|
||||
float aSampleRate = 0.0f);
|
||||
~AudioContext();
|
||||
|
||||
void Init();
|
||||
|
||||
public:
|
||||
typedef uint64_t AudioContextId;
|
||||
|
||||
|
@ -598,7 +598,7 @@ AudioDestinationNode::SetMozAudioChannelType(AudioChannel aValue, ErrorResult& a
|
||||
bool
|
||||
AudioDestinationNode::CheckAudioChannelPermissions(AudioChannel aValue)
|
||||
{
|
||||
if (!Preferences::GetBool("media.useAudioChannelService")) {
|
||||
if (!UseAudioChannelService()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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"),
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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',
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user