From 192f030a706e84dba6ce05af77766d20a1743b86 Mon Sep 17 00:00:00 2001 From: Sotaro Ikeda Date: Wed, 20 Mar 2013 10:07:46 -0400 Subject: [PATCH] Bug 844248 - Add a custom media stream for camera preview. r=roc --- content/media/MediaStreamGraph.h | 18 ++-- dom/camera/CameraPreviewMediaStream.cpp | 111 ++++++++++++++++++++++++ dom/camera/CameraPreviewMediaStream.h | 55 ++++++++++++ dom/camera/DOMCameraPreview.cpp | 22 ++--- dom/camera/DOMCameraPreview.h | 3 +- dom/camera/Makefile.in | 1 + 6 files changed, 186 insertions(+), 24 deletions(-) create mode 100644 dom/camera/CameraPreviewMediaStream.cpp create mode 100644 dom/camera/CameraPreviewMediaStream.h diff --git a/content/media/MediaStreamGraph.h b/content/media/MediaStreamGraph.h index 06105d4e5de3..2473a95f4cce 100644 --- a/content/media/MediaStreamGraph.h +++ b/content/media/MediaStreamGraph.h @@ -303,20 +303,20 @@ public: // a single audio output stream is used; the volumes are combined. // Currently only the first enabled audio track is played. // XXX change this so all enabled audio tracks are mixed and played. - void AddAudioOutput(void* aKey); - void SetAudioOutputVolume(void* aKey, float aVolume); - void RemoveAudioOutput(void* aKey); + virtual void AddAudioOutput(void* aKey); + virtual void SetAudioOutputVolume(void* aKey, float aVolume); + virtual void RemoveAudioOutput(void* aKey); // Since a stream can be played multiple ways, we need to be able to // play to multiple VideoFrameContainers. // Only the first enabled video track is played. - void AddVideoOutput(VideoFrameContainer* aContainer); - void RemoveVideoOutput(VideoFrameContainer* aContainer); + virtual void AddVideoOutput(VideoFrameContainer* aContainer); + virtual void RemoveVideoOutput(VideoFrameContainer* aContainer); // Explicitly block. Useful for example if a media element is pausing // and we need to stop its stream emitting its buffered data. - void ChangeExplicitBlockerCount(int32_t aDelta); + virtual void ChangeExplicitBlockerCount(int32_t aDelta); // Events will be dispatched by calling methods of aListener. - void AddListener(MediaStreamListener* aListener); - void RemoveListener(MediaStreamListener* aListener); + virtual void AddListener(MediaStreamListener* aListener); + virtual void RemoveListener(MediaStreamListener* aListener); // Events will be dispatched by calling methods of aListener. It is the // responsibility of the caller to remove aListener before it is destroyed. void AddMainThreadListener(MainThreadMediaStreamListener* aListener) @@ -332,7 +332,7 @@ public: mMainThreadListeners.RemoveElement(aListener); } // Signal that the client is done with this MediaStream. It will be deleted later. - void Destroy(); + virtual void Destroy(); // Returns the main-thread's view of how much data has been processed by // this stream. StreamTime GetCurrentTime() diff --git a/dom/camera/CameraPreviewMediaStream.cpp b/dom/camera/CameraPreviewMediaStream.cpp new file mode 100644 index 000000000000..24fdcf595f82 --- /dev/null +++ b/dom/camera/CameraPreviewMediaStream.cpp @@ -0,0 +1,111 @@ +/* -*- 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 "CameraPreviewMediaStream.h" + +using namespace mozilla::layers; +using namespace mozilla::dom; + +namespace mozilla { + +void +CameraPreviewMediaStream::AddAudioOutput(void* aKey) +{ +} + +void +CameraPreviewMediaStream::SetAudioOutputVolume(void* aKey, float aVolume) +{ +} + +void +CameraPreviewMediaStream::RemoveAudioOutput(void* aKey) +{ +} + +void +CameraPreviewMediaStream::AddVideoOutput(VideoFrameContainer* aContainer) +{ + MutexAutoLock lock(mMutex); + nsRefPtr container = aContainer; + AddVideoOutputImpl(container.forget()); + + if (mVideoOutputs.Length() > 1) { + return; + } + MediaStreamGraph* gm = MediaStreamGraph::GetInstance(); + mIsConsumed = true; + for (uint32_t j = 0; j < mListeners.Length(); ++j) { + MediaStreamListener* l = mListeners[j]; + l->NotifyConsumptionChanged(gm, MediaStreamListener::CONSUMED); + } +} + +void +CameraPreviewMediaStream::RemoveVideoOutput(VideoFrameContainer* aContainer) +{ + MutexAutoLock lock(mMutex); + RemoveVideoOutputImpl(aContainer); + + if (!mVideoOutputs.IsEmpty()) { + return; + } + MediaStreamGraph* gm = MediaStreamGraph::GetInstance(); + mIsConsumed = false; + for (uint32_t j = 0; j < mListeners.Length(); ++j) { + MediaStreamListener* l = mListeners[j]; + l->NotifyConsumptionChanged(gm, MediaStreamListener::NOT_CONSUMED); + } +} + +void +CameraPreviewMediaStream::ChangeExplicitBlockerCount(int32_t aDelta) +{ +} + +void +CameraPreviewMediaStream::AddListener(MediaStreamListener* aListener) +{ + MutexAutoLock lock(mMutex); + + MediaStreamGraph* gm = MediaStreamGraph::GetInstance(); + MediaStreamListener* listener = *mListeners.AppendElement() = aListener; + listener->NotifyBlockingChanged(gm, MediaStreamListener::UNBLOCKED); +} + +void +CameraPreviewMediaStream::RemoveListener(MediaStreamListener* aListener) +{ + MutexAutoLock lock(mMutex); + + MediaStreamGraph* gm = MediaStreamGraph::GetInstance(); + nsRefPtr listener(aListener); + mListeners.RemoveElement(aListener); + listener->NotifyRemoved(gm); +} + +void +CameraPreviewMediaStream::Destroy() +{ + MutexAutoLock lock(mMutex); + DestroyImpl(); +} + +void +CameraPreviewMediaStream::SetCurrentFrame(const gfxIntSize& aIntrinsicSize, Image* aImage) +{ + MutexAutoLock lock(mMutex); + + TimeStamp now = TimeStamp::Now(); + for (uint32_t i = 0; i < mVideoOutputs.Length(); ++i) { + VideoFrameContainer* output = mVideoOutputs[i]; + output->SetCurrentFrame(aIntrinsicSize, aImage, now); + nsCOMPtr event = + NS_NewRunnableMethod(output, &VideoFrameContainer::Invalidate); + NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); + } +} + +} diff --git a/dom/camera/CameraPreviewMediaStream.h b/dom/camera/CameraPreviewMediaStream.h new file mode 100644 index 000000000000..ea9c0f71c72c --- /dev/null +++ b/dom/camera/CameraPreviewMediaStream.h @@ -0,0 +1,55 @@ +/* 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 DOM_CAMERA_CAMERAPREVIEWMEDIASTREAM_H +#define DOM_CAMERA_CAMERAPREVIEWMEDIASTREAM_H + +#include "VideoFrameContainer.h" +#include "MediaStreamGraph.h" +#include "mozilla/Mutex.h" + +namespace mozilla { + +/** + * This is a stream for camere preview. + * + * XXX It is a temporary fix of SourceMediaStream. + * A camera preview requests no delay and no buffering stream. + * But the SourceMediaStream do not support it. + */ +class CameraPreviewMediaStream : public MediaStream { + typedef mozilla::layers::Image Image; + +public: + CameraPreviewMediaStream(DOMMediaStream* aWrapper) : + MediaStream(aWrapper), + mMutex("mozilla::camera::CameraPreviewMediaStream") + { + mIsConsumed = false; + } + + virtual void AddAudioOutput(void* aKey); + virtual void SetAudioOutputVolume(void* aKey, float aVolume); + virtual void RemoveAudioOutput(void* aKey); + virtual void AddVideoOutput(VideoFrameContainer* aContainer); + virtual void RemoveVideoOutput(VideoFrameContainer* aContainer); + virtual void ChangeExplicitBlockerCount(int32_t aDelta); + virtual void AddListener(MediaStreamListener* aListener); + virtual void RemoveListener(MediaStreamListener* aListener); + virtual void Destroy(); + + // Call these on any thread. + void SetCurrentFrame(const gfxIntSize& aIntrinsicSize, Image* aImage); + +protected: + // mMutex protects all the class' fields. + // This class is not registered to MediaStreamGraph. + // It needs to protect all the fields. + Mutex mMutex; +}; + + +} + +#endif // DOM_CAMERA_CAMERAPREVIEWMEDIASTREAM_H diff --git a/dom/camera/DOMCameraPreview.cpp b/dom/camera/DOMCameraPreview.cpp index 72427129402c..a5fd96e2f682 100644 --- a/dom/camera/DOMCameraPreview.cpp +++ b/dom/camera/DOMCameraPreview.cpp @@ -155,17 +155,13 @@ DOMCameraPreview::DOMCameraPreview(nsGlobalWindow* aWindow, DOM_CAMERA_LOGT("%s:%d : this=%p : mWidth=%d, mHeight=%d, mFramesPerSecond=%d\n", __func__, __LINE__, this, mWidth, mHeight, mFramesPerSecond); mImageContainer = LayerManager::CreateImageContainer(); - MediaStreamGraph* gm = MediaStreamGraph::GetInstance(); - mStream = gm->CreateSourceStream(this); mWindow = aWindow; - mInput = GetStream()->AsSourceStream(); + mInput = new CameraPreviewMediaStream(this); + mStream = mInput; mListener = new DOMCameraPreviewListener(this); mInput->AddListener(mListener); - mInput->AddTrack(TRACK_VIDEO, mFramesPerSecond, 0, new VideoSegment()); - mInput->AdvanceKnownTracksTime(MEDIA_TIME_MAX); - if (aWindow->GetExtantDoc()) { CombineWithPrincipal(aWindow->GetExtantDoc()->NodePrincipal()); } @@ -180,7 +176,7 @@ DOMCameraPreview::~DOMCameraPreview() bool DOMCameraPreview::HaveEnoughBuffered() { - return mInput->HaveEnoughBuffered(TRACK_VIDEO); + return true; } bool @@ -198,9 +194,7 @@ DOMCameraPreview::ReceiveFrame(void* aBuffer, ImageFormat aFormat, FrameBuilder nsRefPtr image = mImageContainer->CreateImage(&format, 1); aBuilder(image, aBuffer, mWidth, mHeight); - // AppendFrame() takes over image's reference - mVideoSegment.AppendFrame(image.forget(), 1, gfxIntSize(mWidth, mHeight)); - mInput->AppendToTrack(TRACK_VIDEO, &mVideoSegment); + mInput->SetCurrentFrame(gfxIntSize(mWidth, mHeight), image); return true; } @@ -261,8 +255,8 @@ DOMCameraPreview::StopPreview() DOM_CAMERA_LOGI("Stopping preview stream\n"); DOM_CAMERA_SETSTATE(STOPPING); mCameraControl->StopPreview(); - mInput->EndTrack(TRACK_VIDEO); - mInput->Finish(); + //mInput->EndTrack(TRACK_VIDEO); + //mInput->Finish(); } void @@ -272,8 +266,8 @@ DOMCameraPreview::SetStateStopped() // see bug 809259 and bug 817367. if (mState != STOPPING) { - mInput->EndTrack(TRACK_VIDEO); - mInput->Finish(); + //mInput->EndTrack(TRACK_VIDEO); + //mInput->Finish(); } DOM_CAMERA_SETSTATE(STOPPED); DOM_CAMERA_LOGI("Preview stream stopped\n"); diff --git a/dom/camera/DOMCameraPreview.h b/dom/camera/DOMCameraPreview.h index c43d0a055b72..96ffad40ae03 100644 --- a/dom/camera/DOMCameraPreview.h +++ b/dom/camera/DOMCameraPreview.h @@ -10,6 +10,7 @@ #include "StreamBuffer.h" #include "ICameraControl.h" #include "DOMMediaStream.h" +#include "CameraPreviewMediaStream.h" #include "CameraCommon.h" class nsGlobalWindow; @@ -77,7 +78,7 @@ protected: uint32_t mWidth; uint32_t mHeight; uint32_t mFramesPerSecond; - SourceMediaStream* mInput; + CameraPreviewMediaStream* mInput; nsRefPtr mImageContainer; VideoSegment mVideoSegment; uint32_t mFrameCount; diff --git a/dom/camera/Makefile.in b/dom/camera/Makefile.in index 97288a6bd430..065b495d1893 100644 --- a/dom/camera/Makefile.in +++ b/dom/camera/Makefile.in @@ -23,6 +23,7 @@ CPPSRCS = \ DOMCameraCapabilities.cpp \ CameraControlImpl.cpp \ CameraRecorderProfiles.cpp \ + CameraPreviewMediaStream.cpp \ $(NULL) ifeq ($(MOZ_B2G_CAMERA),1)