Merge mozilla-central and b2g-inbound

This commit is contained in:
Ed Morley 2013-09-12 12:09:58 +01:00
commit ffcffb51c7
30 changed files with 3861 additions and 528 deletions

View File

@ -318,7 +318,9 @@ let AdbController = {
// Check if we have a remote debugging session going on. If so, we won't
// disable adb even if the screen is locked.
let isDebugging = Object.keys(DebuggerServer._connections).length > 0;
this.debug("isDebugging=" + isDebugging);
if (this.DEBUG) {
this.debug("isDebugging=" + isDebugging);
}
let enableAdb = this.remoteDebuggerEnabled &&
(!(this.lockEnabled && this.locked) || isDebugging);

View File

@ -9,8 +9,17 @@ this.EXPORTED_SYMBOLS = ["WebappsUpdater"];
const Cc = Components.classes;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "settings",
"@mozilla.org/settingsService;1",
"nsISettingsService");
function debug(aStr) {
//dump("--*-- WebappsUpdater: " + aStr);
}
this.WebappsUpdater = {
_checkingApps: false,
_pendingEvents: [],
@ -29,7 +38,7 @@ this.WebappsUpdater = {
let browser = Services.wm.getMostRecentWindow("navigator:browser");
if (!browser) {
this._pendingEvents.push(detail);
dump("Warning: Couldn't send update event " + aType +
debug("Warning: Couldn't send update event " + aType +
": no content browser. Will send again when content becomes available.");
return false;
}
@ -39,8 +48,8 @@ this.WebappsUpdater = {
},
_appsUpdated: function(aApps) {
dump("appsUpdated: " + aApps.length + " apps to update");
let lock = Services.settings.createLock();
debug("appsUpdated: " + aApps.length + " apps to update");
let lock = settings.createLock();
lock.set("apps.updateStatus", "check-complete", null);
this.sendChromeEvent("apps-update-check", { apps: aApps });
this._checkingApps = false;
@ -49,7 +58,7 @@ this.WebappsUpdater = {
// Trigger apps update check and wait for all to be done before
// notifying gaia.
updateApps: function() {
dump("updateApps (" + this._checkingApps + ")");
debug("updateApps (" + this._checkingApps + ")");
// Don't start twice.
if (this._checkingApps) {
return;

View File

@ -1,4 +1,4 @@
{
"revision": "af6b88994605d8833693cde83e43fe3d9e93d181",
"revision": "c96e0e230e9dba0fcc7f7a6bfb76d85a62fb95c5",
"repo_path": "/integration/gaia-central"
}

View File

@ -211,15 +211,17 @@ if test -n "$gonkdir" ; then
MOZ_B2G_BT=1
MOZ_B2G_CAMERA=1
MOZ_OMX_DECODER=1
AC_DEFINE(MOZ_OMX_DECODER)
AC_SUBST(MOZ_OMX_DECODER)
;;
18)
GONK_INCLUDES="-I$gonkdir/frameworks/native/include"
GONK_INCLUDES="-I$gonkdir/frameworks/native/include -I$gonkdir/frameworks/av/include -I$gonkdir/frameworks/av/include/media -I$gonkdir/frameworks/av/include/camera -I$gonkdir/frameworks/native/include/media/openmax -I$gonkdir/frameworks/av/media/libstagefright/include"
if test -d "$gonkdir/external/bluetooth/bluez"; then
GONK_INCLUDES+=" -I$gonkdir/external/dbus -I$gonkdir/external/bluetooth/bluez/lib"
MOZ_B2G_BT=1
fi
MOZ_B2G_CAMERA=1
MOZ_OMX_DECODER=1
AC_SUBST(MOZ_OMX_DECODER)
;;
*)
AC_MSG_ERROR([Unsupported platform version: $ANDROID_VERSION])

View File

@ -5,6 +5,10 @@
include $(topsrcdir)/config/rules.mk
include $(topsrcdir)/ipc/chromium/chromium-config.mk
ifdef MOZ_OMX_DECODER
DEFINES += -DMOZ_OMX_DECODER
endif
LOCAL_INCLUDES += \
-I$(topsrcdir)/content/base/src \
-I$(topsrcdir)/layout/generic \

View File

@ -472,7 +472,11 @@ bool OmxDecoder::AllocateMediaResources()
if ((mVideoTrack != nullptr) && (mVideoSource == nullptr)) {
mNativeWindow = new GonkNativeWindow();
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18
mNativeWindowClient = new GonkNativeWindowClient(mNativeWindow->getBufferQueue());
#else
mNativeWindowClient = new GonkNativeWindowClient(mNativeWindow);
#endif
// Experience with OMX codecs is that only the HW decoders are
// worth bothering with, at least on the platforms where this code

View File

@ -24,6 +24,14 @@
#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
@ -36,7 +44,7 @@ SortedVector< wp<IMediaResourceManagerDeathNotifier> > IMediaResourceManagerDeat
/*static*/const sp<IMediaResourceManagerService>&
IMediaResourceManagerDeathNotifier::getMediaResourceManagerService()
{
LOGV("getMediaResourceManagerService");
DN_LOGV("getMediaResourceManagerService");
Mutex::Autolock _l(sServiceLock);
if (sMediaResourceManagerService.get() == 0) {
sp<IServiceManager> sm = defaultServiceManager();
@ -46,7 +54,7 @@ IMediaResourceManagerDeathNotifier::getMediaResourceManagerService()
if (binder != 0) {
break;
}
LOGW("Media resource manager service not published, waiting...");
DN_LOGW("Media resource manager service not published, waiting...");
usleep(500000); // 0.5 s
} while(true);
@ -56,14 +64,13 @@ IMediaResourceManagerDeathNotifier::getMediaResourceManagerService()
binder->linkToDeath(sDeathNotifier);
sMediaResourceManagerService = interface_cast<IMediaResourceManagerService>(binder);
}
LOGE_IF(sMediaResourceManagerService == 0, "no media player service!?");
DN_LOGE_IF(sMediaResourceManagerService == 0, "no media player service!?");
return sMediaResourceManagerService;
}
/*static*/ void
IMediaResourceManagerDeathNotifier::addObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient)
{
LOGV("addObitRecipient");
Mutex::Autolock _l(sServiceLock);
sObitRecipients.add(recipient);
}
@ -71,7 +78,6 @@ IMediaResourceManagerDeathNotifier::addObitRecipient(const wp<IMediaResourceMana
/*static*/ void
IMediaResourceManagerDeathNotifier::removeObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient)
{
LOGV("removeObitRecipient");
Mutex::Autolock _l(sServiceLock);
sObitRecipients.remove(recipient);
}
@ -79,8 +85,7 @@ IMediaResourceManagerDeathNotifier::removeObitRecipient(const wp<IMediaResourceM
void
IMediaResourceManagerDeathNotifier::DeathNotifier::binderDied(const wp<IBinder>& who)
{
LOGW("media server died");
DN_LOGW("media resource manager service died");
// Need to do this with the lock held
SortedVector< wp<IMediaResourceManagerDeathNotifier> > list;
{
@ -103,7 +108,6 @@ IMediaResourceManagerDeathNotifier::DeathNotifier::binderDied(const wp<IBinder>&
IMediaResourceManagerDeathNotifier::DeathNotifier::~DeathNotifier()
{
LOGV("DeathNotifier::~DeathNotifier");
Mutex::Autolock _l(sServiceLock);
sObitRecipients.clear();
if (sMediaResourceManagerService != 0) {

View File

@ -1,179 +0,0 @@
/*
* Copyright (C) 2006-2011 The Android Open Source Project
*
* 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_TAG "AudioParameter"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
#include <media/AudioParameter.h>
namespace android {
const char *AudioParameter::keyRouting = "routing";
const char *AudioParameter::keySamplingRate = "sampling_rate";
const char *AudioParameter::keyFormat = "format";
const char *AudioParameter::keyChannels = "channels";
const char *AudioParameter::keyFrameCount = "frame_count";
const char *AudioParameter::keyInputSource = "input_source";
AudioParameter::AudioParameter(const String8& keyValuePairs)
{
char *str = new char[keyValuePairs.length()+1];
mKeyValuePairs = keyValuePairs;
strcpy(str, keyValuePairs.string());
char *pair = strtok(str, ";");
while (pair != NULL) {
if (strlen(pair) != 0) {
size_t eqIdx = strcspn(pair, "=");
String8 key = String8(pair, eqIdx);
String8 value;
if (eqIdx == strlen(pair)) {
value = String8("");
} else {
value = String8(pair + eqIdx + 1);
}
if (mParameters.indexOfKey(key) < 0) {
mParameters.add(key, value);
} else {
mParameters.replaceValueFor(key, value);
}
} else {
LOGV("AudioParameter() cstor empty key value pair");
}
pair = strtok(NULL, ";");
}
delete[] str;
}
AudioParameter::~AudioParameter()
{
mParameters.clear();
}
String8 AudioParameter::toString()
{
String8 str = String8("");
size_t size = mParameters.size();
for (size_t i = 0; i < size; i++) {
str += mParameters.keyAt(i);
str += "=";
str += mParameters.valueAt(i);
if (i < (size - 1)) str += ";";
}
return str;
}
status_t AudioParameter::add(const String8& key, const String8& value)
{
if (mParameters.indexOfKey(key) < 0) {
mParameters.add(key, value);
return NO_ERROR;
} else {
mParameters.replaceValueFor(key, value);
return ALREADY_EXISTS;
}
}
status_t AudioParameter::addInt(const String8& key, const int value)
{
char str[12];
if (snprintf(str, 12, "%d", value) > 0) {
String8 str8 = String8(str);
return add(key, str8);
} else {
return BAD_VALUE;
}
}
status_t AudioParameter::addFloat(const String8& key, const float value)
{
char str[23];
if (snprintf(str, 23, "%.10f", value) > 0) {
String8 str8 = String8(str);
return add(key, str8);
} else {
return BAD_VALUE;
}
}
status_t AudioParameter::remove(const String8& key)
{
if (mParameters.indexOfKey(key) >= 0) {
mParameters.removeItem(key);
return NO_ERROR;
} else {
return BAD_VALUE;
}
}
status_t AudioParameter::get(const String8& key, String8& value)
{
if (mParameters.indexOfKey(key) >= 0) {
value = mParameters.valueFor(key);
return NO_ERROR;
} else {
return BAD_VALUE;
}
}
status_t AudioParameter::getInt(const String8& key, int& value)
{
String8 str8;
status_t result = get(key, str8);
value = 0;
if (result == NO_ERROR) {
int val;
if (sscanf(str8.string(), "%d", &val) == 1) {
value = val;
} else {
result = INVALID_OPERATION;
}
}
return result;
}
status_t AudioParameter::getFloat(const String8& key, float& value)
{
String8 str8;
status_t result = get(key, str8);
value = 0;
if (result == NO_ERROR) {
float val;
if (sscanf(str8.string(), "%f", &val) == 1) {
value = val;
} else {
result = INVALID_OPERATION;
}
}
return result;
}
status_t AudioParameter::getAt(size_t index, String8& key, String8& value)
{
if (mParameters.size() > index) {
key = mParameters.keyAt(index);
value = mParameters.valueAt(index);
return NO_ERROR;
} else {
return BAD_VALUE;
}
}
}; // namespace android

View File

@ -183,14 +183,24 @@ GonkCameraHardware::Init()
mNativeWindow = new GonkNativeWindow();
mNativeWindow->setNewFrameCallback(this);
mCamera->setListener(this);
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18
mCamera->setPreviewTexture(mNativeWindow->getBufferQueue());
#else
mCamera->setPreviewTexture(mNativeWindow);
#endif
mInitialized = true;
}
sp<GonkCameraHardware>
GonkCameraHardware::Connect(mozilla::nsGonkCameraControl* aTarget, uint32_t aCameraId)
{
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18
sp<Camera> camera = Camera::connect(aCameraId, /* clientPackageName */String16("gonk.camera"), Camera::USE_CALLING_UID);
#else
sp<Camera> camera = Camera::connect(aCameraId);
#endif
if (camera.get() == nullptr) {
return nullptr;
}

View File

@ -1,5 +1,6 @@
/*
* Copyright (C) 2009 The Android Open Source Project
* Copyright (C) 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.
@ -18,24 +19,36 @@
#include "nsDebug.h"
#define DOM_CAMERA_LOG_LEVEL 3
#include "CameraCommon.h"
#define LOGD DOM_CAMERA_LOGA
#define LOGV DOM_CAMERA_LOGI
#define LOGI DOM_CAMERA_LOGI
#define LOGW DOM_CAMERA_LOGW
#define LOGE DOM_CAMERA_LOGE
/*
#define CS_LOGD(...) DOM_CAMERA_LOGA(__VA_ARGS__)
#define CS_LOGV(...) DOM_CAMERA_LOGI(__VA_ARGS__)
#define CS_LOGI(...) DOM_CAMERA_LOGI(__VA_ARGS__)
#define CS_LOGW(...) DOM_CAMERA_LOGW(__VA_ARGS__)
#define CS_LOGE(...) DOM_CAMERA_LOGE(__VA_ARGS__)
*/
#define CS_LOGD(fmt, ...) DOM_CAMERA_LOGA("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__)
#define CS_LOGV(fmt, ...) DOM_CAMERA_LOGI("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__)
#define CS_LOGI(fmt, ...) DOM_CAMERA_LOGI("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__)
#define CS_LOGW(fmt, ...) DOM_CAMERA_LOGW("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__)
#define CS_LOGE(fmt, ...) DOM_CAMERA_LOGE("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__)
#include <OMX_Component.h>
#include "GonkCameraSource.h"
#include "GonkCameraListener.h"
#include "GonkCameraHwMgr.h"
#include <media/stagefright/MediaDebug.h>
#include <binder/IPCThreadState.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <camera/CameraParameters.h>
#include <utils/String8.h>
#include <cutils/properties.h>
#include "GonkCameraSource.h"
#include "GonkCameraListener.h"
#include "GonkCameraHwMgr.h"
using namespace mozilla;
namespace android {
static const int64_t CAMERA_SOURCE_TIMEOUT_NS = 3000000000LL;
@ -68,12 +81,12 @@ GonkCameraSourceListener::~GonkCameraSourceListener() {
}
void GonkCameraSourceListener::notify(int32_t msgType, int32_t ext1, int32_t ext2) {
LOGV("notify(%d, %d, %d)", msgType, ext1, ext2);
CS_LOGV("notify(%d, %d, %d)", msgType, ext1, ext2);
}
void GonkCameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr,
camera_frame_metadata_t *metadata) {
LOGV("postData(%d, ptr:%p, size:%d)",
CS_LOGV("postData(%d, ptr:%p, size:%d)",
msgType, dataPtr->pointer(), dataPtr->size());
sp<GonkCameraSource> source = mSource.promote();
@ -92,7 +105,7 @@ void GonkCameraSourceListener::postDataTimestamp(
}
static int32_t getColorFormat(const char* colorFormat) {
return OMX_COLOR_FormatYUV420SemiPlanar;
return OMX_COLOR_FormatYUV420SemiPlanar; //XXX nsGonkCameraControl uses only YUV420SemiPlanar
if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420P)) {
return OMX_COLOR_FormatYUV420Planar;
@ -117,11 +130,15 @@ static int32_t getColorFormat(const char* colorFormat) {
if (!strcmp(colorFormat, "OMX_TI_COLOR_FormatYUV420PackedSemiPlanar")) {
return OMX_TI_COLOR_FormatYUV420PackedSemiPlanar;
}
LOGE("Uknown color format (%s), please add it to "
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18
if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE)) {
return OMX_COLOR_FormatAndroidOpaque;
}
#endif
CS_LOGE("Uknown color format (%s), please add it to "
"GonkCameraSource::getColorFormat", colorFormat);
CHECK_EQ(0, "Unknown color format");
CHECK(!"Unknown color format");
}
GonkCameraSource *GonkCameraSource::Create(
@ -143,6 +160,7 @@ GonkCameraSource::GonkCameraSource(
bool storeMetaDataInVideoBuffers)
: mCameraHw(aCameraHw),
mCameraFlags(0),
mNumInputBuffers(0),
mVideoFrameRate(-1),
mNumFramesReceived(0),
mLastFrameTimestampUs(0),
@ -181,7 +199,7 @@ static bool isVideoSizeSupported(
int32_t width, int32_t height,
const Vector<Size>& supportedSizes) {
LOGV("isVideoSizeSupported");
CS_LOGV("isVideoSizeSupported");
for (size_t i = 0; i < supportedSizes.size(); ++i) {
if (width == supportedSizes[i].width &&
height == supportedSizes[i].height) {
@ -218,7 +236,7 @@ static void getSupportedVideoSizes(
*isSetVideoSizeSupported = true;
params.getSupportedVideoSizes(sizes);
if (sizes.size() == 0) {
LOGD("Camera does not support setVideoSize()");
CS_LOGD("Camera does not support setVideoSize()");
params.getSupportedPreviewSizes(sizes);
*isSetVideoSizeSupported = false;
}
@ -258,14 +276,14 @@ status_t GonkCameraSource::configureCamera(
CameraParameters* params,
int32_t width, int32_t height,
int32_t frameRate) {
LOGV("configureCamera");
CS_LOGV("configureCamera");
Vector<Size> sizes;
bool isSetVideoSizeSupportedByCamera = true;
getSupportedVideoSizes(*params, &isSetVideoSizeSupportedByCamera, sizes);
bool isCameraParamChanged = false;
if (width != -1 && height != -1) {
if (!isVideoSizeSupported(width, height, sizes)) {
LOGE("Video dimension (%dx%d) is unsupported", width, height);
CS_LOGE("Video dimension (%dx%d) is unsupported", width, height);
return BAD_VALUE;
}
if (isSetVideoSizeSupportedByCamera) {
@ -278,7 +296,7 @@ status_t GonkCameraSource::configureCamera(
(width != -1 && height == -1)) {
// If one and only one of the width and height is -1
// we reject such a request.
LOGE("Requested video size (%dx%d) is not supported", width, height);
CS_LOGE("Requested video size (%dx%d) is not supported", width, height);
return BAD_VALUE;
} else { // width == -1 && height == -1
// Do not configure the camera.
@ -290,11 +308,11 @@ status_t GonkCameraSource::configureCamera(
const char* supportedFrameRates =
params->get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES);
CHECK(supportedFrameRates != NULL);
LOGV("Supported frame rates: %s", supportedFrameRates);
CS_LOGV("Supported frame rates: %s", supportedFrameRates);
char buf[4];
snprintf(buf, 4, "%d", frameRate);
if (strstr(supportedFrameRates, buf) == NULL) {
LOGE("Requested frame rate (%d) is not supported: %s",
CS_LOGE("Requested frame rate (%d) is not supported: %s",
frameRate, supportedFrameRates);
return BAD_VALUE;
}
@ -310,8 +328,8 @@ status_t GonkCameraSource::configureCamera(
if (isCameraParamChanged) {
// Either frame rate or frame size needs to be changed.
if (OK != mCameraHw->PushParameters(*params)) {
LOGE("Could not change settings."
" Someone else is using camera ?");
CS_LOGE("Could not change settings."
" Someone else is using camera?");
return -EBUSY;
}
}
@ -333,7 +351,7 @@ status_t GonkCameraSource::checkVideoSize(
const CameraParameters& params,
int32_t width, int32_t height) {
LOGV("checkVideoSize");
CS_LOGV("checkVideoSize");
// The actual video size is the same as the preview size
// if the camera hal does not support separate video and
// preview output. In this case, we retrieve the video
@ -350,7 +368,7 @@ status_t GonkCameraSource::checkVideoSize(
params.getVideoSize(&frameWidthActual, &frameHeightActual);
}
if (frameWidthActual < 0 || frameHeightActual < 0) {
LOGE("Failed to retrieve video frame size (%dx%d)",
CS_LOGE("Failed to retrieve video frame size (%dx%d)",
frameWidthActual, frameHeightActual);
return UNKNOWN_ERROR;
}
@ -359,7 +377,7 @@ status_t GonkCameraSource::checkVideoSize(
// video frame size.
if (width != -1 && height != -1) {
if (frameWidthActual != width || frameHeightActual != height) {
LOGE("Failed to set video frame size to %dx%d. "
CS_LOGE("Failed to set video frame size to %dx%d. "
"The actual video size is %dx%d ", width, height,
frameWidthActual, frameHeightActual);
return UNKNOWN_ERROR;
@ -385,17 +403,17 @@ status_t GonkCameraSource::checkFrameRate(
const CameraParameters& params,
int32_t frameRate) {
LOGV("checkFrameRate");
CS_LOGV("checkFrameRate");
int32_t frameRateActual = params.getPreviewFrameRate();
if (frameRateActual < 0) {
LOGE("Failed to retrieve preview frame rate (%d)", frameRateActual);
CS_LOGE("Failed to retrieve preview frame rate (%d)", frameRateActual);
return UNKNOWN_ERROR;
}
// Check the actual video frame rate against the target/requested
// video frame rate.
if (frameRate != -1 && (frameRateActual - frameRate) != 0) {
LOGE("Failed to set preview frame rate to %d fps. The actual "
CS_LOGE("Failed to set preview frame rate to %d fps. The actual "
"frame rate is %d", frameRate, frameRateActual);
return UNKNOWN_ERROR;
}
@ -406,7 +424,7 @@ status_t GonkCameraSource::checkFrameRate(
}
/*
* Initialize the CameraSource to so that it becomes
* Initialize the GonkCameraSource so that it becomes
* ready for providing the video input streams as requested.
* @param camera the camera object used for the video source
* @param cameraId if camera == 0, use camera with this id
@ -428,7 +446,7 @@ status_t GonkCameraSource::init(
int32_t frameRate,
bool storeMetaDataInVideoBuffers) {
LOGV("init");
CS_LOGV("init");
status_t err = OK;
//TODO: need to do something here to check the sanity of camera
@ -466,26 +484,11 @@ status_t GonkCameraSource::init(
}
}
const char *hfr_str = params.get("video-hfr");
int32_t hfr = -1;
if ( hfr_str != NULL ) {
hfr = atoi(hfr_str);
}
if(hfr < 0) {
LOGW("Invalid hfr value(%d) set from app. Disabling HFR.", hfr);
hfr = 0;
}
int64_t glitchDurationUs = (1000000LL / mVideoFrameRate);
if (glitchDurationUs > mGlitchDurationThresholdUs) {
mGlitchDurationThresholdUs = glitchDurationUs;
}
const char * k3dFrameArrangement = "3d-frame-format";
const char * arrangement = params.get(k3dFrameArrangement);
// XXX: just assume left/right for now since that's all the camera supports
bool want3D = (arrangement != NULL && !strcmp("left-right", arrangement));
// XXX: query camera for the stride and slice height
// when the capability becomes available.
mMeta = new MetaData;
@ -496,13 +499,12 @@ status_t GonkCameraSource::init(
mMeta->setInt32(kKeyStride, mVideoSize.width);
mMeta->setInt32(kKeySliceHeight, mVideoSize.height);
mMeta->setInt32(kKeyFrameRate, mVideoFrameRate);
return OK;
}
GonkCameraSource::~GonkCameraSource() {
if (mStarted) {
stop();
reset();
} else if (mInitCheck == OK) {
// Camera is initialized but because start() is never called,
// the lock on Camera is never released(). This makes sure
@ -513,17 +515,17 @@ GonkCameraSource::~GonkCameraSource() {
}
int GonkCameraSource::startCameraRecording() {
LOGV("startCameraRecording");
CS_LOGV("startCameraRecording");
return mCameraHw->StartRecording();
}
status_t GonkCameraSource::start(MetaData *meta) {
int rv;
LOGV("start");
CS_LOGV("start");
CHECK(!mStarted);
if (mInitCheck != OK) {
LOGE("GonkCameraSource is not initialized yet");
CS_LOGE("GonkCameraSource is not initialized yet");
return mInitCheck;
}
@ -534,10 +536,19 @@ status_t GonkCameraSource::start(MetaData *meta) {
}
mStartTimeUs = 0;
int64_t startTimeUs;
if (meta && meta->findInt64(kKeyTime, &startTimeUs)) {
LOGV("Metadata enabled, startime: %lld us", startTimeUs);
mStartTimeUs = startTimeUs;
mNumInputBuffers = 0;
if (meta) {
int64_t startTimeUs;
if (meta->findInt64(kKeyTime, &startTimeUs)) {
mStartTimeUs = startTimeUs;
}
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18
int32_t nBuffers;
if (meta->findInt32(kKeyNumBuffers, &nBuffers)) {
CHECK_GT(nBuffers, 0);
mNumInputBuffers = nBuffers;
}
#endif
}
// Register a listener with GonkCameraHardware so that we can get callbacks
@ -550,16 +561,16 @@ status_t GonkCameraSource::start(MetaData *meta) {
}
void GonkCameraSource::stopCameraRecording() {
LOGV("stopCameraRecording");
CS_LOGV("stopCameraRecording");
mCameraHw->StopRecording();
}
void GonkCameraSource::releaseCamera() {
LOGV("releaseCamera");
CS_LOGV("releaseCamera");
}
status_t GonkCameraSource::stop() {
LOGV("stop: E");
status_t GonkCameraSource::reset() {
CS_LOGD("reset: E");
Mutex::Autolock autoLock(mLock);
mStarted = false;
mFrameAvailableCondition.signal();
@ -569,31 +580,30 @@ status_t GonkCameraSource::stop() {
if (NO_ERROR !=
mFrameCompleteCondition.waitRelative(mLock,
mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) {
LOGW("Timed out waiting for outstanding frames being encoded: %d",
CS_LOGW("Timed out waiting for outstanding frames being encoded: %d",
mFramesBeingEncoded.size());
}
}
LOGV("Calling stopCameraRecording");
stopCameraRecording();
releaseCamera();
if (mCollectStats) {
LOGI("Frames received/encoded/dropped: %d/%d/%d in %lld us",
CS_LOGI("Frames received/encoded/dropped: %d/%d/%d in %lld us",
mNumFramesReceived, mNumFramesEncoded, mNumFramesDropped,
mLastFrameTimestampUs - mFirstFrameTimeUs);
}
if (mNumGlitches > 0) {
LOGW("%d long delays between neighboring video frames", mNumGlitches);
CS_LOGW("%d long delays between neighboring video frames", mNumGlitches);
}
CHECK_EQ(mNumFramesReceived, mNumFramesEncoded + mNumFramesDropped);
LOGV("stop: X");
CS_LOGD("reset: X");
return OK;
}
void GonkCameraSource::releaseRecordingFrame(const sp<IMemory>& frame) {
LOGV("releaseRecordingFrame");
CS_LOGV("releaseRecordingFrame");
mCameraHw->ReleaseRecordingFrame(frame);
}
@ -616,7 +626,7 @@ void GonkCameraSource::releaseOneRecordingFrame(const sp<IMemory>& frame) {
}
void GonkCameraSource::signalBufferReturned(MediaBuffer *buffer) {
LOGV("signalBufferReturned: %p", buffer->data());
CS_LOGV("signalBufferReturned: %p", buffer->data());
Mutex::Autolock autoLock(mLock);
for (List<sp<IMemory> >::iterator it = mFramesBeingEncoded.begin();
it != mFramesBeingEncoded.end(); ++it) {
@ -630,12 +640,12 @@ void GonkCameraSource::signalBufferReturned(MediaBuffer *buffer) {
return;
}
}
CHECK_EQ(0, "signalBufferReturned: bogus buffer");
CHECK(!"signalBufferReturned: bogus buffer");
}
status_t GonkCameraSource::read(
MediaBuffer **buffer, const ReadOptions *options) {
LOGV("read");
CS_LOGV("read");
*buffer = NULL;
@ -655,7 +665,7 @@ status_t GonkCameraSource::read(
mFrameAvailableCondition.waitRelative(mLock,
mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) {
//TODO: check sanity of camera?
LOGW("Timed out waiting for incoming camera video frames: %lld us",
CS_LOGW("Timed out waiting for incoming camera video frames: %lld us",
mLastFrameTimestampUs);
}
}
@ -678,11 +688,10 @@ status_t GonkCameraSource::read(
void GonkCameraSource::dataCallbackTimestamp(int64_t timestampUs,
int32_t msgType, const sp<IMemory> &data) {
LOGV("dataCallbackTimestamp: timestamp %lld us", timestampUs);
//LOGV("dataCallbackTimestamp: data %x size %d", data->pointer(), data->size());
CS_LOGV("dataCallbackTimestamp: timestamp %lld us", timestampUs);
Mutex::Autolock autoLock(mLock);
if (!mStarted || (mNumFramesReceived == 0 && timestampUs < mStartTimeUs)) {
LOGV("Drop frame at %lld/%lld us", timestampUs, mStartTimeUs);
CS_LOGV("Drop frame at %lld/%lld us", timestampUs, mStartTimeUs);
releaseOneRecordingFrame(data);
return;
}
@ -695,7 +704,7 @@ void GonkCameraSource::dataCallbackTimestamp(int64_t timestampUs,
}
// May need to skip frame or modify timestamp. Currently implemented
// by the subclass GonkCameraSourceTimeLapse.
// by the subclass CameraSourceTimeLapse.
if (skipCurrentFrame(timestampUs)) {
releaseOneRecordingFrame(data);
return;
@ -721,14 +730,14 @@ void GonkCameraSource::dataCallbackTimestamp(int64_t timestampUs,
mFramesReceived.push_back(data);
int64_t timeUs = mStartTimeUs + (timestampUs - mFirstFrameTimeUs);
mFrameTimes.push_back(timeUs);
LOGV("initial delay: %lld, current time stamp: %lld",
CS_LOGV("initial delay: %lld, current time stamp: %lld",
mStartTimeUs, timeUs);
mFrameAvailableCondition.signal();
}
bool GonkCameraSource::isMetaDataStoredInVideoBuffers() const {
LOGV("isMetaDataStoredInVideoBuffers");
CS_LOGV("isMetaDataStoredInVideoBuffers");
return mIsMetaDataStoredInVideoBuffers;
}
} // namespace android
} // namespace android

View File

@ -23,14 +23,13 @@
#include <camera/CameraParameters.h>
#include <utils/List.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
#include <utils/String16.h>
#include "GonkCameraHwMgr.h"
namespace android {
class IMemory;
class GonkCameraSourceListener;
class GonkCameraSource : public MediaSource, public MediaBufferObserver {
public:
@ -43,7 +42,7 @@ public:
virtual ~GonkCameraSource();
virtual status_t start(MetaData *params = NULL);
virtual status_t stop();
virtual status_t stop() { return reset(); }
virtual status_t read(
MediaBuffer **buffer, const ReadOptions *options = NULL);
@ -85,6 +84,7 @@ protected:
int32_t mCameraFlags;
Size mVideoSize;
int32_t mNumInputBuffers;
int32_t mVideoFrameRate;
int32_t mColorFormat;
status_t mInitCheck;
@ -153,6 +153,7 @@ private:
int32_t frameRate);
void releaseCamera();
status_t reset();
GonkCameraSource(const GonkCameraSource &);
GonkCameraSource &operator=(const GonkCameraSource &);

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,5 @@
/*
* Copyright (C) 2009 The Android Open Source Project
* Copyright (C) 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.
@ -19,11 +18,14 @@
#define GONK_RECORDER_H_
#include "nsISupportsImpl.h"
#include "GonkCameraHwMgr.h"
#include <media/mediarecorder.h>
#include <media/MediaRecorderBase.h>
#include <camera/CameraParameters.h>
#include <utils/String8.h>
#include <system/audio.h>
#include "mozilla/RefPtr.h"
#include "GonkCameraHwMgr.h"
namespace android {
@ -54,6 +56,7 @@ struct GonkRecorder {
virtual status_t setParameters(const String8& params);
virtual status_t setCamera(const sp<GonkCameraHardware>& aCameraHw);
virtual status_t setListener(const sp<IMediaRecorderClient>& listener);
virtual status_t setClientName(const String16& clientName);
virtual status_t prepare();
virtual status_t start();
virtual status_t pause();
@ -69,6 +72,8 @@ protected:
private:
sp<IMediaRecorderClient> mListener;
String16 mClientName;
uid_t mClientUid;
sp<MediaWriter> mWriter;
int mOutputFd;
sp<AudioSource> mAudioSourceNode;
@ -108,10 +113,10 @@ private:
bool mStarted;
// Needed when GLFrames are encoded.
// An <ISurfaceTexture> pointer
// An <IGraphicBufferProducer> pointer
// will be sent to the client side using which the
// frame buffers will be queued and dequeued
bool mDisableAudio;
sp<GonkCameraHardware> mCameraHw;
status_t setupMPEG4Recording(
@ -124,7 +129,11 @@ private:
sp<MetaData> *meta);
status_t startMPEG4Recording();
status_t startAMRRecording();
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18
status_t startAACRecording();
#endif
status_t startRawAudioRecording();
status_t startRTPRecording();
status_t startMPEG2TSRecording();
sp<MediaSource> createAudioSource();
status_t checkVideoEncoderCapabilities();

View File

@ -39,7 +39,6 @@ if CONFIG['MOZ_B2G_CAMERA']:
'GonkCameraHwMgr.cpp',
'GonkRecorder.cpp',
'GonkCameraSource.cpp',
'AudioParameter.cpp',
'GonkRecorderProfiles.cpp',
]
else:

View File

@ -29,6 +29,8 @@ uint32_t GrallocImage::sColorIdMap[] = {
HAL_PIXEL_FORMAT_YCbCr_420_SP, OMX_COLOR_FormatYUV420SemiPlanar,
HAL_PIXEL_FORMAT_YCrCb_420_SP, -1,
HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO, -1,
HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED, HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED,
HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS, HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS,
HAL_PIXEL_FORMAT_YV12, OMX_COLOR_FormatYUV420Planar,
0, 0
};

View File

@ -104,6 +104,8 @@ public:
HAL_PIXEL_FORMAT_YCbCr_420_P = 0x103,
HAL_PIXEL_FORMAT_YCbCr_420_SP = 0x109,
HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO = 0x10A,
HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED = 0x7FA30C03,
HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS = 0x7FA30C04,
};
virtual already_AddRefed<gfxASurface> GetAsSurface();

View File

@ -7,6 +7,7 @@
#include "gfxImageSurface.h"
#include "gfx2DGlue.h"
#include <ui/GraphicBuffer.h>
#include "GrallocImages.h" // for GrallocImage
#include "mozilla/layers/GrallocTextureHost.h"
#include "mozilla/layers/CompositorOGL.h"
@ -33,6 +34,8 @@ SurfaceFormatForAndroidPixelFormat(android::PixelFormat aFormat,
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
case HAL_PIXEL_FORMAT_YCbCr_422_I:
case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
case HAL_PIXEL_FORMAT_YV12:
return gfx::FORMAT_B8G8R8A8; // yup, use FORMAT_B8G8R8A8 even though it's a YUV texture. This is an external texture.
default:
@ -59,6 +62,8 @@ TextureTargetForAndroidPixelFormat(android::PixelFormat aFormat)
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
case HAL_PIXEL_FORMAT_YCbCr_422_I:
case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
case HAL_PIXEL_FORMAT_YV12:
return LOCAL_GL_TEXTURE_EXTERNAL;
case android::PIXEL_FORMAT_RGBA_8888:

View File

@ -19,6 +19,9 @@
#include "mozilla/gfx/2D.h" // for DataSourceSurface
#include "mozilla/gfx/BaseSize.h" // for BaseSize
#include "mozilla/layers/CompositorOGL.h" // for CompositorOGL
#ifdef MOZ_WIDGET_GONK
# include "GrallocImages.h" // for GrallocImage
#endif
#include "mozilla/layers/ISurfaceAllocator.h"
#include "mozilla/layers/YCbCrImageDataSerializer.h"
#include "mozilla/layers/GrallocTextureHost.h"
@ -952,6 +955,8 @@ SurfaceFormatForAndroidPixelFormat(android::PixelFormat aFormat,
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
case HAL_PIXEL_FORMAT_YCbCr_422_I:
case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
case HAL_PIXEL_FORMAT_YV12:
return FORMAT_B8G8R8A8; // yup, use FORMAT_B8G8R8A8 even though it's a YUV texture. This is an external texture.
default:
@ -977,6 +982,8 @@ TextureTargetForAndroidPixelFormat(android::PixelFormat aFormat)
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
case HAL_PIXEL_FORMAT_YCbCr_422_I:
case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
case HAL_PIXEL_FORMAT_YV12:
return LOCAL_GL_TEXTURE_EXTERNAL;
case android::PIXEL_FORMAT_RGBA_8888:

View File

@ -25,6 +25,10 @@ include $(topsrcdir)/ipc/chromium/chromium-config.mk
DEFINES += -DHAVE_OFF64_T -DSK_BUILD_FOR_ANDROID_NDK
ifdef MOZ_OMX_DECODER
DEFINES += -DMOZ_OMX_DECODER
endif
LOCAL_INCLUDES += \
-I$(ANDROID_SOURCE)/hardware/libhardware/include \
-I$(ANDROID_SOURCE)/hardware/libhardware_legacy/include \

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,639 @@
/*
* Copyright (C) 2012 The Android Open Source Project
* Copyright (C) 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 NATIVEWINDOW_GONKBUFFERQUEUE_H
#define NATIVEWINDOW_GONKBUFFERQUEUE_H
#include <gui/IGraphicBufferAlloc.h>
#include <gui/IGraphicBufferProducer.h>
#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
#include <utils/String8.h>
#include <utils/Vector.h>
#include <utils/threads.h>
#include "mozilla/layers/LayersSurfaces.h"
namespace android {
// ----------------------------------------------------------------------------
class GonkBufferQueue : public BnGraphicBufferProducer {
typedef mozilla::layers::SurfaceDescriptor SurfaceDescriptor;
public:
enum { MIN_UNDEQUEUED_BUFFERS = 2 };
enum { NUM_BUFFER_SLOTS = 32 };
enum { NO_CONNECTED_API = 0 };
enum { INVALID_BUFFER_SLOT = -1 };
enum { STALE_BUFFER_SLOT = 1, NO_BUFFER_AVAILABLE };
// When in async mode we reserve two slots in order to guarantee that the
// producer and consumer can run asynchronously.
enum { MAX_MAX_ACQUIRED_BUFFERS = NUM_BUFFER_SLOTS - 2 };
// ConsumerListener is the interface through which the GonkBufferQueue notifies
// the consumer of events that the consumer may wish to react to. Because
// the consumer will generally have a mutex that is locked during calls from
// the consumer to the GonkBufferQueue, these calls from the GonkBufferQueue to the
// consumer *MUST* be called only when the GonkBufferQueue mutex is NOT locked.
struct ConsumerListener : public virtual RefBase {
// onFrameAvailable is called from queueBuffer each time an additional
// frame becomes available for consumption. This means that frames that
// are queued while in asynchronous mode only trigger the callback if no
// previous frames are pending. Frames queued while in synchronous mode
// always trigger the callback.
//
// This is called without any lock held and can be called concurrently
// by multiple threads.
virtual void onFrameAvailable() = 0;
// onBuffersReleased is called to notify the buffer consumer that the
// GonkBufferQueue has released its references to one or more GraphicBuffers
// contained in its slots. The buffer consumer should then call
// GonkBufferQueue::getReleasedBuffers to retrieve the list of buffers
//
// This is called without any lock held and can be called concurrently
// by multiple threads.
virtual void onBuffersReleased() = 0;
};
// ProxyConsumerListener is a ConsumerListener implementation that keeps a weak
// reference to the actual consumer object. It forwards all calls to that
// consumer object so long as it exists.
//
// This class exists to avoid having a circular reference between the
// GonkBufferQueue object and the consumer object. The reason this can't be a weak
// reference in the GonkBufferQueue class is because we're planning to expose the
// consumer side of a GonkBufferQueue as a binder interface, which doesn't support
// weak references.
class ProxyConsumerListener : public GonkBufferQueue::ConsumerListener {
public:
ProxyConsumerListener(const wp<GonkBufferQueue::ConsumerListener>& consumerListener);
virtual ~ProxyConsumerListener();
virtual void onFrameAvailable();
virtual void onBuffersReleased();
private:
// mConsumerListener is a weak reference to the ConsumerListener. This is
// the raison d'etre of ProxyConsumerListener.
wp<GonkBufferQueue::ConsumerListener> mConsumerListener;
};
// GonkBufferQueue manages a pool of gralloc memory slots to be used by
// producers and consumers. allowSynchronousMode specifies whether or not
// synchronous mode can be enabled by the producer. allocator is used to
// allocate all the needed gralloc buffers.
GonkBufferQueue(bool allowSynchronousMode = true,
const sp<IGraphicBufferAlloc>& allocator = NULL);
virtual ~GonkBufferQueue();
// Query native window attributes. The "what" values are enumerated in
// window.h (e.g. NATIVE_WINDOW_FORMAT).
virtual int query(int what, int* value);
// setBufferCount updates the number of available buffer slots. If this
// method succeeds, buffer slots will be both unallocated and owned by
// the GonkBufferQueue object (i.e. they are not owned by the producer or
// consumer).
//
// This will fail if the producer has dequeued any buffers, or if
// bufferCount is invalid. bufferCount must generally be a value
// between the minimum undequeued buffer count and NUM_BUFFER_SLOTS
// (inclusive). It may also be set to zero (the default) to indicate
// that the producer does not wish to set a value. The minimum value
// can be obtained by calling query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
// ...).
//
// This may only be called by the producer. The consumer will be told
// to discard buffers through the onBuffersReleased callback.
virtual status_t setBufferCount(int bufferCount);
// requestBuffer returns the GraphicBuffer for slot N.
//
// In normal operation, this is called the first time slot N is returned
// by dequeueBuffer. It must be called again if dequeueBuffer returns
// flags indicating that previously-returned buffers are no longer valid.
virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
// dequeueBuffer gets the next buffer slot index for the producer to use.
// If a buffer slot is available then that slot index is written to the
// location pointed to by the buf argument and a status of OK is returned.
// If no slot is available then a status of -EBUSY is returned and buf is
// unmodified.
//
// The fence parameter will be updated to hold the fence associated with
// the buffer. The contents of the buffer must not be overwritten until the
// fence signals. If the fence is Fence::NO_FENCE, the buffer may be
// written immediately.
//
// The width and height parameters must be no greater than the minimum of
// GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
// An error due to invalid dimensions might not be reported until
// updateTexImage() is called. If width and height are both zero, the
// default values specified by setDefaultBufferSize() are used instead.
//
// The pixel formats are enumerated in graphics.h, e.g.
// HAL_PIXEL_FORMAT_RGBA_8888. If the format is 0, the default format
// will be used.
//
// The usage argument specifies gralloc buffer usage flags. The values
// are enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER. These
// will be merged with the usage flags specified by setConsumerUsageBits.
//
// The return value may be a negative error value or a non-negative
// collection of flags. If the flags are set, the return values are
// valid, but additional actions must be performed.
//
// If IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION is set, the
// producer must discard cached GraphicBuffer references for the slot
// returned in buf.
// If IGraphicBufferProducer::RELEASE_ALL_BUFFERS is set, the producer
// must discard cached GraphicBuffer references for all slots.
//
// In both cases, the producer will need to call requestBuffer to get a
// GraphicBuffer handle for the returned slot.
virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence,
uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
// queueBuffer returns a filled buffer to the GonkBufferQueue.
//
// Additional data is provided in the QueueBufferInput struct. Notably,
// a timestamp must be provided for the buffer. The timestamp is in
// nanoseconds, and must be monotonically increasing. Its other semantics
// (zero point, etc) are producer-specific and should be documented by the
// producer.
//
// The caller may provide a fence that signals when all rendering
// operations have completed. Alternatively, NO_FENCE may be used,
// indicating that the buffer is ready immediately.
//
// Some values are returned in the output struct: the current settings
// for default width and height, the current transform hint, and the
// number of queued buffers.
virtual status_t queueBuffer(int buf,
const QueueBufferInput& input, QueueBufferOutput* output);
// cancelBuffer returns a dequeued buffer to the GonkBufferQueue, but doesn't
// queue it for use by the consumer.
//
// The buffer will not be overwritten until the fence signals. The fence
// will usually be the one obtained from dequeueBuffer.
virtual void cancelBuffer(int buf, const sp<Fence>& fence);
// setSynchronousMode sets whether dequeueBuffer is synchronous or
// asynchronous. In synchronous mode, dequeueBuffer blocks until
// a buffer is available, the currently bound buffer can be dequeued and
// queued buffers will be acquired in order. In asynchronous mode,
// a queued buffer may be replaced by a subsequently queued buffer.
//
// The default mode is asynchronous.
virtual status_t setSynchronousMode(bool enabled);
// connect attempts to connect a producer API to the GonkBufferQueue. This
// must be called before any other IGraphicBufferProducer methods are
// called except for getAllocator. A consumer must already be connected.
//
// This method will fail if connect was previously called on the
// GonkBufferQueue and no corresponding disconnect call was made (i.e. if
// it's still connected to a producer).
//
// APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU).
virtual status_t connect(int api, QueueBufferOutput* output);
// disconnect attempts to disconnect a producer API from the GonkBufferQueue.
// Calling this method will cause any subsequent calls to other
// IGraphicBufferProducer methods to fail except for getAllocator and connect.
// Successfully calling connect after this will allow the other methods to
// succeed again.
//
// This method will fail if the the GonkBufferQueue is not currently
// connected to the specified producer API.
virtual status_t disconnect(int api);
// dump our state in a String
virtual void dump(String8& result) const;
virtual void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const;
// public facing structure for BufferSlot
struct BufferItem {
BufferItem()
:
mSurfaceDescriptor(SurfaceDescriptor()),
mTransform(0),
mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mTimestamp(0),
mFrameNumber(0),
mBuf(INVALID_BUFFER_SLOT) {
mCrop.makeInvalid();
}
// mGraphicBuffer points to the buffer allocated for this slot, or is NULL
// if the buffer in this slot has been acquired in the past (see
// BufferSlot.mAcquireCalled).
sp<GraphicBuffer> mGraphicBuffer;
// mSurfaceDescriptor is the token to remotely allocated GraphicBuffer.
SurfaceDescriptor mSurfaceDescriptor;
// mCrop is the current crop rectangle for this buffer slot.
Rect mCrop;
// mTransform is the current transform flags for this buffer slot.
uint32_t mTransform;
// mScalingMode is the current scaling mode for this buffer slot.
uint32_t mScalingMode;
// mTimestamp is the current timestamp for this buffer slot. This gets
// to set by queueBuffer each time this slot is queued.
int64_t mTimestamp;
// mFrameNumber is the number of the queued frame for this slot.
uint64_t mFrameNumber;
// mBuf is the slot index of this buffer
int mBuf;
// mFence is a fence that will signal when the buffer is idle.
sp<Fence> mFence;
};
// The following public functions are the consumer-facing interface
// acquireBuffer attempts to acquire ownership of the next pending buffer in
// the GonkBufferQueue. If no buffer is pending then it returns -EINVAL. If a
// buffer is successfully acquired, the information about the buffer is
// returned in BufferItem. If the buffer returned had previously been
// acquired then the BufferItem::mGraphicBuffer field of buffer is set to
// NULL and it is assumed that the consumer still holds a reference to the
// buffer.
status_t acquireBuffer(BufferItem *buffer);
// releaseBuffer releases a buffer slot from the consumer back to the
// GonkBufferQueue. This may be done while the buffer's contents are still
// being accessed. The fence will signal when the buffer is no longer
// in use.
//
// If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free
// any references to the just-released buffer that it might have, as if it
// had received a onBuffersReleased() call with a mask set for the released
// buffer.
//
// Note that the dependencies on EGL will be removed once we switch to using
// the Android HW Sync HAL.
status_t releaseBuffer(int buf, const sp<Fence>& releaseFence);
// consumerConnect connects a consumer to the GonkBufferQueue. Only one
// consumer may be connected, and when that consumer disconnects the
// GonkBufferQueue is placed into the "abandoned" state, causing most
// interactions with the GonkBufferQueue by the producer to fail.
//
// consumer may not be NULL.
status_t consumerConnect(const sp<ConsumerListener>& consumer);
// consumerDisconnect disconnects a consumer from the GonkBufferQueue. All
// buffers will be freed and the GonkBufferQueue is placed in the "abandoned"
// state, causing most interactions with the GonkBufferQueue by the producer to
// fail.
status_t consumerDisconnect();
// getReleasedBuffers sets the value pointed to by slotMask to a bit mask
// indicating which buffer slots have been released by the GonkBufferQueue
// but have not yet been released by the consumer.
//
// This should be called from the onBuffersReleased() callback.
status_t getReleasedBuffers(uint32_t* slotMask);
// setDefaultBufferSize is used to set the size of buffers returned by
// dequeueBuffer when a width and height of zero is requested. Default
// is 1x1.
status_t setDefaultBufferSize(uint32_t w, uint32_t h);
// setDefaultMaxBufferCount sets the default value for the maximum buffer
// count (the initial default is 2). If the producer has requested a
// buffer count using setBufferCount, the default buffer count will only
// take effect if the producer sets the count back to zero.
//
// The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
status_t setDefaultMaxBufferCount(int bufferCount);
// setMaxAcquiredBufferCount sets the maximum number of buffers that can
// be acquired by the consumer at one time (default 1). This call will
// fail if a producer is connected to the GonkBufferQueue.
status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
// isSynchronousMode returns whether the GonkBufferQueue is currently in
// synchronous mode.
bool isSynchronousMode() const;
// setConsumerName sets the name used in logging
void setConsumerName(const String8& name);
// setDefaultBufferFormat allows the GonkBufferQueue to create
// GraphicBuffers of a defaultFormat if no format is specified
// in dequeueBuffer. Formats are enumerated in graphics.h; the
// initial default is HAL_PIXEL_FORMAT_RGBA_8888.
status_t setDefaultBufferFormat(uint32_t defaultFormat);
// setConsumerUsageBits will turn on additional usage bits for dequeueBuffer.
// These are merged with the bits passed to dequeueBuffer. The values are
// enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0.
status_t setConsumerUsageBits(uint32_t usage);
// setTransformHint bakes in rotation to buffers so overlays can be used.
// The values are enumerated in window.h, e.g.
// NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform).
status_t setTransformHint(uint32_t hint);
int getGeneration();
SurfaceDescriptor *getSurfaceDescriptorFromBuffer(ANativeWindowBuffer* buffer);
private:
// releaseBufferFreeListUnlocked releases the resources in the freeList;
// this must be called with mMutex unlocked.
void releaseBufferFreeListUnlocked(nsTArray<SurfaceDescriptor>& freeList);
// freeBufferLocked frees the GraphicBuffer and sync resources for the
// given slot.
//void freeBufferLocked(int index);
// freeAllBuffersLocked frees the GraphicBuffer and sync resources for
// all slots.
//void freeAllBuffersLocked();
void freeAllBuffersLocked(nsTArray<SurfaceDescriptor>& freeList);
// setDefaultMaxBufferCountLocked sets the maximum number of buffer slots
// that will be used if the producer does not override the buffer slot
// count. The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
// The initial default is 2.
status_t setDefaultMaxBufferCountLocked(int count);
// getMinBufferCountLocked returns the minimum number of buffers allowed
// given the current GonkBufferQueue state.
int getMinMaxBufferCountLocked() const;
// getMinUndequeuedBufferCountLocked returns the minimum number of buffers
// that must remain in a state other than DEQUEUED.
int getMinUndequeuedBufferCountLocked() const;
// getMaxBufferCountLocked returns the maximum number of buffers that can
// be allocated at once. This value depends upon the following member
// variables:
//
// mSynchronousMode
// mMaxAcquiredBufferCount
// mDefaultMaxBufferCount
// mOverrideMaxBufferCount
//
// Any time one of these member variables is changed while a producer is
// connected, mDequeueCondition must be broadcast.
int getMaxBufferCountLocked() const;
struct BufferSlot {
BufferSlot()
: mSurfaceDescriptor(SurfaceDescriptor()),
mBufferState(BufferSlot::FREE),
mRequestBufferCalled(false),
mTransform(0),
mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mTimestamp(0),
mFrameNumber(0),
mAcquireCalled(false),
mNeedsCleanupOnRelease(false) {
mCrop.makeInvalid();
}
// mGraphicBuffer points to the buffer allocated for this slot or is NULL
// if no buffer has been allocated.
sp<GraphicBuffer> mGraphicBuffer;
// mSurfaceDescriptor is the token to remotely allocated GraphicBuffer.
SurfaceDescriptor mSurfaceDescriptor;
// BufferState represents the different states in which a buffer slot
// can be. All slots are initially FREE.
enum BufferState {
// FREE indicates that the buffer is available to be dequeued
// by the producer. The buffer may be in use by the consumer for
// a finite time, so the buffer must not be modified until the
// associated fence is signaled.
//
// The slot is "owned" by GonkBufferQueue. It transitions to DEQUEUED
// when dequeueBuffer is called.
FREE = 0,
// DEQUEUED indicates that the buffer has been dequeued by the
// producer, but has not yet been queued or canceled. The
// producer may modify the buffer's contents as soon as the
// associated ready fence is signaled.
//
// The slot is "owned" by the producer. It can transition to
// QUEUED (via queueBuffer) or back to FREE (via cancelBuffer).
DEQUEUED = 1,
// QUEUED indicates that the buffer has been filled by the
// producer and queued for use by the consumer. The buffer
// contents may continue to be modified for a finite time, so
// the contents must not be accessed until the associated fence
// is signaled.
//
// The slot is "owned" by GonkBufferQueue. It can transition to
// ACQUIRED (via acquireBuffer) or to FREE (if another buffer is
// queued in asynchronous mode).
QUEUED = 2,
// ACQUIRED indicates that the buffer has been acquired by the
// consumer. As with QUEUED, the contents must not be accessed
// by the consumer until the fence is signaled.
//
// The slot is "owned" by the consumer. It transitions to FREE
// when releaseBuffer is called.
ACQUIRED = 3
};
// mBufferState is the current state of this buffer slot.
BufferState mBufferState;
// mRequestBufferCalled is used for validating that the producer did
// call requestBuffer() when told to do so. Technically this is not
// needed but useful for debugging and catching producer bugs.
bool mRequestBufferCalled;
// mCrop is the current crop rectangle for this buffer slot.
Rect mCrop;
// mTransform is the current transform flags for this buffer slot.
// (example: NATIVE_WINDOW_TRANSFORM_ROT_90)
uint32_t mTransform;
// mScalingMode is the current scaling mode for this buffer slot.
// (example: NATIVE_WINDOW_SCALING_MODE_FREEZE)
uint32_t mScalingMode;
// mTimestamp is the current timestamp for this buffer slot. This gets
// to set by queueBuffer each time this slot is queued.
int64_t mTimestamp;
// mFrameNumber is the number of the queued frame for this slot. This
// is used to dequeue buffers in LRU order (useful because buffers
// may be released before their release fence is signaled).
uint64_t mFrameNumber;
// mEglFence is the EGL sync object that must signal before the buffer
// associated with this buffer slot may be dequeued. It is initialized
// to EGL_NO_SYNC_KHR when the buffer is created and may be set to a
// new sync object in releaseBuffer. (This is deprecated in favor of
// mFence, below.)
//EGLSyncKHR mEglFence;
// mFence is a fence which will signal when work initiated by the
// previous owner of the buffer is finished. When the buffer is FREE,
// the fence indicates when the consumer has finished reading
// from the buffer, or when the producer has finished writing if it
// called cancelBuffer after queueing some writes. When the buffer is
// QUEUED, it indicates when the producer has finished filling the
// buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been
// passed to the consumer or producer along with ownership of the
// buffer, and mFence is set to NO_FENCE.
sp<Fence> mFence;
// Indicates whether this buffer has been seen by a consumer yet
bool mAcquireCalled;
// Indicates whether this buffer needs to be cleaned up by the
// consumer. This is set when a buffer in ACQUIRED state is freed.
// It causes releaseBuffer to return STALE_BUFFER_SLOT.
bool mNeedsCleanupOnRelease;
};
// mSlots is the array of buffer slots that must be mirrored on the
// producer side. This allows buffer ownership to be transferred between
// the producer and consumer without sending a GraphicBuffer over binder.
// The entire array is initialized to NULL at construction time, and
// buffers are allocated for a slot when requestBuffer is called with
// that slot's index.
BufferSlot mSlots[NUM_BUFFER_SLOTS];
// mDefaultWidth holds the default width of allocated buffers. It is used
// in dequeueBuffer() if a width and height of zero is specified.
uint32_t mDefaultWidth;
// mDefaultHeight holds the default height of allocated buffers. It is used
// in dequeueBuffer() if a width and height of zero is specified.
uint32_t mDefaultHeight;
// mMaxAcquiredBufferCount is the number of buffers that the consumer may
// acquire at one time. It defaults to 1 and can be changed by the
// consumer via the setMaxAcquiredBufferCount method, but this may only be
// done when no producer is connected to the GonkBufferQueue.
//
// This value is used to derive the value returned for the
// MIN_UNDEQUEUED_BUFFERS query by the producer.
int mMaxAcquiredBufferCount;
// mDefaultMaxBufferCount is the default limit on the number of buffers
// that will be allocated at one time. This default limit is set by the
// consumer. The limit (as opposed to the default limit) may be
// overridden by the producer.
int mDefaultMaxBufferCount;
// mOverrideMaxBufferCount is the limit on the number of buffers that will
// be allocated at one time. This value is set by the image producer by
// calling setBufferCount. The default is zero, which means the producer
// doesn't care about the number of buffers in the pool. In that case
// mDefaultMaxBufferCount is used as the limit.
int mOverrideMaxBufferCount;
// mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to
// allocate new GraphicBuffer objects.
sp<IGraphicBufferAlloc> mGraphicBufferAlloc;
// mConsumerListener is used to notify the connected consumer of
// asynchronous events that it may wish to react to. It is initially set
// to NULL and is written by consumerConnect and consumerDisconnect.
sp<ConsumerListener> mConsumerListener;
// mSynchronousMode whether we're in synchronous mode or not
bool mSynchronousMode;
// mAllowSynchronousMode whether we allow synchronous mode or not. Set
// when the GonkBufferQueue is created (by the consumer).
const bool mAllowSynchronousMode;
// mConnectedApi indicates the producer API that is currently connected
// to this GonkBufferQueue. It defaults to NO_CONNECTED_API (= 0), and gets
// updated by the connect and disconnect methods.
int mConnectedApi;
// mDequeueCondition condition used for dequeueBuffer in synchronous mode
mutable Condition mDequeueCondition;
// mQueue is a FIFO of queued buffers used in synchronous mode
typedef Vector<int> Fifo;
Fifo mQueue;
// mAbandoned indicates that the GonkBufferQueue will no longer be used to
// consume image buffers pushed to it using the IGraphicBufferProducer
// interface. It is initialized to false, and set to true in the
// consumerDisconnect method. A GonkBufferQueue that has been abandoned will
// return the NO_INIT error from all IGraphicBufferProducer methods
// capable of returning an error.
bool mAbandoned;
// mConsumerName is a string used to identify the GonkBufferQueue in log
// messages. It is set by the setConsumerName method.
String8 mConsumerName;
// mMutex is the mutex used to prevent concurrent access to the member
// variables of GonkBufferQueue objects. It must be locked whenever the
// member variables are accessed.
mutable Mutex mMutex;
// mFrameCounter is the free running counter, incremented on every
// successful queueBuffer call.
uint64_t mFrameCounter;
// mBufferHasBeenQueued is true once a buffer has been queued. It is
// reset when something causes all buffers to be freed (e.g. changing the
// buffer count).
bool mBufferHasBeenQueued;
// mDefaultBufferFormat can be set so it will override
// the buffer format when it isn't specified in dequeueBuffer
uint32_t mDefaultBufferFormat;
// mConsumerUsageBits contains flags the consumer wants for GraphicBuffers
uint32_t mConsumerUsageBits;
// mTransformHint is used to optimize for screen rotations
uint32_t mTransformHint;
// mGeneration is the current generation of buffer slots
uint32_t mGeneration;
};
// ----------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_GUI_BUFFERQUEUE_H

View File

@ -0,0 +1,237 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C) 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_TAG "GonkConsumerBase"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
//#define LOG_NDEBUG 0
#define EGL_EGLEXT_PROTOTYPES
#include <hardware/hardware.h>
#include <gui/IGraphicBufferAlloc.h>
#include <utils/Log.h>
#include <utils/String8.h>
#include "GonkConsumerBase.h"
// Macros for including the GonkConsumerBase name in log messages
#define CB_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
#define CB_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define CB_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define CB_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define CB_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
namespace android {
// Get an ID that's unique within this process.
static int32_t createProcessUniqueId() {
static volatile int32_t globalCounter = 0;
return android_atomic_inc(&globalCounter);
}
GonkConsumerBase::GonkConsumerBase(const sp<GonkBufferQueue>& bufferQueue) :
mAbandoned(false),
mBufferQueue(bufferQueue) {
// Choose a name using the PID and a process-unique ID.
mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
// Note that we can't create an sp<...>(this) in a ctor that will not keep a
// reference once the ctor ends, as that would cause the refcount of 'this'
// dropping to 0 at the end of the ctor. Since all we need is a wp<...>
// that's what we create.
wp<GonkBufferQueue::ConsumerListener> listener;
sp<GonkBufferQueue::ConsumerListener> proxy;
listener = static_cast<GonkBufferQueue::ConsumerListener*>(this);
proxy = new GonkBufferQueue::ProxyConsumerListener(listener);
status_t err = mBufferQueue->consumerConnect(proxy);
if (err != NO_ERROR) {
CB_LOGE("GonkConsumerBase: error connecting to GonkBufferQueue: %s (%d)",
strerror(-err), err);
} else {
mBufferQueue->setConsumerName(mName);
}
}
GonkConsumerBase::~GonkConsumerBase() {
CB_LOGV("~GonkConsumerBase");
Mutex::Autolock lock(mMutex);
// Verify that abandon() has been called before we get here. This should
// be done by GonkConsumerBase::onLastStrongRef(), but it's possible for a
// derived class to override that method and not call
// GonkConsumerBase::onLastStrongRef().
LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~GonkConsumerBase was called, but the "
"consumer is not abandoned!", mName.string());
}
void GonkConsumerBase::onLastStrongRef(const void* id) {
abandon();
}
void GonkConsumerBase::freeBufferLocked(int slotIndex) {
CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
mSlots[slotIndex].mGraphicBuffer = 0;
mSlots[slotIndex].mFence = Fence::NO_FENCE;
}
// Used for refactoring, should not be in final interface
sp<GonkBufferQueue> GonkConsumerBase::getBufferQueue() const {
Mutex::Autolock lock(mMutex);
return mBufferQueue;
}
void GonkConsumerBase::onFrameAvailable() {
CB_LOGV("onFrameAvailable");
sp<FrameAvailableListener> listener;
{ // scope for the lock
Mutex::Autolock lock(mMutex);
listener = mFrameAvailableListener.promote();
}
if (listener != NULL) {
CB_LOGV("actually calling onFrameAvailable");
listener->onFrameAvailable();
}
}
void GonkConsumerBase::onBuffersReleased() {
Mutex::Autolock lock(mMutex);
CB_LOGV("onBuffersReleased");
if (mAbandoned) {
// Nothing to do if we're already abandoned.
return;
}
uint32_t mask = 0;
mBufferQueue->getReleasedBuffers(&mask);
for (int i = 0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) {
if (mask & (1 << i)) {
freeBufferLocked(i);
}
}
}
void GonkConsumerBase::abandon() {
CB_LOGV("abandon");
Mutex::Autolock lock(mMutex);
if (!mAbandoned) {
abandonLocked();
mAbandoned = true;
}
}
void GonkConsumerBase::abandonLocked() {
CB_LOGV("abandonLocked");
for (int i =0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) {
freeBufferLocked(i);
}
// disconnect from the GonkBufferQueue
mBufferQueue->consumerDisconnect();
mBufferQueue.clear();
}
void GonkConsumerBase::setFrameAvailableListener(
const wp<FrameAvailableListener>& listener) {
CB_LOGV("setFrameAvailableListener");
Mutex::Autolock lock(mMutex);
mFrameAvailableListener = listener;
}
void GonkConsumerBase::dump(String8& result) const {
char buffer[1024];
dump(result, "", buffer, 1024);
}
void GonkConsumerBase::dump(String8& result, const char* prefix,
char* buffer, size_t size) const {
Mutex::Autolock _l(mMutex);
dumpLocked(result, prefix, buffer, size);
}
void GonkConsumerBase::dumpLocked(String8& result, const char* prefix,
char* buffer, size_t SIZE) const {
snprintf(buffer, SIZE, "%smAbandoned=%d\n", prefix, int(mAbandoned));
result.append(buffer);
if (!mAbandoned) {
mBufferQueue->dump(result, prefix, buffer, SIZE);
}
}
status_t GonkConsumerBase::acquireBufferLocked(GonkBufferQueue::BufferItem *item) {
status_t err = mBufferQueue->acquireBuffer(item);
if (err != NO_ERROR) {
return err;
}
if (item->mGraphicBuffer != NULL) {
mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer;
}
mSlots[item->mBuf].mFence = item->mFence;
CB_LOGV("acquireBufferLocked: -> slot=%d", item->mBuf);
return OK;
}
status_t GonkConsumerBase::addReleaseFence(int slot, const sp<Fence>& fence) {
Mutex::Autolock lock(mMutex);
return addReleaseFenceLocked(slot, fence);
}
status_t GonkConsumerBase::addReleaseFenceLocked(int slot, const sp<Fence>& fence) {
CB_LOGV("addReleaseFenceLocked: slot=%d", slot);
if (!mSlots[slot].mFence.get()) {
mSlots[slot].mFence = fence;
} else {
sp<Fence> mergedFence = Fence::merge(
String8::format("%.28s:%d", mName.string(), slot),
mSlots[slot].mFence, fence);
if (!mergedFence.get()) {
CB_LOGE("failed to merge release fences");
// synchronization is broken, the best we can do is hope fences
// signal in order so the new fence will act like a union
mSlots[slot].mFence = fence;
return BAD_VALUE;
}
mSlots[slot].mFence = mergedFence;
}
return OK;
}
status_t GonkConsumerBase::releaseBufferLocked(int slot) {
CB_LOGV("releaseBufferLocked: slot=%d", slot);
status_t err = mBufferQueue->releaseBuffer(slot, mSlots[slot].mFence);
if (err == GonkBufferQueue::STALE_BUFFER_SLOT) {
freeBufferLocked(slot);
}
mSlots[slot].mFence = Fence::NO_FENCE;
return err;
}
} // namespace android

View File

@ -0,0 +1,231 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C) 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 NATIVEWINDOW_GONKCONSUMERBASE_H
#define NATIVEWINDOW_GONKCONSUMERBASE_H
#include <ui/GraphicBuffer.h>
#include <utils/String8.h>
#include <utils/Vector.h>
#include <utils/threads.h>
#include "GonkBufferQueue.h"
namespace android {
// ----------------------------------------------------------------------------
class String8;
// GonkConsumerBase is a base class for GonkBufferQueue consumer end-points. It
// handles common tasks like management of the connection to the GonkBufferQueue
// and the buffer pool.
class GonkConsumerBase : public virtual RefBase,
protected GonkBufferQueue::ConsumerListener {
public:
struct FrameAvailableListener : public virtual RefBase {
// onFrameAvailable() is called each time an additional frame becomes
// available for consumption. This means that frames that are queued
// while in asynchronous mode only trigger the callback if no previous
// frames are pending. Frames queued while in synchronous mode always
// trigger the callback.
//
// This is called without any lock held and can be called concurrently
// by multiple threads.
virtual void onFrameAvailable() = 0;
};
virtual ~GonkConsumerBase();
// abandon frees all the buffers and puts the GonkConsumerBase into the
// 'abandoned' state. Once put in this state the GonkConsumerBase can never
// leave it. When in the 'abandoned' state, all methods of the
// IGraphicBufferProducer interface will fail with the NO_INIT error.
//
// Note that while calling this method causes all the buffers to be freed
// from the perspective of the the GonkConsumerBase, if there are additional
// references on the buffers (e.g. if a buffer is referenced by a client
// or by OpenGL ES as a texture) then those buffer will remain allocated.
void abandon();
// set the name of the GonkConsumerBase that will be used to identify it in
// log messages.
void setName(const String8& name);
// getBufferQueue returns the GonkBufferQueue object to which this
// GonkConsumerBase is connected.
sp<GonkBufferQueue> getBufferQueue() const;
// dump writes the current state to a string. Child classes should add
// their state to the dump by overriding the dumpLocked method, which is
// called by these methods after locking the mutex.
void dump(String8& result) const;
void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const;
// setFrameAvailableListener sets the listener object that will be notified
// when a new frame becomes available.
void setFrameAvailableListener(const wp<FrameAvailableListener>& listener);
private:
GonkConsumerBase(const GonkConsumerBase&);
void operator=(const GonkConsumerBase&);
protected:
// GonkConsumerBase constructs a new GonkConsumerBase object to consume image
// buffers from the given GonkBufferQueue.
GonkConsumerBase(const sp<GonkBufferQueue> &bufferQueue);
// onLastStrongRef gets called by RefBase just before the dtor of the most
// derived class. It is used to clean up the buffers so that GonkConsumerBase
// can coordinate the clean-up by calling into virtual methods implemented
// by the derived classes. This would not be possible from the
// ConsuemrBase dtor because by the time that gets called the derived
// classes have already been destructed.
//
// This methods should not need to be overridden by derived classes, but
// if they are overridden the GonkConsumerBase implementation must be called
// from the derived class.
virtual void onLastStrongRef(const void* id);
// Implementation of the GonkBufferQueue::ConsumerListener interface. These
// calls are used to notify the GonkConsumerBase of asynchronous events in the
// GonkBufferQueue. These methods should not need to be overridden by derived
// classes, but if they are overridden the GonkConsumerBase implementation
// must be called from the derived class.
virtual void onFrameAvailable();
virtual void onBuffersReleased();
// freeBufferLocked frees up the given buffer slot. If the slot has been
// initialized this will release the reference to the GraphicBuffer in that
// slot. Otherwise it has no effect.
//
// Derived classes should override this method to clean up any state they
// keep per slot. If it is overridden, the derived class's implementation
// must call GonkConsumerBase::freeBufferLocked.
//
// This method must be called with mMutex locked.
virtual void freeBufferLocked(int slotIndex);
// abandonLocked puts the GonkBufferQueue into the abandoned state, causing
// all future operations on it to fail. This method rather than the public
// abandon method should be overridden by child classes to add abandon-
// time behavior.
//
// Derived classes should override this method to clean up any object
// state they keep (as opposed to per-slot state). If it is overridden,
// the derived class's implementation must call GonkConsumerBase::abandonLocked.
//
// This method must be called with mMutex locked.
virtual void abandonLocked();
// dumpLocked dumps the current state of the GonkConsumerBase object to the
// result string. Each line is prefixed with the string pointed to by the
// prefix argument. The buffer argument points to a buffer that may be
// used for intermediate formatting data, and the size of that buffer is
// indicated by the size argument.
//
// Derived classes should override this method to dump their internal
// state. If this method is overridden the derived class's implementation
// should call GonkConsumerBase::dumpLocked.
//
// This method must be called with mMutex locked.
virtual void dumpLocked(String8& result, const char* prefix, char* buffer,
size_t size) const;
// acquireBufferLocked fetches the next buffer from the GonkBufferQueue and
// updates the buffer slot for the buffer returned.
//
// Derived classes should override this method to perform any
// initialization that must take place the first time a buffer is assigned
// to a slot. If it is overridden the derived class's implementation must
// call GonkConsumerBase::acquireBufferLocked.
virtual status_t acquireBufferLocked(GonkBufferQueue::BufferItem *item);
// releaseBufferLocked relinquishes control over a buffer, returning that
// control to the GonkBufferQueue.
//
// Derived classes should override this method to perform any cleanup that
// must take place when a buffer is released back to the GonkBufferQueue. If
// it is overridden the derived class's implementation must call
// GonkConsumerBase::releaseBufferLocked.
virtual status_t releaseBufferLocked(int buf);
// addReleaseFence* adds the sync points associated with a fence to the set
// of sync points that must be reached before the buffer in the given slot
// may be used after the slot has been released. This should be called by
// derived classes each time some asynchronous work is kicked off that
// references the buffer.
status_t addReleaseFence(int slot, const sp<Fence>& fence);
status_t addReleaseFenceLocked(int slot, const sp<Fence>& fence);
// Slot contains the information and object references that
// GonkConsumerBase maintains about a GonkBufferQueue buffer slot.
struct Slot {
// mGraphicBuffer is the Gralloc buffer store in the slot or NULL if
// no Gralloc buffer is in the slot.
sp<GraphicBuffer> mGraphicBuffer;
// mFence is a fence which will signal when the buffer associated with
// this buffer slot is no longer being used by the consumer and can be
// overwritten. The buffer can be dequeued before the fence signals;
// the producer is responsible for delaying writes until it signals.
sp<Fence> mFence;
};
// mSlots stores the buffers that have been allocated by the GonkBufferQueue
// for each buffer slot. It is initialized to null pointers, and gets
// filled in with the result of GonkBufferQueue::acquire when the
// client dequeues a buffer from a
// slot that has not yet been used. The buffer allocated to a slot will also
// be replaced if the requested buffer usage or geometry differs from that
// of the buffer allocated to a slot.
Slot mSlots[GonkBufferQueue::NUM_BUFFER_SLOTS];
// mAbandoned indicates that the GonkBufferQueue will no longer be used to
// consume images buffers pushed to it using the IGraphicBufferProducer
// interface. It is initialized to false, and set to true in the abandon
// method. A GonkBufferQueue that has been abandoned will return the NO_INIT
// error from all IGonkConsumerBase methods capable of returning an error.
bool mAbandoned;
// mName is a string used to identify the GonkConsumerBase in log messages.
// It can be set by the setName method.
String8 mName;
// mFrameAvailableListener is the listener object that will be called when a
// new frame becomes available. If it is not NULL it will be called from
// queueBuffer.
wp<FrameAvailableListener> mFrameAvailableListener;
// The GonkConsumerBase has-a GonkBufferQueue and is responsible for creating this object
// if none is supplied
sp<GonkBufferQueue> mBufferQueue;
// mMutex is the mutex used to prevent concurrent access to the member
// variables of GonkConsumerBase objects. It must be locked whenever the
// member variables are accessed or when any of the *Locked methods are
// called.
//
// This mutex is intended to be locked by derived classes.
mutable Mutex mMutex;
};
// ----------------------------------------------------------------------------
}; // namespace android
#endif // NATIVEWINDOW_GONKCONSUMERBASE_H

View File

@ -1,2 +1,20 @@
/* Copyright 2013 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 "GonkNativeWindowICS.h"
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18
# include "GonkNativeWindowJB.h"
#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION == 15
# include "GonkNativeWindowICS.h"
#endif

View File

@ -1,2 +1,20 @@
/* Copyright 2013 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 "GonkNativeWindowClientICS.h"
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18
# include "GonkNativeWindowClientJB.h"
#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION == 15
# include "GonkNativeWindowClientICS.h"
#endif

View File

@ -0,0 +1,652 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C) 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_TAG "GonkNativeWindowClient"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
//#define LOG_NDEBUG 0
#include <android/native_window.h>
#include <cutils/trace.h>
#include <binder/Parcel.h>
#include <utils/Log.h>
#include <ui/Fence.h>
#include "GonkNativeWindowClientJB.h"
namespace android {
GonkNativeWindowClient::GonkNativeWindowClient(
const sp<IGraphicBufferProducer>& bufferProducer)
: mGraphicBufferProducer(bufferProducer)
{
// Initialize the ANativeWindow function pointers.
ANativeWindow::setSwapInterval = hook_setSwapInterval;
ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
ANativeWindow::cancelBuffer = hook_cancelBuffer;
ANativeWindow::queueBuffer = hook_queueBuffer;
ANativeWindow::query = hook_query;
ANativeWindow::perform = hook_perform;
ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED;
ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED;
ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED;
const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
mReqWidth = 0;
mReqHeight = 0;
mReqFormat = 0;
mReqUsage = 0;
mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
mCrop.clear();
mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
mTransform = 0;
mDefaultWidth = 0;
mDefaultHeight = 0;
mUserWidth = 0;
mUserHeight = 0;
mTransformHint = 0;
mConsumerRunningBehind = false;
mConnectedToCpu = false;
}
GonkNativeWindowClient::~GonkNativeWindowClient() {
if (mConnectedToCpu) {
GonkNativeWindowClient::disconnect(NATIVE_WINDOW_API_CPU);
}
}
sp<IGraphicBufferProducer> GonkNativeWindowClient::getIGraphicBufferProducer() const {
return mGraphicBufferProducer;
}
int GonkNativeWindowClient::hook_setSwapInterval(ANativeWindow* window, int interval) {
GonkNativeWindowClient* c = getSelf(window);
return c->setSwapInterval(interval);
}
int GonkNativeWindowClient::hook_dequeueBuffer(ANativeWindow* window,
ANativeWindowBuffer** buffer, int* fenceFd) {
GonkNativeWindowClient* c = getSelf(window);
return c->dequeueBuffer(buffer, fenceFd);
}
int GonkNativeWindowClient::hook_cancelBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer, int fenceFd) {
GonkNativeWindowClient* c = getSelf(window);
return c->cancelBuffer(buffer, fenceFd);
}
int GonkNativeWindowClient::hook_queueBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer, int fenceFd) {
GonkNativeWindowClient* c = getSelf(window);
return c->queueBuffer(buffer, fenceFd);
}
int GonkNativeWindowClient::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer** buffer) {
GonkNativeWindowClient* c = getSelf(window);
ANativeWindowBuffer* buf;
int fenceFd = -1;
int result = c->dequeueBuffer(&buf, &fenceFd);
sp<Fence> fence(new Fence(fenceFd));
int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED");
if (waitResult != OK) {
ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d",
waitResult);
c->cancelBuffer(buf, -1);
return waitResult;
}
*buffer = buf;
return result;
}
int GonkNativeWindowClient::hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
GonkNativeWindowClient* c = getSelf(window);
return c->cancelBuffer(buffer, -1);
}
int GonkNativeWindowClient::hook_lockBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
GonkNativeWindowClient* c = getSelf(window);
return c->lockBuffer_DEPRECATED(buffer);
}
int GonkNativeWindowClient::hook_queueBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
GonkNativeWindowClient* c = getSelf(window);
return c->queueBuffer(buffer, -1);
}
int GonkNativeWindowClient::hook_query(const ANativeWindow* window,
int what, int* value) {
const GonkNativeWindowClient* c = getSelf(window);
return c->query(what, value);
}
int GonkNativeWindowClient::hook_perform(ANativeWindow* window, int operation, ...) {
va_list args;
va_start(args, operation);
GonkNativeWindowClient* c = getSelf(window);
return c->perform(operation, args);
}
int GonkNativeWindowClient::setSwapInterval(int interval) {
// EGL specification states:
// interval is silently clamped to minimum and maximum implementation
// dependent values before being stored.
// Although we don't have to, we apply the same logic here.
if (interval < minSwapInterval)
interval = minSwapInterval;
if (interval > maxSwapInterval)
interval = maxSwapInterval;
status_t res = mGraphicBufferProducer->setSynchronousMode(interval ? true : false);
return res;
}
int GonkNativeWindowClient::dequeueBuffer(android_native_buffer_t** buffer,
int* fenceFd) {
ALOGV("GonkNativeWindowClient::dequeueBuffer");
Mutex::Autolock lock(mMutex);
int buf = -1;
int reqW = mReqWidth ? mReqWidth : mUserWidth;
int reqH = mReqHeight ? mReqHeight : mUserHeight;
sp<Fence> fence;
status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence,
reqW, reqH, mReqFormat, mReqUsage);
if (result < 0) {
ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d)"
"failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage,
result);
return result;
}
sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) {
freeAllBuffers();
}
if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
if (result != NO_ERROR) {
ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d",
result);
return result;
}
}
if (fence->isValid()) {
*fenceFd = fence->dup();
if (*fenceFd == -1) {
ALOGE("dequeueBuffer: error duping fence: %d", errno);
// dup() should never fail; something is badly wrong. Soldier on
// and hope for the best; the worst that should happen is some
// visible corruption that lasts until the next frame.
}
} else {
*fenceFd = -1;
}
*buffer = gbuf.get();
return OK;
}
int GonkNativeWindowClient::cancelBuffer(android_native_buffer_t* buffer,
int fenceFd) {
ALOGV("GonkNativeWindowClient::cancelBuffer");
Mutex::Autolock lock(mMutex);
int i = getSlotFromBufferLocked(buffer);
if (i < 0) {
return i;
}
sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
mGraphicBufferProducer->cancelBuffer(i, fence);
return OK;
}
int GonkNativeWindowClient::getSlotFromBufferLocked(
android_native_buffer_t* buffer) const {
bool dumpedState = false;
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
if (mSlots[i].buffer != NULL &&
mSlots[i].buffer->handle == buffer->handle) {
return i;
}
}
ALOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle);
return BAD_VALUE;
}
int GonkNativeWindowClient::lockBuffer_DEPRECATED(android_native_buffer_t* buffer) {
ALOGV("GonkNativeWindowClient::lockBuffer");
Mutex::Autolock lock(mMutex);
return OK;
}
int GonkNativeWindowClient::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
ALOGV("GonkNativeWindowClient::queueBuffer");
Mutex::Autolock lock(mMutex);
int64_t timestamp;
if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) {
timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
ALOGV("GonkNativeWindowClient::queueBuffer making up timestamp: %.2f ms",
timestamp / 1000000.f);
} else {
timestamp = mTimestamp;
}
int i = getSlotFromBufferLocked(buffer);
if (i < 0) {
return i;
}
// Make sure the crop rectangle is entirely inside the buffer.
Rect crop;
mCrop.intersect(Rect(buffer->width, buffer->height), &crop);
sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
IGraphicBufferProducer::QueueBufferOutput output;
IGraphicBufferProducer::QueueBufferInput input(timestamp, crop, mScalingMode,
mTransform, fence);
status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
if (err != OK) {
ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
}
uint32_t numPendingBuffers = 0;
output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,
&numPendingBuffers);
mConsumerRunningBehind = (numPendingBuffers >= 2);
return err;
}
int GonkNativeWindowClient::query(int what, int* value) const {
ALOGV("GonkNativeWindowClient::query");
{ // scope for the lock
Mutex::Autolock lock(mMutex);
switch (what) {
case NATIVE_WINDOW_FORMAT:
if (mReqFormat) {
*value = mReqFormat;
return NO_ERROR;
}
break;
case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: {
//sp<ISurfaceComposer> composer(
// ComposerService::getComposerService());
//if (composer->authenticateSurfaceTexture(mGraphicBufferProducer)) {
// *value = 1;
//} else {
*value = 0;
//}
return NO_ERROR;
}
case NATIVE_WINDOW_CONCRETE_TYPE:
*value = NATIVE_WINDOW_SURFACE;
return NO_ERROR;
case NATIVE_WINDOW_DEFAULT_WIDTH:
*value = mUserWidth ? mUserWidth : mDefaultWidth;
return NO_ERROR;
case NATIVE_WINDOW_DEFAULT_HEIGHT:
*value = mUserHeight ? mUserHeight : mDefaultHeight;
return NO_ERROR;
case NATIVE_WINDOW_TRANSFORM_HINT:
*value = mTransformHint;
return NO_ERROR;
case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: {
status_t err = NO_ERROR;
if (!mConsumerRunningBehind) {
*value = 0;
} else {
err = mGraphicBufferProducer->query(what, value);
if (err == NO_ERROR) {
mConsumerRunningBehind = *value;
}
}
return err;
}
}
}
return mGraphicBufferProducer->query(what, value);
}
int GonkNativeWindowClient::perform(int operation, va_list args)
{
int res = NO_ERROR;
switch (operation) {
case NATIVE_WINDOW_CONNECT:
// deprecated. must return NO_ERROR.
break;
case NATIVE_WINDOW_DISCONNECT:
// deprecated. must return NO_ERROR.
break;
case NATIVE_WINDOW_SET_USAGE:
res = dispatchSetUsage(args);
break;
case NATIVE_WINDOW_SET_CROP:
res = dispatchSetCrop(args);
break;
case NATIVE_WINDOW_SET_BUFFER_COUNT:
res = dispatchSetBufferCount(args);
break;
case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
res = dispatchSetBuffersGeometry(args);
break;
case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
res = dispatchSetBuffersTransform(args);
break;
case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
res = dispatchSetBuffersTimestamp(args);
break;
case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
res = dispatchSetBuffersDimensions(args);
break;
case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS:
res = dispatchSetBuffersUserDimensions(args);
break;
case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
res = dispatchSetBuffersFormat(args);
break;
case NATIVE_WINDOW_LOCK:
res = dispatchLock(args);
break;
case NATIVE_WINDOW_UNLOCK_AND_POST:
res = dispatchUnlockAndPost(args);
break;
case NATIVE_WINDOW_SET_SCALING_MODE:
res = dispatchSetScalingMode(args);
break;
case NATIVE_WINDOW_API_CONNECT:
res = dispatchConnect(args);
break;
case NATIVE_WINDOW_API_DISCONNECT:
res = dispatchDisconnect(args);
break;
default:
res = NAME_NOT_FOUND;
break;
}
return res;
}
int GonkNativeWindowClient::dispatchConnect(va_list args) {
int api = va_arg(args, int);
return connect(api);
}
int GonkNativeWindowClient::dispatchDisconnect(va_list args) {
int api = va_arg(args, int);
return disconnect(api);
}
int GonkNativeWindowClient::dispatchSetUsage(va_list args) {
int usage = va_arg(args, int);
return setUsage(usage);
}
int GonkNativeWindowClient::dispatchSetCrop(va_list args) {
android_native_rect_t const* rect = va_arg(args, android_native_rect_t*);
return setCrop(reinterpret_cast<Rect const*>(rect));
}
int GonkNativeWindowClient::dispatchSetBufferCount(va_list args) {
size_t bufferCount = va_arg(args, size_t);
return setBufferCount(bufferCount);
}
int GonkNativeWindowClient::dispatchSetBuffersGeometry(va_list args) {
int w = va_arg(args, int);
int h = va_arg(args, int);
int f = va_arg(args, int);
int err = setBuffersDimensions(w, h);
if (err != 0) {
return err;
}
return setBuffersFormat(f);
}
int GonkNativeWindowClient::dispatchSetBuffersDimensions(va_list args) {
int w = va_arg(args, int);
int h = va_arg(args, int);
return setBuffersDimensions(w, h);
}
int GonkNativeWindowClient::dispatchSetBuffersUserDimensions(va_list args) {
int w = va_arg(args, int);
int h = va_arg(args, int);
return setBuffersUserDimensions(w, h);
}
int GonkNativeWindowClient::dispatchSetBuffersFormat(va_list args) {
int f = va_arg(args, int);
return setBuffersFormat(f);
}
int GonkNativeWindowClient::dispatchSetScalingMode(va_list args) {
int m = va_arg(args, int);
return setScalingMode(m);
}
int GonkNativeWindowClient::dispatchSetBuffersTransform(va_list args) {
int transform = va_arg(args, int);
return setBuffersTransform(transform);
}
int GonkNativeWindowClient::dispatchSetBuffersTimestamp(va_list args) {
int64_t timestamp = va_arg(args, int64_t);
return setBuffersTimestamp(timestamp);
}
int GonkNativeWindowClient::dispatchLock(va_list args) {
ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*);
ARect* inOutDirtyBounds = va_arg(args, ARect*);
return lock(outBuffer, inOutDirtyBounds);
}
int GonkNativeWindowClient::dispatchUnlockAndPost(va_list args) {
return unlockAndPost();
}
int GonkNativeWindowClient::connect(int api) {
ALOGV("GonkNativeWindowClient::connect");
Mutex::Autolock lock(mMutex);
IGraphicBufferProducer::QueueBufferOutput output;
int err = mGraphicBufferProducer->connect(api, &output);
if (err == NO_ERROR) {
uint32_t numPendingBuffers = 0;
output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,
&numPendingBuffers);
mConsumerRunningBehind = (numPendingBuffers >= 2);
}
if (!err && api == NATIVE_WINDOW_API_CPU) {
mConnectedToCpu = true;
}
return err;
}
int GonkNativeWindowClient::disconnect(int api) {
ALOGV("GonkNativeWindowClient::disconnect");
Mutex::Autolock lock(mMutex);
freeAllBuffers();
int err = mGraphicBufferProducer->disconnect(api);
if (!err) {
mReqFormat = 0;
mReqWidth = 0;
mReqHeight = 0;
mReqUsage = 0;
mCrop.clear();
mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
mTransform = 0;
if (api == NATIVE_WINDOW_API_CPU) {
mConnectedToCpu = false;
}
}
return err;
}
int GonkNativeWindowClient::setUsage(uint32_t reqUsage)
{
ALOGV("GonkNativeWindowClient::setUsage");
Mutex::Autolock lock(mMutex);
mReqUsage = reqUsage;
return OK;
}
int GonkNativeWindowClient::setCrop(Rect const* rect)
{
Rect realRect;
if (rect == NULL || rect->isEmpty()) {
realRect.clear();
} else {
realRect = *rect;
}
ALOGV("GonkNativeWindowClient::setCrop rect=[%d %d %d %d]",
realRect.left, realRect.top, realRect.right, realRect.bottom);
Mutex::Autolock lock(mMutex);
mCrop = realRect;
return NO_ERROR;
}
int GonkNativeWindowClient::setBufferCount(int bufferCount)
{
ALOGV("GonkNativeWindowClient::setBufferCount");
Mutex::Autolock lock(mMutex);
status_t err = mGraphicBufferProducer->setBufferCount(bufferCount);
ALOGE_IF(err, "IGraphicBufferProducer::setBufferCount(%d) returned %s",
bufferCount, strerror(-err));
if (err == NO_ERROR) {
freeAllBuffers();
}
return err;
}
int GonkNativeWindowClient::setBuffersDimensions(int w, int h)
{
ALOGV("GonkNativeWindowClient::setBuffersDimensions");
if (w<0 || h<0)
return BAD_VALUE;
if ((w && !h) || (!w && h))
return BAD_VALUE;
Mutex::Autolock lock(mMutex);
mReqWidth = w;
mReqHeight = h;
return NO_ERROR;
}
int GonkNativeWindowClient::setBuffersUserDimensions(int w, int h)
{
ALOGV("GonkNativeWindowClient::setBuffersUserDimensions");
if (w<0 || h<0)
return BAD_VALUE;
if ((w && !h) || (!w && h))
return BAD_VALUE;
Mutex::Autolock lock(mMutex);
mUserWidth = w;
mUserHeight = h;
return NO_ERROR;
}
int GonkNativeWindowClient::setBuffersFormat(int format)
{
ALOGV("GonkNativeWindowClient::setBuffersFormat");
if (format<0)
return BAD_VALUE;
Mutex::Autolock lock(mMutex);
mReqFormat = format;
return NO_ERROR;
}
int GonkNativeWindowClient::setScalingMode(int mode)
{
ALOGV("GonkNativeWindowClient::setScalingMode(%d)", mode);
switch (mode) {
case NATIVE_WINDOW_SCALING_MODE_FREEZE:
case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
break;
default:
ALOGE("unknown scaling mode: %d", mode);
return BAD_VALUE;
}
Mutex::Autolock lock(mMutex);
mScalingMode = mode;
return NO_ERROR;
}
int GonkNativeWindowClient::setBuffersTransform(int transform)
{
ALOGV("GonkNativeWindowClient::setBuffersTransform");
Mutex::Autolock lock(mMutex);
mTransform = transform;
return NO_ERROR;
}
int GonkNativeWindowClient::setBuffersTimestamp(int64_t timestamp)
{
ALOGV("GonkNativeWindowClient::setBuffersTimestamp");
Mutex::Autolock lock(mMutex);
mTimestamp = timestamp;
return NO_ERROR;
}
void GonkNativeWindowClient::freeAllBuffers() {
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
mSlots[i].buffer = 0;
}
}
// ----------------------------------------------------------------------
// the lock/unlock APIs must be used from the same thread
// ----------------------------------------------------------------------------
status_t GonkNativeWindowClient::lock(
ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
{
return INVALID_OPERATION;
}
status_t GonkNativeWindowClient::unlockAndPost()
{
return INVALID_OPERATION;
}
}; // namespace android

View File

@ -0,0 +1,252 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C) 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 NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_JB_H
#define NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_JB_H
#include <gui/IGraphicBufferProducer.h>
#include <ui/ANativeObjectBase.h>
#include <ui/Region.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
#include <utils/KeyedVector.h>
#include "GonkBufferQueue.h"
struct ANativeWindow_Buffer;
namespace android {
/*
* An implementation of ANativeWindow that feeds graphics buffers into a
* BufferQueue.
*
* This is typically used by programs that want to render frames through
* some means (maybe OpenGL, a software renderer, or a hardware decoder)
* and have the frames they create forwarded to SurfaceFlinger for
* compositing. For example, a video decoder could render a frame and call
* eglSwapBuffers(), which invokes ANativeWindow callbacks defined by
* GonkNativeWindowClient. GonkNativeWindowClient then forwards the buffers through Binder IPC
* to the BufferQueue's producer interface, providing the new frame to a
* consumer such as GLConsumer.
*/
class GonkNativeWindowClient
: public ANativeObjectBase<ANativeWindow, GonkNativeWindowClient, RefBase>
{
public:
/*
* creates a GonkNativeWindowClient from the given IGraphicBufferProducer (which concrete
* implementation is a BufferQueue).
*
* GonkNativeWindowClient is mainly state-less while it's disconnected, it can be
* viewed as a glorified IGraphicBufferProducer holder. It's therefore
* safe to create other GonkNativeWindowClients from the same IGraphicBufferProducer.
*
* However, once a GonkNativeWindowClient is connected, it'll prevent other GonkNativeWindowClients
* referring to the same IGraphicBufferProducer to become connected and
* therefore prevent them to be used as actual producers of buffers.
*/
GonkNativeWindowClient(const sp<IGraphicBufferProducer>& bufferProducer);
/* getIGraphicBufferProducer() returns the IGraphicBufferProducer this
* GonkNativeWindowClient was created with. Usually it's an error to use the
* IGraphicBufferProducer while the GonkNativeWindowClient is connected.
*/
sp<IGraphicBufferProducer> getIGraphicBufferProducer() const;
/* convenience function to check that the given surface is non NULL as
* well as its IGraphicBufferProducer */
static bool isValid(const sp<GonkNativeWindowClient>& surface) {
return surface != NULL && surface->getIGraphicBufferProducer() != NULL;
}
protected:
virtual ~GonkNativeWindowClient();
private:
// can't be copied
GonkNativeWindowClient& operator = (const GonkNativeWindowClient& rhs);
GonkNativeWindowClient(const GonkNativeWindowClient& rhs);
// ANativeWindow hooks
static int hook_cancelBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer, int fenceFd);
static int hook_dequeueBuffer(ANativeWindow* window,
ANativeWindowBuffer** buffer, int* fenceFd);
static int hook_perform(ANativeWindow* window, int operation, ...);
static int hook_query(const ANativeWindow* window, int what, int* value);
static int hook_queueBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer, int fenceFd);
static int hook_setSwapInterval(ANativeWindow* window, int interval);
static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer* buffer);
static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer** buffer);
static int hook_lockBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer* buffer);
static int hook_queueBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer* buffer);
int dispatchConnect(va_list args);
int dispatchDisconnect(va_list args);
int dispatchSetBufferCount(va_list args);
int dispatchSetBuffersGeometry(va_list args);
int dispatchSetBuffersDimensions(va_list args);
int dispatchSetBuffersUserDimensions(va_list args);
int dispatchSetBuffersFormat(va_list args);
int dispatchSetScalingMode(va_list args);
int dispatchSetBuffersTransform(va_list args);
int dispatchSetBuffersTimestamp(va_list args);
int dispatchSetCrop(va_list args);
int dispatchSetPostTransformCrop(va_list args);
int dispatchSetUsage(va_list args);
int dispatchLock(va_list args);
int dispatchUnlockAndPost(va_list args);
protected:
virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
virtual int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd);
virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd);
virtual int perform(int operation, va_list args);
virtual int query(int what, int* value) const;
virtual int setSwapInterval(int interval);
virtual int lockBuffer_DEPRECATED(ANativeWindowBuffer* buffer);
virtual int connect(int api);
virtual int disconnect(int api);
virtual int setBufferCount(int bufferCount);
virtual int setBuffersDimensions(int w, int h);
virtual int setBuffersUserDimensions(int w, int h);
virtual int setBuffersFormat(int format);
virtual int setScalingMode(int mode);
virtual int setBuffersTransform(int transform);
virtual int setBuffersTimestamp(int64_t timestamp);
virtual int setCrop(Rect const* rect);
virtual int setUsage(uint32_t reqUsage);
public:
virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
virtual int unlockAndPost();
protected:
enum { NUM_BUFFER_SLOTS = GonkBufferQueue::NUM_BUFFER_SLOTS };
enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
private:
void freeAllBuffers();
int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
struct BufferSlot {
sp<GraphicBuffer> buffer;
Region dirtyRegion;
};
// mSurfaceTexture is the interface to the surface texture server. All
// operations on the surface texture client ultimately translate into
// interactions with the server using this interface.
// TODO: rename to mBufferProducer
sp<IGraphicBufferProducer> mGraphicBufferProducer;
// mSlots stores the buffers that have been allocated for each buffer slot.
// It is initialized to null pointers, and gets filled in with the result of
// IGraphicBufferProducer::requestBuffer when the client dequeues a buffer from a
// slot that has not yet been used. The buffer allocated to a slot will also
// be replaced if the requested buffer usage or geometry differs from that
// of the buffer allocated to a slot.
BufferSlot mSlots[NUM_BUFFER_SLOTS];
// mReqWidth is the buffer width that will be requested at the next dequeue
// operation. It is initialized to 1.
uint32_t mReqWidth;
// mReqHeight is the buffer height that will be requested at the next
// dequeue operation. It is initialized to 1.
uint32_t mReqHeight;
// mReqFormat is the buffer pixel format that will be requested at the next
// deuque operation. It is initialized to PIXEL_FORMAT_RGBA_8888.
uint32_t mReqFormat;
// mReqUsage is the set of buffer usage flags that will be requested
// at the next deuque operation. It is initialized to 0.
uint32_t mReqUsage;
// mTimestamp is the timestamp that will be used for the next buffer queue
// operation. It defaults to NATIVE_WINDOW_TIMESTAMP_AUTO, which means that
// a timestamp is auto-generated when queueBuffer is called.
int64_t mTimestamp;
// mCrop is the crop rectangle that will be used for the next buffer
// that gets queued. It is set by calling setCrop.
Rect mCrop;
// mScalingMode is the scaling mode that will be used for the next
// buffers that get queued. It is set by calling setScalingMode.
int mScalingMode;
// mTransform is the transform identifier that will be used for the next
// buffer that gets queued. It is set by calling setTransform.
uint32_t mTransform;
// mDefaultWidth is default width of the buffers, regardless of the
// native_window_set_buffers_dimensions call.
uint32_t mDefaultWidth;
// mDefaultHeight is default height of the buffers, regardless of the
// native_window_set_buffers_dimensions call.
uint32_t mDefaultHeight;
// mUserWidth, if non-zero, is an application-specified override
// of mDefaultWidth. This is lower priority than the width set by
// native_window_set_buffers_dimensions.
uint32_t mUserWidth;
// mUserHeight, if non-zero, is an application-specified override
// of mDefaultHeight. This is lower priority than the height set
// by native_window_set_buffers_dimensions.
uint32_t mUserHeight;
// mTransformHint is the transform probably applied to buffers of this
// window. this is only a hint, actual transform may differ.
uint32_t mTransformHint;
// mConsumerRunningBehind whether the consumer is running more than
// one buffer behind the producer.
mutable bool mConsumerRunningBehind;
// mMutex is the mutex used to prevent concurrent access to the member
// variables of GonkNativeWindowClient objects. It must be locked whenever the
// member variables are accessed.
mutable Mutex mMutex;
// must be used from the lock/unlock thread
sp<GraphicBuffer> mLockedBuffer;
sp<GraphicBuffer> mPostedBuffer;
bool mConnectedToCpu;
// must be accessed from lock/unlock thread only
Region mDirtyRegion;
};
}; // namespace android
#endif // NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_JB_H

View File

@ -0,0 +1,163 @@
/*
* Copyright (C) 2012 The Android Open Source Project
* Copyright (C) 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 "GonkNativeWindow"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <utils/Log.h>
#include "GonkNativeWindowJB.h"
#include "GrallocImages.h"
#define BI_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
#define BI_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define BI_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define BI_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define BI_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
using namespace mozilla::layers;
namespace android {
GonkNativeWindow::GonkNativeWindow() :
GonkConsumerBase(new GonkBufferQueue(true) )
{
mBufferQueue->setMaxAcquiredBufferCount(GonkBufferQueue::MIN_UNDEQUEUED_BUFFERS);
}
GonkNativeWindow::~GonkNativeWindow() {
}
void GonkNativeWindow::setName(const String8& name) {
Mutex::Autolock _l(mMutex);
mName = name;
mBufferQueue->setConsumerName(name);
}
status_t GonkNativeWindow::acquireBuffer(BufferItem *item, bool waitForFence) {
status_t err;
if (!item) return BAD_VALUE;
Mutex::Autolock _l(mMutex);
err = acquireBufferLocked(item);
if (err != OK) {
if (err != NO_BUFFER_AVAILABLE) {
BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
}
return err;
}
if (waitForFence) {
err = item->mFence->waitForever("GonkNativeWindow::acquireBuffer");
if (err != OK) {
BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
strerror(-err), err);
return err;
}
}
item->mGraphicBuffer = mSlots[item->mBuf].mGraphicBuffer;
return OK;
}
status_t GonkNativeWindow::releaseBuffer(const BufferItem &item,
const sp<Fence>& releaseFence) {
status_t err;
Mutex::Autolock _l(mMutex);
err = addReleaseFenceLocked(item.mBuf, releaseFence);
err = releaseBufferLocked(item.mBuf);
if (err != OK) {
BI_LOGE("Failed to release buffer: %s (%d)",
strerror(-err), err);
}
return err;
}
status_t GonkNativeWindow::setDefaultBufferSize(uint32_t w, uint32_t h) {
Mutex::Autolock _l(mMutex);
return mBufferQueue->setDefaultBufferSize(w, h);
}
status_t GonkNativeWindow::setDefaultBufferFormat(uint32_t defaultFormat) {
Mutex::Autolock _l(mMutex);
return mBufferQueue->setDefaultBufferFormat(defaultFormat);
}
already_AddRefed<GraphicBufferLocked>
GonkNativeWindow::getCurrentBuffer()
{
Mutex::Autolock _l(mMutex);
GonkBufferQueue::BufferItem item;
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
status_t err = acquireBufferLocked(&item);
if (err != NO_ERROR) {
return NULL;
}
nsRefPtr<GraphicBufferLocked> ret =
new CameraGraphicBuffer(this, item.mBuf, mBufferQueue->getGeneration(), item.mSurfaceDescriptor);
return ret.forget();
}
bool
GonkNativeWindow::returnBuffer(uint32_t aIndex, uint32_t aGeneration) {
BI_LOGD("GonkNativeWindow::returnBuffer: slot=%d (generation=%d)", aIndex, aGeneration);
Mutex::Autolock lock(mMutex);
if (aGeneration != mBufferQueue->getGeneration()) {
BI_LOGD("returnBuffer: buffer is from generation %d (current is %d)",
aGeneration, mBufferQueue->getGeneration());
return false;
}
status_t err = releaseBufferLocked(aIndex);
if (err != NO_ERROR) {
return false;
}
return true;
}
mozilla::layers::SurfaceDescriptor *
GonkNativeWindow::getSurfaceDescriptorFromBuffer(ANativeWindowBuffer* buffer)
{
Mutex::Autolock lock(mMutex);
return mBufferQueue->getSurfaceDescriptorFromBuffer(buffer);
}
void GonkNativeWindow::setNewFrameCallback(
GonkNativeWindowNewFrameCallback* aCallback) {
BI_LOGD("setNewFrameCallback");
Mutex::Autolock lock(mMutex);
mNewFrameCallback = aCallback;
}
void GonkNativeWindow::onFrameAvailable() {
GonkConsumerBase::onFrameAvailable();
if (mNewFrameCallback) {
mNewFrameCallback->OnNewFrame();
}
}
} // namespace android

View File

@ -0,0 +1,182 @@
/*
* Copyright (C) 2012 The Android Open Source Project
* Copyright (C) 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 NATIVEWINDOW_GONKNATIVEWINDOW_JB_H
#define NATIVEWINDOW_GONKNATIVEWINDOW_JB_H
#include <ui/GraphicBuffer.h>
#include <utils/String8.h>
#include <utils/Vector.h>
#include <utils/threads.h>
#include "CameraCommon.h"
#include "GonkConsumerBase.h"
#include "GrallocImages.h"
#include "mozilla/layers/ImageBridgeChild.h"
#include "mozilla/layers/LayersSurfaces.h"
namespace mozilla {
namespace layers {
class PGrallocBufferChild;
}
}
namespace android {
// The user of GonkNativeWindow who wants to receive notification of
// new frames should implement this interface.
class GonkNativeWindowNewFrameCallback {
public:
virtual void OnNewFrame() = 0;
};
/**
* GonkNativeWindow is a GonkBufferQueue consumer endpoint that allows clients
* access to the whole BufferItem entry from GonkBufferQueue. Multiple buffers may
* be acquired at once, to be used concurrently by the client. This consumer can
* operate either in synchronous or asynchronous mode.
*/
class GonkNativeWindow: public GonkConsumerBase
{
typedef mozilla::layers::GraphicBufferLocked GraphicBufferLocked;
typedef mozilla::layers::SurfaceDescriptor SurfaceDescriptor;
public:
typedef GonkConsumerBase::FrameAvailableListener FrameAvailableListener;
typedef GonkBufferQueue::BufferItem BufferItem;
enum { INVALID_BUFFER_SLOT = GonkBufferQueue::INVALID_BUFFER_SLOT };
enum { NO_BUFFER_AVAILABLE = GonkBufferQueue::NO_BUFFER_AVAILABLE };
// Create a new buffer item consumer. The consumerUsage parameter determines
// the consumer usage flags passed to the graphics allocator. The
// bufferCount parameter specifies how many buffers can be locked for user
// access at the same time.
GonkNativeWindow();
virtual ~GonkNativeWindow();
// set the name of the GonkNativeWindow that will be used to identify it in
// log messages.
void setName(const String8& name);
// Gets the next graphics buffer from the producer, filling out the
// passed-in BufferItem structure. Returns NO_BUFFER_AVAILABLE if the queue
// of buffers is empty, and INVALID_OPERATION if the maximum number of
// buffers is already acquired.
//
// Only a fixed number of buffers can be acquired at a time, determined by
// the construction-time bufferCount parameter. If INVALID_OPERATION is
// returned by acquireBuffer, then old buffers must be returned to the
// queue by calling releaseBuffer before more buffers can be acquired.
//
// If waitForFence is true, and the acquired BufferItem has a valid fence object,
// acquireBuffer will wait on the fence with no timeout before returning.
status_t acquireBuffer(BufferItem *item, bool waitForFence = true);
// Returns an acquired buffer to the queue, allowing it to be reused. Since
// only a fixed number of buffers may be acquired at a time, old buffers
// must be released by calling releaseBuffer to ensure new buffers can be
// acquired by acquireBuffer. Once a BufferItem is released, the caller must
// not access any members of the BufferItem, and should immediately remove
// all of its references to the BufferItem itself.
status_t releaseBuffer(const BufferItem &item,
const sp<Fence>& releaseFence = Fence::NO_FENCE);
sp<IGraphicBufferProducer> getProducerInterface() const { return getBufferQueue(); }
// setDefaultBufferSize is used to set the size of buffers returned by
// requestBuffers when a with and height of zero is requested.
status_t setDefaultBufferSize(uint32_t w, uint32_t h);
// setDefaultBufferFormat allows the BufferQueue to create
// GraphicBuffers of a defaultFormat if no format is specified
// in dequeueBuffer
status_t setDefaultBufferFormat(uint32_t defaultFormat);
// Get next frame from the queue, caller owns the returned buffer.
already_AddRefed<GraphicBufferLocked> getCurrentBuffer();
// Return the buffer to the queue and mark it as FREE. After that
// the buffer is useable again for the decoder.
bool returnBuffer(uint32_t index, uint32_t generation);
SurfaceDescriptor* getSurfaceDescriptorFromBuffer(ANativeWindowBuffer* buffer);
void setNewFrameCallback(GonkNativeWindowNewFrameCallback* aCallback);
protected:
virtual void onFrameAvailable();
private:
GonkNativeWindowNewFrameCallback* mNewFrameCallback;
};
// CameraGraphicBuffer maintains the buffer returned from GonkNativeWindow
class CameraGraphicBuffer : public mozilla::layers::GraphicBufferLocked
{
typedef mozilla::layers::SurfaceDescriptor SurfaceDescriptor;
typedef mozilla::layers::ImageBridgeChild ImageBridgeChild;
public:
CameraGraphicBuffer(GonkNativeWindow* aNativeWindow,
uint32_t aIndex,
uint32_t aGeneration,
SurfaceDescriptor aBuffer)
: GraphicBufferLocked(aBuffer)
, mNativeWindow(aNativeWindow)
, mIndex(aIndex)
, mGeneration(aGeneration)
, mLocked(true)
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
virtual ~CameraGraphicBuffer()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
// Unlock either returns the buffer to the native window or
// destroys the buffer if the window is already released.
virtual void Unlock() MOZ_OVERRIDE
{
if (mLocked) {
// The window might have been destroyed. The buffer is no longer
// valid at that point.
sp<GonkNativeWindow> window = mNativeWindow.promote();
if (window.get() && window->returnBuffer(mIndex, mGeneration)) {
mLocked = false;
} else {
// If the window doesn't exist any more, release the buffer
// directly.
ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton();
ibc->DeallocSurfaceDescriptorGralloc(mSurfaceDescriptor);
}
}
}
protected:
wp<GonkNativeWindow> mNativeWindow;
uint32_t mIndex;
uint32_t mGeneration;
bool mLocked;
};
} // namespace android
#endif // NATIVEWINDOW_GONKNATIVEWINDOW_JB_H

View File

@ -21,16 +21,32 @@ EXPORTS += [
'GonkNativeWindowClient.h',
]
EXPORTS += [
'GonkNativeWindowClientICS.h',
'GonkNativeWindowICS.h',
]
if CONFIG['ANDROID_VERSION'] == '18':
EXPORTS += [
'GonkBufferQueue.h',
'GonkConsumerBase.h',
'GonkNativeWindowClientJB.h',
'GonkNativeWindowJB.h',
]
elif CONFIG['ANDROID_VERSION'] == '15':
EXPORTS += [
'GonkNativeWindowClientICS.h',
'GonkNativeWindowICS.h',
]
if CONFIG['MOZ_B2G_CAMERA'] or CONFIG['MOZ_OMX_DECODER']:
CPP_SOURCES += [
'GonkNativeWindowICS.cpp',
'GonkNativeWindowClientICS.cpp',
]
if CONFIG['ANDROID_VERSION'] == '18':
CPP_SOURCES += [
'GonkBufferQueue.cpp',
'GonkConsumerBase.cpp',
'GonkNativeWindowJB.cpp',
'GonkNativeWindowClientJB.cpp',
]
elif CONFIG['ANDROID_VERSION'] == '15':
CPP_SOURCES += [
'GonkNativeWindowClientICS.cpp',
'GonkNativeWindowICS.cpp',
]
FAIL_ON_WARNINGS = True