Bug 844248 - Add a custom media stream for camera preview. r=roc

This commit is contained in:
Sotaro Ikeda 2013-03-20 10:07:46 -04:00
parent 7c086cdcb5
commit ebcd1fab7b
6 changed files with 186 additions and 24 deletions

View File

@ -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()

View File

@ -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<VideoFrameContainer> 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<MediaStreamListener> 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<nsIRunnable> event =
NS_NewRunnableMethod(output, &VideoFrameContainer::Invalidate);
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
}
}
}

View File

@ -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

View File

@ -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> 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");

View File

@ -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<mozilla::layers::ImageContainer> mImageContainer;
VideoSegment mVideoSegment;
uint32_t mFrameCount;

View File

@ -23,6 +23,7 @@ CPPSRCS = \
DOMCameraCapabilities.cpp \
CameraControlImpl.cpp \
CameraRecorderProfiles.cpp \
CameraPreviewMediaStream.cpp \
$(NULL)
ifeq ($(MOZ_B2G_CAMERA),1)