mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-09 04:25:38 +00:00
Bug 1003712: extend MediaResourceManagerService to support video encoder and no-wait mode. r=rjesup,jhlin,sotaro
This commit is contained in:
parent
ecf1a3c65c
commit
edbb0cfe38
@ -80,7 +80,7 @@ OMXCodecProxy::~OMXCodecProxy()
|
||||
IPCThreadState::self()->flushCommands();
|
||||
|
||||
if (mManagerService.get() && mClient.get()) {
|
||||
mManagerService->cancelClient(mClient);
|
||||
mManagerService->cancelClient(mClient, IMediaResourceManagerService::HW_VIDEO_DECODER);
|
||||
}
|
||||
|
||||
mSource.clear();
|
||||
@ -126,7 +126,7 @@ void OMXCodecProxy::requestResource()
|
||||
return;
|
||||
}
|
||||
|
||||
mManagerService->requestMediaResource(mClient, MediaResourceManagerClient::HW_VIDEO_DECODER);
|
||||
mManagerService->requestMediaResource(mClient, IMediaResourceManagerService::HW_VIDEO_DECODER, true /* will wait */);
|
||||
}
|
||||
|
||||
bool OMXCodecProxy::IsWaitingResources()
|
||||
|
@ -34,20 +34,23 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
virtual void requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType)
|
||||
virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType, bool willWait)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IMediaResourceManagerService::getInterfaceDescriptor());
|
||||
data.writeStrongBinder(client->asBinder());
|
||||
data.writeInt32(resourceType);
|
||||
data.writeInt32(willWait ? 1 : 0);
|
||||
remote()->transact(REQUEST_MEDIA_RESOURCE, data, &reply);
|
||||
return reply.readInt32();
|
||||
}
|
||||
|
||||
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client)
|
||||
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client, int resourceType)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IMediaResourceManagerService::getInterfaceDescriptor());
|
||||
data.writeStrongBinder(client->asBinder());
|
||||
data.writeInt32(resourceType);
|
||||
remote()->transact(DEREGISTER_CLIENT, data, &reply);
|
||||
return reply.readInt32();
|
||||
}
|
||||
@ -66,14 +69,17 @@ status_t BnMediaResourceManagerService::onTransact(
|
||||
CHECK_INTERFACE(IMediaResourceManagerService, data, reply);
|
||||
sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(data.readStrongBinder());
|
||||
int resourceType = data.readInt32();
|
||||
requestMediaResource(client, resourceType);
|
||||
bool willWait = (data.readInt32() == 1);
|
||||
status_t result = requestMediaResource(client, resourceType, willWait);
|
||||
reply->writeInt32(result);
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
case DEREGISTER_CLIENT: {
|
||||
CHECK_INTERFACE(IMediaResourceManagerService, data, reply);
|
||||
sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(data.readStrongBinder());
|
||||
cancelClient(client);
|
||||
reply->writeInt32(NO_ERROR);
|
||||
int resourceType = data.readInt32();
|
||||
status_t result = cancelClient(client, resourceType);
|
||||
reply->writeInt32(result);
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
default:
|
||||
|
@ -22,10 +22,36 @@ class IMediaResourceManagerService : public IInterface
|
||||
public:
|
||||
DECLARE_META_INTERFACE(MediaResourceManagerService);
|
||||
|
||||
// Enumeration for the resource types
|
||||
enum ResourceType {
|
||||
HW_VIDEO_DECODER = 0,
|
||||
HW_AUDIO_DECODER, // Not supported currently.
|
||||
HW_VIDEO_ENCODER,
|
||||
HW_CAMERA, // Not supported currently.
|
||||
NUM_OF_RESOURCE_TYPES,
|
||||
INVALID_RESOURCE_TYPE = -1
|
||||
};
|
||||
|
||||
enum ErrorCode {
|
||||
RESOURCE_NOT_AVAILABLE = -EAGAIN
|
||||
};
|
||||
|
||||
// Request a media resource for IMediaResourceManagerClient.
|
||||
virtual void requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType) = 0;
|
||||
// client is the binder that service will notify (through
|
||||
// IMediaResourceManagerClient::statusChanged()) when request status changed.
|
||||
// resourceType is type of resource that client would like to request.
|
||||
// willWait indicates that, when the resource is not currently available
|
||||
// (i.e., already in use by another client), if the client wants to wait. If
|
||||
// true, client will be put into a (FIFO) waiting list and be notified when
|
||||
// resource is available.
|
||||
// For unsupported types, this function returns BAD_TYPE. For supported
|
||||
// types, it always returns OK when willWait is true; otherwise it will
|
||||
// return true when resouce is available, or RESOURCE_NOT_AVAILABLE when
|
||||
// resouce is in use.
|
||||
virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType, bool willWait) = 0;
|
||||
// Cancel a media resource request and a resource allocated to IMediaResourceManagerClient.
|
||||
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client) = 0;
|
||||
// Client must call this function after it's done with the media resource requested.
|
||||
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client, int resourceType) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -22,12 +22,6 @@ public:
|
||||
CLIENT_STATE_RESOURCE_ASSIGNED,
|
||||
CLIENT_STATE_SHUTDOWN
|
||||
};
|
||||
// Enumeration for the resource types
|
||||
enum ResourceType {
|
||||
HW_VIDEO_DECODER,
|
||||
HW_AUDIO_DECODER,
|
||||
HW_CAMERA
|
||||
};
|
||||
|
||||
struct EventListener : public virtual RefBase {
|
||||
// Notifies a change of media resource request status.
|
||||
|
@ -7,6 +7,8 @@
|
||||
//#define LOG_NDEBUG 0
|
||||
#define LOG_TAG "MediaResourceManagerService"
|
||||
|
||||
#include <mozilla/Assertions.h>
|
||||
|
||||
#include <binder/IServiceManager.h>
|
||||
#include <media/stagefright/foundation/AMessage.h>
|
||||
#include <utils/Log.h>
|
||||
@ -16,14 +18,16 @@
|
||||
|
||||
namespace android {
|
||||
|
||||
const char* MediaResourceManagerService::kMsgKeyResourceType = "res-type";
|
||||
|
||||
/* static */
|
||||
void MediaResourceManagerService::instantiate() {
|
||||
defaultServiceManager()->addService(
|
||||
String16("media.resource_manager"), new MediaResourceManagerService());
|
||||
String16("media.resource_manager"),
|
||||
new MediaResourceManagerService());
|
||||
}
|
||||
|
||||
MediaResourceManagerService::MediaResourceManagerService()
|
||||
: mVideoDecoderCount(VIDEO_DECODER_COUNT)
|
||||
{
|
||||
mLooper = new ALooper;
|
||||
mLooper->setName("MediaResourceManagerService");
|
||||
@ -49,99 +53,319 @@ void MediaResourceManagerService::binderDied(const wp<IBinder>& who)
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
sp<IBinder> binder = who.promote();
|
||||
if (binder != NULL) {
|
||||
cancelClientLocked(binder);
|
||||
mResources.forgetClient(binder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MediaResourceManagerService::requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType)
|
||||
status_t MediaResourceManagerService::requestMediaResource(const sp<IMediaResourceManagerClient>& client,
|
||||
int resourceType, bool willWait)
|
||||
{
|
||||
if (resourceType != MediaResourceManagerClient::HW_VIDEO_DECODER) {
|
||||
// Support only HW_VIDEO_DECODER
|
||||
return;
|
||||
ResourceType type = static_cast<ResourceType>(resourceType);
|
||||
// Support only HW_VIDEO_DECODER and HW_VIDEO_ENCODER.
|
||||
switch (type) {
|
||||
case HW_VIDEO_DECODER:
|
||||
case HW_VIDEO_ENCODER:
|
||||
break;
|
||||
default:
|
||||
// Type not supported.
|
||||
return BAD_TYPE;
|
||||
}
|
||||
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
sp<IBinder> binder = client->asBinder();
|
||||
mVideoCodecRequestQueue.push_back(binder);
|
||||
binder->linkToDeath(this);
|
||||
}
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
|
||||
sp<AMessage> notify =
|
||||
new AMessage(kNotifyRequest, mReflector->id());
|
||||
// Must know if it will be granted or not - if there are enough unfufilled requests to
|
||||
// use up the resource, fail. Otherwise we know that enqueuing under lock will succeed.
|
||||
if (!willWait &&
|
||||
(mResources.findAvailableResource(type, mResources.countRequests(type) + 1) ==
|
||||
NAME_NOT_FOUND)) {
|
||||
return RESOURCE_NOT_AVAILABLE;
|
||||
}
|
||||
// We could early-return here without enqueuing IF we can do the rest of
|
||||
// the allocation safely here. However, enqueuing ensures there's only
|
||||
// one copy of that code, and that any callbacks are made from the same
|
||||
// context.
|
||||
|
||||
sp<IBinder> binder = client->asBinder();
|
||||
mResources.enqueueRequest(binder, type);
|
||||
binder->linkToDeath(this);
|
||||
|
||||
sp<AMessage> notify = new AMessage(kNotifyRequest, mReflector->id());
|
||||
notify->setInt32(kMsgKeyResourceType, resourceType);
|
||||
// Post AMessage to MediaResourceManagerService via ALooper.
|
||||
notify->post();
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t MediaResourceManagerService::cancelClient(const sp<IMediaResourceManagerClient>& client)
|
||||
status_t MediaResourceManagerService::cancelClient(const sp<IMediaResourceManagerClient>& client,
|
||||
int resourceType)
|
||||
{
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
sp<IBinder> binder = client->asBinder();
|
||||
cancelClientLocked(binder);
|
||||
}
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
|
||||
sp<AMessage> notify =
|
||||
new AMessage(kNotifyRequest, mReflector->id());
|
||||
// Post AMessage to MediaResourceManagerService via ALooper.
|
||||
sp<IBinder> binder = client->asBinder();
|
||||
cancelClientLocked(binder, static_cast<ResourceType>(resourceType));
|
||||
|
||||
sp<AMessage> notify = new AMessage(kNotifyRequest, mReflector->id());
|
||||
notify->setInt32(kMsgKeyResourceType, resourceType);
|
||||
// Next!
|
||||
// Note: since we held the lock while releasing and then posting, if there is
|
||||
// a queue, no willWait==false entries can jump into the queue thinking they'll
|
||||
// get the resource.
|
||||
notify->post();
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// Extract resource type from message.
|
||||
static int32_t getResourceType(const sp<AMessage>& message)
|
||||
{
|
||||
int32_t resourceType = MediaResourceManagerService::INVALID_RESOURCE_TYPE;
|
||||
return message->findInt32(MediaResourceManagerService::kMsgKeyResourceType, &resourceType) ?
|
||||
resourceType : MediaResourceManagerService::INVALID_RESOURCE_TYPE;
|
||||
}
|
||||
|
||||
// Called on ALooper thread.
|
||||
void MediaResourceManagerService::onMessageReceived(const sp<AMessage> &msg)
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
ResourceType type = static_cast<ResourceType>(getResourceType(msg));
|
||||
|
||||
// Exit if no request.
|
||||
if (mVideoCodecRequestQueue.empty()) {
|
||||
// Note: a message is sent both for "I added an entry to the queue"
|
||||
// (which may succeed, typically if the queue is empty), and for "I gave
|
||||
// up the resource", in which case it's "give to the next waiting client,
|
||||
// or no one".
|
||||
|
||||
// Exit if no resource is available, but leave the client in the waiting
|
||||
// list.
|
||||
int found = mResources.findAvailableResource(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if resource is available
|
||||
int found = -1;
|
||||
for (int i=0 ; i<mVideoDecoderCount ; i++) {
|
||||
if (!mVideoDecoderSlots[i].mClient.get()) {
|
||||
// Exit if no request.
|
||||
if (!mResources.hasRequest(type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sp<IBinder>& req = mResources.nextRequest(type);
|
||||
mResources.aquireResource(req, type, found);
|
||||
// Notify resource assignment to the client.
|
||||
sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(req);
|
||||
client->statusChanged(MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED);
|
||||
mResources.dequeueRequest(type);
|
||||
}
|
||||
|
||||
void MediaResourceManagerService::cancelClientLocked(const sp<IBinder>& binder,
|
||||
ResourceType resourceType)
|
||||
{
|
||||
mResources.forgetClient(binder, resourceType);
|
||||
binder->unlinkToDeath(this);
|
||||
}
|
||||
|
||||
MediaResourceManagerService::ResourceTable::ResourceTable()
|
||||
{
|
||||
// Populate types of resources.
|
||||
for (int type = 0; type < NUM_OF_RESOURCE_TYPES; type++) {
|
||||
ssize_t index = mMap.add(static_cast<ResourceType>(type), Resources());
|
||||
Resources& resources = mMap.editValueAt(index);
|
||||
int available;
|
||||
switch (type) {
|
||||
case HW_VIDEO_DECODER:
|
||||
available = VIDEO_DECODER_COUNT;
|
||||
break;
|
||||
case HW_VIDEO_ENCODER:
|
||||
available = VIDEO_ENCODER_COUNT;
|
||||
break;
|
||||
default:
|
||||
available = 0;
|
||||
break;
|
||||
}
|
||||
resources.mSlots.insertAt(0, available);
|
||||
}
|
||||
}
|
||||
|
||||
MediaResourceManagerService::ResourceTable::~ResourceTable() {
|
||||
// Remove resouces.
|
||||
mMap.clear();
|
||||
}
|
||||
|
||||
bool MediaResourceManagerService::ResourceTable::supportsType(ResourceType type)
|
||||
{
|
||||
return mMap.indexOfKey(type) != NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
ssize_t MediaResourceManagerService::ResourceTable::findAvailableResource(ResourceType type,
|
||||
size_t numberNeeded)
|
||||
{
|
||||
MOZ_ASSERT(numberNeeded > 0);
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return found;
|
||||
}
|
||||
const Slots& slots = mMap.valueAt(found).mSlots;
|
||||
|
||||
found = NAME_NOT_FOUND;
|
||||
for (size_t i = 0; i < slots.size(); i++) {
|
||||
if (slots[i].mClient != nullptr) {
|
||||
// Already in use.
|
||||
continue;
|
||||
}
|
||||
if (--numberNeeded == 0) {
|
||||
found = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Exit if no resource is available.
|
||||
if (found == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Assign resource to IMediaResourceManagerClient
|
||||
Fifo::iterator front(mVideoCodecRequestQueue.begin());
|
||||
mVideoDecoderSlots[found].mClient = *front;
|
||||
mVideoCodecRequestQueue.erase(front);
|
||||
// Notify resource assignment to the client.
|
||||
sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(mVideoDecoderSlots[found].mClient);
|
||||
client->statusChanged(MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED);
|
||||
return found;
|
||||
}
|
||||
|
||||
void MediaResourceManagerService::cancelClientLocked(const sp<IBinder>& binder)
|
||||
bool MediaResourceManagerService::ResourceTable::isOwnedByClient(const sp<IBinder>& client,
|
||||
ResourceType type,
|
||||
size_t index)
|
||||
{
|
||||
// Clear the request from request queue.
|
||||
Fifo::iterator it(mVideoCodecRequestQueue.begin());
|
||||
while (it != mVideoCodecRequestQueue.end()) {
|
||||
if ((*it).get() == binder.get()) {
|
||||
mVideoCodecRequestQueue.erase(it);
|
||||
ResourceSlot* slot = resourceOfTypeAt(type, index);
|
||||
return slot && slot->mClient == client;
|
||||
}
|
||||
|
||||
status_t MediaResourceManagerService::ResourceTable::aquireResource(const sp<IBinder>& client,
|
||||
ResourceType type,
|
||||
size_t index)
|
||||
{
|
||||
ResourceSlot* slot = resourceOfTypeAt(type, index);
|
||||
// Resouce should not be in use.
|
||||
MOZ_ASSERT(slot && slot->mClient == nullptr);
|
||||
if (!slot) {
|
||||
return NAME_NOT_FOUND;
|
||||
} else if (slot->mClient != nullptr) {
|
||||
// Resource already in use by other client.
|
||||
return PERMISSION_DENIED;
|
||||
}
|
||||
|
||||
slot->mClient = client;
|
||||
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
MediaResourceManagerService::ResourceSlot*
|
||||
MediaResourceManagerService::ResourceTable::resourceOfTypeAt(ResourceType type,
|
||||
size_t index)
|
||||
{
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Slots& slots = mMap.editValueAt(found).mSlots;
|
||||
MOZ_ASSERT(index < slots.size());
|
||||
if (index >= slots.size()) {
|
||||
// Index out of range.
|
||||
return nullptr;
|
||||
}
|
||||
return &(slots.editItemAt(index));
|
||||
}
|
||||
|
||||
bool MediaResourceManagerService::ResourceTable::hasRequest(ResourceType type)
|
||||
{
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Fifo& queue = mMap.valueAt(found).mRequestQueue;
|
||||
return !queue.empty();
|
||||
}
|
||||
|
||||
uint32_t MediaResourceManagerService::ResourceTable::countRequests(ResourceType type)
|
||||
{
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Fifo& queue = mMap.valueAt(found).mRequestQueue;
|
||||
return queue.size();
|
||||
}
|
||||
|
||||
const sp<IBinder>& MediaResourceManagerService::ResourceTable::nextRequest(ResourceType type)
|
||||
{
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Fifo& queue = mMap.valueAt(found).mRequestQueue;
|
||||
return *(queue.begin());
|
||||
}
|
||||
|
||||
status_t MediaResourceManagerService::ResourceTable::enqueueRequest(const sp<IBinder>& client,
|
||||
ResourceType type)
|
||||
{
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return found;
|
||||
}
|
||||
|
||||
mMap.editValueAt(found).mRequestQueue.push_back(client);
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t MediaResourceManagerService::ResourceTable::dequeueRequest(ResourceType type)
|
||||
{
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return found;
|
||||
}
|
||||
|
||||
Fifo& queue = mMap.editValueAt(found).mRequestQueue;
|
||||
queue.erase(queue.begin());
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t MediaResourceManagerService::ResourceTable::forgetClient(const sp<IBinder>& client)
|
||||
{
|
||||
// Traverse all resources.
|
||||
for (int i = 0; i < mMap.size(); i++) {
|
||||
forgetClient(client, mMap.keyAt(i));
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t MediaResourceManagerService::ResourceTable::forgetClient(const sp<IBinder>& client, ResourceType type)
|
||||
{
|
||||
MOZ_ASSERT(supportsType(type));
|
||||
|
||||
Resources& resources = mMap.editValueFor(type);
|
||||
|
||||
// Remove pending requests for given client.
|
||||
Fifo& queue = resources.mRequestQueue;
|
||||
Fifo::iterator it(queue.begin());
|
||||
while (it != queue.end()) {
|
||||
if ((*it).get() == client.get()) {
|
||||
queue.erase(it);
|
||||
break;
|
||||
}
|
||||
it++;
|
||||
}
|
||||
|
||||
// Clear the client from the resource
|
||||
for (int i=0 ; i<mVideoDecoderCount ; i++) {
|
||||
if (mVideoDecoderSlots[i].mClient.get() == binder.get()) {
|
||||
mVideoDecoderSlots[i].mClient = NULL;
|
||||
// Revoke ownership for given client.
|
||||
Slots& slots = resources.mSlots;
|
||||
for (int i = 0; i < slots.size(); i++) {
|
||||
ResourceSlot& slot = slots.editItemAt(i);
|
||||
if (client.get() == slot.mClient.get()) {
|
||||
slot.mClient = nullptr;
|
||||
}
|
||||
}
|
||||
binder->unlinkToDeath(this);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
|
||||
|
@ -10,8 +10,10 @@
|
||||
#include <media/stagefright/foundation/ABase.h>
|
||||
#include <media/stagefright/foundation/AHandlerReflector.h>
|
||||
#include <media/stagefright/foundation/ALooper.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/List.h>
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/Vector.h>
|
||||
|
||||
#include "IMediaResourceManagerClient.h"
|
||||
#include "IMediaResourceManagerService.h"
|
||||
@ -20,20 +22,27 @@ namespace android {
|
||||
|
||||
/**
|
||||
* Manage permissions of using media resources(hw decoder, hw encoder, camera)
|
||||
* XXX Current implementaion support only one hw video decoder.
|
||||
* XXX Current implementation supports only one hw video codec.
|
||||
* Need to extend to support multiple instance and other resources.
|
||||
*/
|
||||
class MediaResourceManagerService: public BnMediaResourceManagerService,
|
||||
public IBinder::DeathRecipient
|
||||
{
|
||||
public:
|
||||
// The maximum number of hardware decoders available.
|
||||
enum { VIDEO_DECODER_COUNT = 1 };
|
||||
|
||||
enum {
|
||||
kNotifyRequest = 'noti'
|
||||
// The maximum number of hardware resoureces available.
|
||||
enum
|
||||
{
|
||||
VIDEO_DECODER_COUNT = 1,
|
||||
VIDEO_ENCODER_COUNT = 1
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
kNotifyRequest = 'noti',
|
||||
};
|
||||
|
||||
static const char* kMsgKeyResourceType;
|
||||
|
||||
// Instantiate MediaResourceManagerService and register to service manager.
|
||||
// If service manager is not present, wait until service manager becomes present.
|
||||
static void instantiate();
|
||||
@ -42,8 +51,10 @@ public:
|
||||
virtual void binderDied(const wp<IBinder>& who);
|
||||
|
||||
// derived from IMediaResourceManagerService
|
||||
virtual void requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType);
|
||||
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client);
|
||||
virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client,
|
||||
int resourceType, bool willWait);
|
||||
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client,
|
||||
int resourceType);
|
||||
|
||||
// Receive a message from AHandlerReflector.
|
||||
// Called on ALooper thread.
|
||||
@ -53,30 +64,54 @@ protected:
|
||||
MediaResourceManagerService();
|
||||
virtual ~MediaResourceManagerService();
|
||||
|
||||
protected:
|
||||
private:
|
||||
// Represent a media resouce.
|
||||
// Hold a IMediaResourceManagerClient that got a media resource as IBinder.
|
||||
struct ResourceSlot {
|
||||
ResourceSlot ()
|
||||
{
|
||||
}
|
||||
sp<IBinder> mClient;
|
||||
};
|
||||
struct ResourceSlot
|
||||
{
|
||||
sp<IBinder> mClient;
|
||||
};
|
||||
typedef Vector<ResourceSlot> Slots;
|
||||
|
||||
void cancelClientLocked(const sp<IBinder>& binder);
|
||||
|
||||
// mVideoDecoderSlots is the array of slots that represent a media resource.
|
||||
ResourceSlot mVideoDecoderSlots[VIDEO_DECODER_COUNT];
|
||||
// The maximum number of hardware decoders available on the device.
|
||||
int mVideoDecoderCount;
|
||||
|
||||
// The lock protects mVideoDecoderSlots and mVideoCodecRequestQueue called
|
||||
// from multiple threads.
|
||||
Mutex mLock;
|
||||
typedef List<sp<IBinder> > Fifo;
|
||||
// Queue of media resource requests.
|
||||
// Hold IMediaResourceManagerClient that requesting a media resource as IBinder.
|
||||
Fifo mVideoCodecRequestQueue;
|
||||
struct Resources
|
||||
{
|
||||
// Queue of media resource requests. Hold IMediaResourceManagerClient that
|
||||
// requesting a media resource as IBinder.
|
||||
Fifo mRequestQueue;
|
||||
// All resources that can be requested. Hold |ResourceSlot|s that track
|
||||
// their usage.
|
||||
Slots mSlots;
|
||||
};
|
||||
|
||||
typedef KeyedVector<ResourceType, Resources> ResourcesMap;
|
||||
// Manages requests from clients and availability of resources.
|
||||
class ResourceTable
|
||||
{
|
||||
ResourceTable();
|
||||
~ResourceTable();
|
||||
// Resource operations.
|
||||
bool supportsType(ResourceType type);
|
||||
ssize_t findAvailableResource(ResourceType type, size_t number_needed = 1);
|
||||
bool isOwnedByClient(const sp<IBinder>& client, ResourceType type, size_t index);
|
||||
status_t aquireResource(const sp<IBinder>& client, ResourceType type, size_t index);
|
||||
ResourceSlot* resourceOfTypeAt(ResourceType type, size_t index);
|
||||
// Request operations.
|
||||
bool hasRequest(ResourceType type);
|
||||
uint32_t countRequests(ResourceType type);
|
||||
const sp<IBinder>& nextRequest(ResourceType type);
|
||||
status_t enqueueRequest(const sp<IBinder>& client, ResourceType type);
|
||||
status_t dequeueRequest(ResourceType type);
|
||||
status_t forgetClient(const sp<IBinder>& client, ResourceType type);
|
||||
status_t forgetClient(const sp<IBinder>& client);
|
||||
|
||||
friend class MediaResourceManagerService;
|
||||
|
||||
// A map for all types of supported resources.
|
||||
ResourcesMap mMap;
|
||||
};
|
||||
|
||||
void cancelClientLocked(const sp<IBinder>& binder, ResourceType resourceType);
|
||||
|
||||
// ALooper is a message loop used in stagefright.
|
||||
// It creates a thread for messages and handles messages in the thread.
|
||||
@ -88,6 +123,11 @@ protected:
|
||||
// http://developer.android.com/reference/android/os/Handler.html
|
||||
sp<AHandlerReflector<MediaResourceManagerService> > mReflector;
|
||||
|
||||
// The lock protects manager operations called from multiple threads.
|
||||
Mutex mLock;
|
||||
|
||||
// Keeps all the records.
|
||||
ResourceTable mResources;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
Loading…
x
Reference in New Issue
Block a user