gecko/netwerk/protocol/device/GonkCaptureProvider.cpp
Chris Pearce 9abb830db0 Bug 811381 - Remove ns prefix from media code. r=roc
--HG--
rename : content/media/nsAudioAvailableEventManager.cpp => content/media/AudioAvailableEventManager.cpp
rename : content/media/nsAudioAvailableEventManager.h => content/media/AudioAvailableEventManager.h
rename : content/media/nsAudioStream.cpp => content/media/AudioStream.cpp
rename : content/media/nsAudioStream.h => content/media/AudioStream.h
rename : content/media/nsMediaCache.cpp => content/media/MediaCache.cpp
rename : content/media/nsMediaCache.h => content/media/MediaCache.h
rename : content/media/nsBuiltinDecoder.cpp => content/media/MediaDecoder.cpp
rename : content/media/nsBuiltinDecoder.h => content/media/MediaDecoder.h
rename : content/media/nsBuiltinDecoderReader.cpp => content/media/MediaDecoderReader.cpp
rename : content/media/nsBuiltinDecoderReader.h => content/media/MediaDecoderReader.h
rename : content/media/nsBuiltinDecoderStateMachine.cpp => content/media/MediaDecoderStateMachine.cpp
rename : content/media/nsBuiltinDecoderStateMachine.h => content/media/MediaDecoderStateMachine.h
rename : content/media/dash/nsDASHDecoder.cpp => content/media/dash/DASHDecoder.cpp
rename : content/media/dash/nsDASHDecoder.h => content/media/dash/DASHDecoder.h
rename : content/media/dash/nsDASHReader.cpp => content/media/dash/DASHReader.cpp
rename : content/media/dash/nsDASHReader.h => content/media/dash/DASHReader.h
rename : content/media/dash/nsDASHRepDecoder.cpp => content/media/dash/DASHRepDecoder.cpp
rename : content/media/dash/nsDASHRepDecoder.h => content/media/dash/DASHRepDecoder.h
rename : content/media/gstreamer/nsGStreamerDecoder.cpp => content/media/gstreamer/GStreamerDecoder.cpp
rename : content/media/gstreamer/nsGStreamerDecoder.h => content/media/gstreamer/GStreamerDecoder.h
rename : content/media/gstreamer/nsGStreamerReader.cpp => content/media/gstreamer/GStreamerReader.cpp
rename : content/media/gstreamer/nsGStreamerReader.h => content/media/gstreamer/GStreamerReader.h
rename : content/media/ogg/nsOggCodecState.cpp => content/media/ogg/OggCodecState.cpp
rename : content/media/ogg/nsOggCodecState.h => content/media/ogg/OggCodecState.h
rename : content/media/ogg/nsOggDecoder.cpp => content/media/ogg/OggDecoder.cpp
rename : content/media/ogg/nsOggDecoder.h => content/media/ogg/OggDecoder.h
rename : content/media/ogg/nsOggReader.cpp => content/media/ogg/OggReader.cpp
rename : content/media/ogg/nsOggReader.h => content/media/ogg/OggReader.h
rename : content/media/omx/nsMediaOmxDecoder.cpp => content/media/omx/MediaOmxDecoder.cpp
rename : content/media/omx/nsMediaOmxDecoder.h => content/media/omx/MediaOmxDecoder.h
rename : content/media/omx/nsMediaOmxReader.cpp => content/media/omx/MediaOmxReader.cpp
rename : content/media/omx/nsMediaOmxReader.h => content/media/omx/MediaOmxReader.h
rename : content/media/plugins/nsMediaPluginDecoder.cpp => content/media/plugins/MediaPluginDecoder.cpp
rename : content/media/plugins/nsMediaPluginDecoder.h => content/media/plugins/MediaPluginDecoder.h
rename : content/media/plugins/nsMediaPluginHost.cpp => content/media/plugins/MediaPluginHost.cpp
rename : content/media/plugins/nsMediaPluginHost.h => content/media/plugins/MediaPluginHost.h
rename : content/media/plugins/nsMediaPluginReader.cpp => content/media/plugins/MediaPluginReader.cpp
rename : content/media/plugins/nsMediaPluginReader.h => content/media/plugins/MediaPluginReader.h
rename : content/media/raw/nsRawDecoder.cpp => content/media/raw/RawDecoder.cpp
rename : content/media/raw/nsRawDecoder.h => content/media/raw/RawDecoder.h
rename : content/media/raw/nsRawReader.cpp => content/media/raw/RawReader.cpp
rename : content/media/raw/nsRawReader.h => content/media/raw/RawReader.h
rename : content/media/raw/nsRawStructs.h => content/media/raw/RawStructs.h
rename : content/media/wave/nsWaveDecoder.cpp => content/media/wave/WaveDecoder.cpp
rename : content/media/wave/nsWaveDecoder.h => content/media/wave/WaveDecoder.h
rename : content/media/wave/nsWaveReader.cpp => content/media/wave/WaveReader.cpp
rename : content/media/wave/nsWaveReader.h => content/media/wave/WaveReader.h
rename : content/media/webm/nsWebMBufferedParser.cpp => content/media/webm/WebMBufferedParser.cpp
rename : content/media/webm/nsWebMBufferedParser.h => content/media/webm/WebMBufferedParser.h
rename : content/media/webm/nsWebMDecoder.cpp => content/media/webm/WebMDecoder.cpp
rename : content/media/webm/nsWebMDecoder.h => content/media/webm/WebMDecoder.h
rename : content/media/webm/nsWebMReader.cpp => content/media/webm/WebMReader.cpp
rename : content/media/webm/nsWebMReader.h => content/media/webm/WebMReader.h
2012-11-14 11:46:40 -08:00

594 lines
16 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
*
* 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.
*/
#include <dlfcn.h>
#include "android/log.h"
#include "cutils/properties.h"
#include "base/basictypes.h"
#include "GonkCaptureProvider.h"
#include "nsXULAppAPI.h"
#include "nsStreamUtils.h"
#include "nsThreadUtils.h"
#include "RawStructs.h"
#include "prinit.h"
#define USE_GS2_LIBCAMERA
#define CameraHardwareInterface CameraHardwareInterface_SGS2
#define HAL_openCameraHardware HAL_openCameraHardware_SGS2
#include "gonk/CameraHardwareInterface.h"
#undef CameraHardwareInterface
#undef USE_GS2_LIBCAMERA
#undef HAL_openCameraHardware
#undef ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
// Needed to prevent a redefinition of 'struct android::image_rect_struct'...
#define image_rect_type image_rect_type2
#define image_rect_struct image_rect_struct2
#define USE_MAGURO_LIBCAMERA
#define CameraHardwareInterface CameraHardwareInterface_MAGURO
#define HAL_openCameraHardware HAL_openCameraHardware_MAGURO
#include "gonk/CameraHardwareInterface.h"
#undef CameraHardwareInterface
#undef USE_MAGURO_LIBCAMERA
#undef HAL_openCameraHardware
#undef ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
#undef image_rect_type
#undef image_rect_struct
#define image_rect_type image_rect_type3
#define image_rect_struct image_rect_struct3
#define CameraHardwareInterface CameraHardwareInterface_DEFAULT
#include "gonk/CameraHardwareInterface.h"
#undef CameraHardwareInterface
using namespace android;
using namespace mozilla;
class CameraHardwareInterface {
public:
enum Type {
CAMERA_SGS2,
CAMERA_MAGURO,
CAMERA_DEFAULT
};
static Type getType() {
char propValue[PROPERTY_VALUE_MAX];
property_get("ro.product.board", propValue, NULL);
if (!strcmp(propValue, "GT-I9100"))
return CAMERA_SGS2;
if (!strcmp(propValue, "msm7627a_sku1") || !strcmp(propValue, "MSM7627A_SKU3"))
return CAMERA_MAGURO;
printf_stderr("CameraHardwareInterface : unsupported camera for device %s\n", propValue);
return CAMERA_DEFAULT;
}
static CameraHardwareInterface* openCamera(uint32_t aCamera);
virtual ~CameraHardwareInterface() { }
virtual bool ok() = 0;
virtual void enableMsgType(int32_t msgType) = 0;
virtual void disableMsgType(int32_t msgType) = 0;
virtual bool msgTypeEnabled(int32_t msgType) = 0;
virtual void setCallbacks(notify_callback notify_cb,
data_callback data_cb,
data_callback_timestamp data_cb_timestamp,
void* user) = 0;
virtual status_t startPreview() = 0;
virtual void stopPreview() = 0;
virtual void release() = 0;
virtual status_t setParameters(const CameraParameters& params) = 0;
virtual CameraParameters getParameters() const = 0;
protected:
CameraHardwareInterface(uint32_t aCamera = 0) { };
};
// Intentionally not trying to dlclose() this handle. That's playing
// Russian roulette with security bugs.
static void* sCameraLib;
static PRCallOnceType sInitCameraLib;
static PRStatus
InitCameraLib()
{
sCameraLib = dlopen("/system/lib/libcamera.so", RTLD_LAZY);
// We might fail to open the camera lib. That's OK.
return PR_SUCCESS;
}
static void*
GetCameraLibHandle()
{
PR_CallOnce(&sInitCameraLib, InitCameraLib);
return sCameraLib;
}
template<class T> class CameraImpl : public CameraHardwareInterface {
public:
typedef sp<T> (*HAL_openCameraHardware_DEFAULT)(int);
typedef sp<T> (*HAL_openCameraHardware_SGS2)(int);
typedef sp<T> (*HAL_openCameraHardware_MAGURO)(int, int);
CameraImpl(uint32_t aCamera = 0) : mOk(false), mCamera(nullptr) {
void* cameraLib = GetCameraLibHandle();
if (!cameraLib) {
printf_stderr("CameraImpl: Failed to dlopen() camera library.");
return;
}
void *hal = dlsym(cameraLib, "HAL_openCameraHardware");
HAL_openCameraHardware_DEFAULT funct0;
HAL_openCameraHardware_SGS2 funct1;
HAL_openCameraHardware_MAGURO funct2;
switch(getType()) {
case CAMERA_SGS2:
funct1 = reinterpret_cast<HAL_openCameraHardware_SGS2> (hal);
mCamera = funct1(aCamera);
break;
case CAMERA_MAGURO:
funct2 = reinterpret_cast<HAL_openCameraHardware_MAGURO> (hal);
mCamera = funct2(aCamera, 1);
break;
case CAMERA_DEFAULT:
funct0 = reinterpret_cast<HAL_openCameraHardware_DEFAULT> (hal);
mCamera = funct0(aCamera);
break;
}
mOk = mCamera != nullptr;
if (!mOk) {
printf_stderr("CameraImpl: HAL_openCameraHardware() returned NULL (no camera interface).");
}
}
bool ok() {
return mOk;
};
void enableMsgType(int32_t msgType) {
mCamera->enableMsgType(msgType);
};
void disableMsgType(int32_t msgType) {
mCamera->disableMsgType(msgType);
};
bool msgTypeEnabled(int32_t msgType) {
return mCamera->msgTypeEnabled(msgType);
};
void setCallbacks(notify_callback notify_cb,
data_callback data_cb,
data_callback_timestamp data_cb_timestamp,
void* user) {
mCamera->setCallbacks(notify_cb, data_cb, data_cb_timestamp, user);
};
status_t startPreview() {
return mCamera->startPreview();
};
void stopPreview() {
mCamera->stopPreview();
};
void release() {
return mCamera->release();
};
status_t setParameters(const CameraParameters& params) {
return mCamera->setParameters(params);
}
CameraParameters getParameters() const {
return mCamera->getParameters();
};
protected:
bool mOk;
sp<T> mCamera;
};
CameraHardwareInterface* CameraHardwareInterface::openCamera(uint32_t aCamera) {
nsAutoPtr<CameraHardwareInterface> instance;
switch(getType()) {
case CAMERA_SGS2:
instance = new CameraImpl<CameraHardwareInterface_SGS2>(aCamera);
break;
case CAMERA_MAGURO:
instance = new CameraImpl<CameraHardwareInterface_MAGURO>(aCamera);
break;
case CAMERA_DEFAULT:
instance = new CameraImpl<CameraHardwareInterface_DEFAULT>(aCamera);
break;
}
if (!instance->ok()) {
return nullptr;
}
return instance.forget();
};
// The maximum number of frames we keep in our queue. Don't live in the past.
#define MAX_FRAMES_QUEUED 5
NS_IMPL_THREADSAFE_ISUPPORTS2(GonkCameraInputStream, nsIInputStream, nsIAsyncInputStream)
GonkCameraInputStream::GonkCameraInputStream() :
mAvailable(sizeof(RawVideoHeader)), mWidth(0), mHeight(0), mFps(30), mCamera(0),
mHeaderSent(false), mClosed(true), mIs420p(false), mFrameSize(0), mMonitor("GonkCamera.Monitor")
{
}
GonkCameraInputStream::~GonkCameraInputStream() {
// clear the frame queue
while (mFrameQueue.GetSize() > 0) {
free(mFrameQueue.PopFront());
}
// no need to close Close() since the stream is opened here :
// http://mxr.mozilla.org/mozilla-central/source/netwerk/base/src/nsBaseChannel.cpp#239
// and this leads to http://mxr.mozilla.org/mozilla-central/source/netwerk/base/src/nsBaseChannel.cpp#259
// that creates and input pump with closeWhenDone == true
// the pump cleans up properly at http://mxr.mozilla.org/mozilla-central/source/netwerk/base/src/nsInputStreamPump.cpp#565
}
void
GonkCameraInputStream::DataCallback(int32_t aMsgType, const sp<IMemory>& aDataPtr, void *aUser) {
GonkCameraInputStream* stream = (GonkCameraInputStream*)(aUser);
stream->ReceiveFrame((char*)aDataPtr->pointer(), aDataPtr->size());
}
uint32_t
GonkCameraInputStream::getNumberOfCameras() {
typedef int (*HAL_getNumberOfCamerasFunct)(void);
void* cameraLib = GetCameraLibHandle();
if (!cameraLib)
return 0;
void *hal = dlsym(cameraLib, "HAL_getNumberOfCameras");
if (nullptr == hal)
return 0;
HAL_getNumberOfCamerasFunct funct = reinterpret_cast<HAL_getNumberOfCamerasFunct> (hal);
return funct();
}
NS_IMETHODIMP
GonkCameraInputStream::Init(nsACString& aContentType, nsCaptureParams* aParams)
{
if (XRE_GetProcessType() != GeckoProcessType_Default)
return NS_ERROR_NOT_IMPLEMENTED;
mContentType = aContentType;
mWidth = aParams->width;
mHeight = aParams->height;
mCamera = aParams->camera;
uint32_t maxNumCameras = getNumberOfCameras();
if (maxNumCameras == 0)
return NS_ERROR_FAILURE;
if (mCamera >= maxNumCameras)
mCamera = 0;
mHardware = CameraHardwareInterface::openCamera(mCamera);
if (!mHardware)
return NS_ERROR_FAILURE;
mHardware->setCallbacks(NULL, GonkCameraInputStream::DataCallback, NULL, this);
mHardware->enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
CameraParameters params = mHardware->getParameters();
printf_stderr("Preview format : %s\n", params.get(params.KEY_SUPPORTED_PREVIEW_FORMATS));
Vector<Size> previewSizes;
params.getSupportedPreviewSizes(previewSizes);
// find the available preview size closest to the requested size.
uint32_t minSizeDelta = UINT32_MAX;
uint32_t bestWidth = mWidth;
uint32_t bestHeight = mHeight;
for (uint32_t i = 0; i < previewSizes.size(); i++) {
Size size = previewSizes[i];
uint32_t delta = abs(size.width * size.height - mWidth * mHeight);
if (delta < minSizeDelta) {
minSizeDelta = delta;
bestWidth = size.width;
bestHeight = size.height;
}
}
mWidth = bestWidth;
mHeight = bestHeight;
params.setPreviewSize(mWidth, mHeight);
// try to set preferred image format
params.setPreviewFormat("yuv420p");
params.setPreviewFrameRate(mFps);
mHardware->setParameters(params);
params = mHardware->getParameters();
mFps = params.getPreviewFrameRate();
mIs420p = !strcmp(params.getPreviewFormat(), "yuv420p");
mHardware->startPreview();
mClosed = false;
return NS_OK;
}
void
GonkCameraInputStream::ReceiveFrame(char* frame, uint32_t length) {
{
ReentrantMonitorAutoEnter enter(mMonitor);
if (mFrameQueue.GetSize() > MAX_FRAMES_QUEUED) {
free(mFrameQueue.PopFront());
mAvailable -= mFrameSize;
}
}
mFrameSize = sizeof(RawPacketHeader) + length;
char* fullFrame = (char*)moz_malloc(mFrameSize);
if (!fullFrame)
return;
RawPacketHeader* header = reinterpret_cast<RawPacketHeader*> (fullFrame);
header->packetID = 0xFF;
header->codecID = RAW_ID;
if (mIs420p) {
memcpy(fullFrame + sizeof(RawPacketHeader), frame, length);
} else {
// we copy the Y plane, and de-interlace the CrCb
uint32_t yFrameSize = mWidth * mHeight;
uint32_t uvFrameSize = yFrameSize / 4;
memcpy(fullFrame + sizeof(RawPacketHeader), frame, yFrameSize);
char* uFrame = fullFrame + sizeof(RawPacketHeader) + yFrameSize;
char* vFrame = fullFrame + sizeof(RawPacketHeader) + yFrameSize + uvFrameSize;
const char* yFrame = frame + yFrameSize;
for (uint32_t i = 0; i < uvFrameSize; i++) {
uFrame[i] = yFrame[2 * i + 1];
vFrame[i] = yFrame[2 * i];
}
}
{
ReentrantMonitorAutoEnter enter(mMonitor);
mAvailable += mFrameSize;
mFrameQueue.Push((void*)fullFrame);
}
NotifyListeners();
}
NS_IMETHODIMP
GonkCameraInputStream::Available(uint64_t *aAvailable)
{
ReentrantMonitorAutoEnter enter(mMonitor);
*aAvailable = mAvailable;
return NS_OK;
}
NS_IMETHODIMP GonkCameraInputStream::IsNonBlocking(bool *aNonBlock) {
*aNonBlock = true;
return NS_OK;
}
NS_IMETHODIMP GonkCameraInputStream::Read(char *aBuffer, uint32_t aCount, uint32_t *aRead) {
return ReadSegments(NS_CopySegmentToBuffer, aBuffer, aCount, aRead);
}
NS_IMETHODIMP GonkCameraInputStream::ReadSegments(nsWriteSegmentFun aWriter, void *aClosure, uint32_t aCount, uint32_t *aRead) {
*aRead = 0;
nsresult rv;
if (mAvailable == 0)
return NS_BASE_STREAM_WOULD_BLOCK;
if (aCount > mAvailable)
aCount = mAvailable;
if (!mHeaderSent) {
RawVideoHeader header;
header.headerPacketID = 0;
header.codecID = RAW_ID;
header.majorVersion = 0;
header.minorVersion = 1;
header.options = 1 | 1 << 1; // color, 4:2:0
header.alphaChannelBpp = 0;
header.lumaChannelBpp = 8;
header.chromaChannelBpp = 4;
header.colorspace = 1;
header.frameWidth = mWidth;
header.frameHeight = mHeight;
header.aspectNumerator = 1;
header.aspectDenominator = 1;
header.framerateNumerator = mFps;
header.framerateDenominator = 1;
rv = aWriter(this, aClosure, (const char*)&header, 0, sizeof(RawVideoHeader), aRead);
if (NS_FAILED(rv))
return NS_OK;
mHeaderSent = true;
aCount -= sizeof(RawVideoHeader);
mAvailable -= sizeof(RawVideoHeader);
}
{
ReentrantMonitorAutoEnter enter(mMonitor);
while ((mAvailable > 0) && (aCount >= mFrameSize)) {
uint32_t readThisTime = 0;
char* frame = (char*)mFrameQueue.PopFront();
rv = aWriter(this, aClosure, (const char*)frame, *aRead, mFrameSize, &readThisTime);
if (readThisTime != mFrameSize) {
mFrameQueue.PushFront((void*)frame);
return NS_OK;
}
// RawReader does a copy when calling VideoData::Create()
free(frame);
if (NS_FAILED(rv))
return NS_OK;
aCount -= readThisTime;
mAvailable -= readThisTime;
*aRead += readThisTime;
}
}
return NS_OK;
}
NS_IMETHODIMP GonkCameraInputStream::Close() {
return CloseWithStatus(NS_OK);
}
void GonkCameraInputStream::doClose() {
ReentrantMonitorAutoEnter enter(mMonitor);
if (mClosed)
return;
mHardware->disableMsgType(CAMERA_MSG_ALL_MSGS);
mHardware->stopPreview();
mHardware->release();
delete mHardware;
mClosed = true;
}
void GonkCameraInputStream::NotifyListeners() {
ReentrantMonitorAutoEnter enter(mMonitor);
if (mCallback && (mAvailable > sizeof(RawVideoHeader))) {
nsCOMPtr<nsIInputStreamCallback> callback;
if (mCallbackTarget) {
NS_NewInputStreamReadyEvent(getter_AddRefs(callback), mCallback, mCallbackTarget);
} else {
callback = mCallback;
}
NS_ASSERTION(callback, "Shouldn't fail to make the callback!");
// Null the callback first because OnInputStreamReady may reenter AsyncWait
mCallback = nullptr;
mCallbackTarget = nullptr;
callback->OnInputStreamReady(this);
}
}
NS_IMETHODIMP GonkCameraInputStream::AsyncWait(nsIInputStreamCallback *aCallback, uint32_t aFlags, uint32_t aRequestedCount, nsIEventTarget *aTarget)
{
if (aFlags != 0)
return NS_ERROR_NOT_IMPLEMENTED;
if (mCallback || mCallbackTarget)
return NS_ERROR_UNEXPECTED;
mCallbackTarget = aTarget;
mCallback = aCallback;
// What we are being asked for may be present already
NotifyListeners();
return NS_OK;
}
NS_IMETHODIMP GonkCameraInputStream::CloseWithStatus(nsresult status)
{
GonkCameraInputStream::doClose();
return NS_OK;
}
/**
* GonkCaptureProvider implementation
*/
NS_IMPL_ISUPPORTS0(GonkCaptureProvider)
GonkCaptureProvider* GonkCaptureProvider::sInstance = NULL;
GonkCaptureProvider::GonkCaptureProvider() {
}
GonkCaptureProvider::~GonkCaptureProvider() {
GonkCaptureProvider::sInstance = NULL;
}
nsresult GonkCaptureProvider::Init(nsACString& aContentType,
nsCaptureParams* aParams,
nsIInputStream** aStream) {
NS_ENSURE_ARG_POINTER(aParams);
NS_ASSERTION(aParams->frameLimit == 0 || aParams->timeLimit == 0,
"Cannot set both a frame limit and a time limit!");
nsRefPtr<GonkCameraInputStream> stream;
if (aContentType.EqualsLiteral("video/x-raw-yuv")) {
stream = new GonkCameraInputStream();
if (stream) {
nsresult rv = stream->Init(aContentType, aParams);
if (NS_FAILED(rv))
return rv;
}
else {
return NS_ERROR_OUT_OF_MEMORY;
}
} else {
NS_NOTREACHED("Should not have asked Gonk for this type!");
}
return CallQueryInterface(stream, aStream);
}
already_AddRefed<GonkCaptureProvider> GetGonkCaptureProvider() {
if (!GonkCaptureProvider::sInstance) {
GonkCaptureProvider::sInstance = new GonkCaptureProvider();
}
GonkCaptureProvider::sInstance->AddRef();
return GonkCaptureProvider::sInstance;
}