summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/foundation/AMessage.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/foundation/AMessage.cpp')
-rw-r--r--media/libstagefright/foundation/AMessage.cpp586
1 files changed, 586 insertions, 0 deletions
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
new file mode 100644
index 0000000..8b01ac6
--- /dev/null
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -0,0 +1,586 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#include "AMessage.h"
+
+#include <ctype.h>
+
+#include "AAtomizer.h"
+#include "ABuffer.h"
+#include "ADebug.h"
+#include "ALooperRoster.h"
+#include "AString.h"
+
+#include <binder/Parcel.h>
+
+namespace android {
+
+extern ALooperRoster gLooperRoster;
+
+AMessage::AMessage(uint32_t what, ALooper::handler_id target)
+ : mWhat(what),
+ mTarget(target),
+ mNumItems(0) {
+}
+
+AMessage::~AMessage() {
+ clear();
+}
+
+void AMessage::setWhat(uint32_t what) {
+ mWhat = what;
+}
+
+uint32_t AMessage::what() const {
+ return mWhat;
+}
+
+void AMessage::setTarget(ALooper::handler_id handlerID) {
+ mTarget = handlerID;
+}
+
+ALooper::handler_id AMessage::target() const {
+ return mTarget;
+}
+
+void AMessage::clear() {
+ for (size_t i = 0; i < mNumItems; ++i) {
+ Item *item = &mItems[i];
+ freeItem(item);
+ }
+ mNumItems = 0;
+}
+
+void AMessage::freeItem(Item *item) {
+ switch (item->mType) {
+ case kTypeString:
+ {
+ delete item->u.stringValue;
+ break;
+ }
+
+ case kTypeObject:
+ case kTypeMessage:
+ case kTypeBuffer:
+ {
+ if (item->u.refValue != NULL) {
+ item->u.refValue->decStrong(this);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+AMessage::Item *AMessage::allocateItem(const char *name) {
+ name = AAtomizer::Atomize(name);
+
+ size_t i = 0;
+ while (i < mNumItems && mItems[i].mName != name) {
+ ++i;
+ }
+
+ Item *item;
+
+ if (i < mNumItems) {
+ item = &mItems[i];
+ freeItem(item);
+ } else {
+ CHECK(mNumItems < kMaxNumItems);
+ i = mNumItems++;
+ item = &mItems[i];
+
+ item->mName = name;
+ }
+
+ return item;
+}
+
+const AMessage::Item *AMessage::findItem(
+ const char *name, Type type) const {
+ name = AAtomizer::Atomize(name);
+
+ for (size_t i = 0; i < mNumItems; ++i) {
+ const Item *item = &mItems[i];
+
+ if (item->mName == name) {
+ return item->mType == type ? item : NULL;
+ }
+ }
+
+ return NULL;
+}
+
+#define BASIC_TYPE(NAME,FIELDNAME,TYPENAME) \
+void AMessage::set##NAME(const char *name, TYPENAME value) { \
+ Item *item = allocateItem(name); \
+ \
+ item->mType = kType##NAME; \
+ item->u.FIELDNAME = value; \
+} \
+ \
+bool AMessage::find##NAME(const char *name, TYPENAME *value) const { \
+ const Item *item = findItem(name, kType##NAME); \
+ if (item) { \
+ *value = item->u.FIELDNAME; \
+ return true; \
+ } \
+ return false; \
+}
+
+BASIC_TYPE(Int32,int32Value,int32_t)
+BASIC_TYPE(Int64,int64Value,int64_t)
+BASIC_TYPE(Size,sizeValue,size_t)
+BASIC_TYPE(Float,floatValue,float)
+BASIC_TYPE(Double,doubleValue,double)
+BASIC_TYPE(Pointer,ptrValue,void *)
+
+#undef BASIC_TYPE
+
+void AMessage::setString(
+ const char *name, const char *s, ssize_t len) {
+ Item *item = allocateItem(name);
+ item->mType = kTypeString;
+ item->u.stringValue = new AString(s, len < 0 ? strlen(s) : len);
+}
+
+void AMessage::setObjectInternal(
+ const char *name, const sp<RefBase> &obj, Type type) {
+ Item *item = allocateItem(name);
+ item->mType = type;
+
+ if (obj != NULL) { obj->incStrong(this); }
+ item->u.refValue = obj.get();
+}
+
+void AMessage::setObject(const char *name, const sp<RefBase> &obj) {
+ setObjectInternal(name, obj, kTypeObject);
+}
+
+void AMessage::setBuffer(const char *name, const sp<ABuffer> &buffer) {
+ setObjectInternal(name, sp<RefBase>(buffer), kTypeBuffer);
+}
+
+void AMessage::setMessage(const char *name, const sp<AMessage> &obj) {
+ Item *item = allocateItem(name);
+ item->mType = kTypeMessage;
+
+ if (obj != NULL) { obj->incStrong(this); }
+ item->u.refValue = obj.get();
+}
+
+void AMessage::setRect(
+ const char *name,
+ int32_t left, int32_t top, int32_t right, int32_t bottom) {
+ Item *item = allocateItem(name);
+ item->mType = kTypeRect;
+
+ item->u.rectValue.mLeft = left;
+ item->u.rectValue.mTop = top;
+ item->u.rectValue.mRight = right;
+ item->u.rectValue.mBottom = bottom;
+}
+
+bool AMessage::findString(const char *name, AString *value) const {
+ const Item *item = findItem(name, kTypeString);
+ if (item) {
+ *value = *item->u.stringValue;
+ return true;
+ }
+ return false;
+}
+
+bool AMessage::findObject(const char *name, sp<RefBase> *obj) const {
+ const Item *item = findItem(name, kTypeObject);
+ if (item) {
+ *obj = item->u.refValue;
+ return true;
+ }
+ return false;
+}
+
+bool AMessage::findBuffer(const char *name, sp<ABuffer> *buf) const {
+ const Item *item = findItem(name, kTypeBuffer);
+ if (item) {
+ *buf = (ABuffer *)(item->u.refValue);
+ return true;
+ }
+ return false;
+}
+
+bool AMessage::findMessage(const char *name, sp<AMessage> *obj) const {
+ const Item *item = findItem(name, kTypeMessage);
+ if (item) {
+ *obj = static_cast<AMessage *>(item->u.refValue);
+ return true;
+ }
+ return false;
+}
+
+bool AMessage::findRect(
+ const char *name,
+ int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const {
+ const Item *item = findItem(name, kTypeRect);
+ if (item == NULL) {
+ return false;
+ }
+
+ *left = item->u.rectValue.mLeft;
+ *top = item->u.rectValue.mTop;
+ *right = item->u.rectValue.mRight;
+ *bottom = item->u.rectValue.mBottom;
+
+ return true;
+}
+
+void AMessage::post(int64_t delayUs) {
+ gLooperRoster.postMessage(this, delayUs);
+}
+
+status_t AMessage::postAndAwaitResponse(sp<AMessage> *response) {
+ return gLooperRoster.postAndAwaitResponse(this, response);
+}
+
+void AMessage::postReply(uint32_t replyID) {
+ gLooperRoster.postReply(replyID, this);
+}
+
+bool AMessage::senderAwaitsResponse(uint32_t *replyID) const {
+ int32_t tmp;
+ bool found = findInt32("replyID", &tmp);
+
+ if (!found) {
+ return false;
+ }
+
+ *replyID = static_cast<uint32_t>(tmp);
+
+ return true;
+}
+
+sp<AMessage> AMessage::dup() const {
+ sp<AMessage> msg = new AMessage(mWhat, mTarget);
+ msg->mNumItems = mNumItems;
+
+ for (size_t i = 0; i < mNumItems; ++i) {
+ const Item *from = &mItems[i];
+ Item *to = &msg->mItems[i];
+
+ to->mName = from->mName;
+ to->mType = from->mType;
+
+ switch (from->mType) {
+ case kTypeString:
+ {
+ to->u.stringValue =
+ new AString(*from->u.stringValue);
+ break;
+ }
+
+ case kTypeObject:
+ case kTypeBuffer:
+ {
+ to->u.refValue = from->u.refValue;
+ to->u.refValue->incStrong(msg.get());
+ break;
+ }
+
+ case kTypeMessage:
+ {
+ sp<AMessage> copy =
+ static_cast<AMessage *>(from->u.refValue)->dup();
+
+ to->u.refValue = copy.get();
+ to->u.refValue->incStrong(msg.get());
+ break;
+ }
+
+ default:
+ {
+ to->u = from->u;
+ break;
+ }
+ }
+ }
+
+ return msg;
+}
+
+static void appendIndent(AString *s, int32_t indent) {
+ static const char kWhitespace[] =
+ " "
+ " ";
+
+ CHECK_LT((size_t)indent, sizeof(kWhitespace));
+
+ s->append(kWhitespace, indent);
+}
+
+static bool isFourcc(uint32_t what) {
+ return isprint(what & 0xff)
+ && isprint((what >> 8) & 0xff)
+ && isprint((what >> 16) & 0xff)
+ && isprint((what >> 24) & 0xff);
+}
+
+AString AMessage::debugString(int32_t indent) const {
+ AString s = "AMessage(what = ";
+
+ AString tmp;
+ if (isFourcc(mWhat)) {
+ tmp = StringPrintf(
+ "'%c%c%c%c'",
+ (char)(mWhat >> 24),
+ (char)((mWhat >> 16) & 0xff),
+ (char)((mWhat >> 8) & 0xff),
+ (char)(mWhat & 0xff));
+ } else {
+ tmp = StringPrintf("0x%08x", mWhat);
+ }
+ s.append(tmp);
+
+ if (mTarget != 0) {
+ tmp = StringPrintf(", target = %d", mTarget);
+ s.append(tmp);
+ }
+ s.append(") = {\n");
+
+ for (size_t i = 0; i < mNumItems; ++i) {
+ const Item &item = mItems[i];
+
+ switch (item.mType) {
+ case kTypeInt32:
+ tmp = StringPrintf(
+ "int32_t %s = %d", item.mName, item.u.int32Value);
+ break;
+ case kTypeInt64:
+ tmp = StringPrintf(
+ "int64_t %s = %lld", item.mName, item.u.int64Value);
+ break;
+ case kTypeSize:
+ tmp = StringPrintf(
+ "size_t %s = %d", item.mName, item.u.sizeValue);
+ break;
+ case kTypeFloat:
+ tmp = StringPrintf(
+ "float %s = %f", item.mName, item.u.floatValue);
+ break;
+ case kTypeDouble:
+ tmp = StringPrintf(
+ "double %s = %f", item.mName, item.u.doubleValue);
+ break;
+ case kTypePointer:
+ tmp = StringPrintf(
+ "void *%s = %p", item.mName, item.u.ptrValue);
+ break;
+ case kTypeString:
+ tmp = StringPrintf(
+ "string %s = \"%s\"",
+ item.mName,
+ item.u.stringValue->c_str());
+ break;
+ case kTypeObject:
+ tmp = StringPrintf(
+ "RefBase *%s = %p", item.mName, item.u.refValue);
+ break;
+ case kTypeBuffer:
+ tmp = StringPrintf(
+ "ABuffer *%s = %p", item.mName, item.u.refValue);
+ break;
+ case kTypeMessage:
+ tmp = StringPrintf(
+ "AMessage %s = %s",
+ item.mName,
+ static_cast<AMessage *>(
+ item.u.refValue)->debugString(
+ indent + strlen(item.mName) + 14).c_str());
+ break;
+ case kTypeRect:
+ tmp = StringPrintf(
+ "Rect %s(%d, %d, %d, %d)",
+ item.mName,
+ item.u.rectValue.mLeft,
+ item.u.rectValue.mTop,
+ item.u.rectValue.mRight,
+ item.u.rectValue.mBottom);
+ break;
+ default:
+ TRESPASS();
+ }
+
+ appendIndent(&s, indent);
+ s.append(" ");
+ s.append(tmp);
+ s.append("\n");
+ }
+
+ appendIndent(&s, indent);
+ s.append("}");
+
+ return s;
+}
+
+// static
+sp<AMessage> AMessage::FromParcel(const Parcel &parcel) {
+ int32_t what = parcel.readInt32();
+ sp<AMessage> msg = new AMessage(what);
+
+ msg->mNumItems = static_cast<size_t>(parcel.readInt32());
+
+ for (size_t i = 0; i < msg->mNumItems; ++i) {
+ Item *item = &msg->mItems[i];
+
+ item->mName = AAtomizer::Atomize(parcel.readCString());
+ item->mType = static_cast<Type>(parcel.readInt32());
+
+ switch (item->mType) {
+ case kTypeInt32:
+ {
+ item->u.int32Value = parcel.readInt32();
+ break;
+ }
+
+ case kTypeInt64:
+ {
+ item->u.int64Value = parcel.readInt64();
+ break;
+ }
+
+ case kTypeSize:
+ {
+ item->u.sizeValue = static_cast<size_t>(parcel.readInt32());
+ break;
+ }
+
+ case kTypeFloat:
+ {
+ item->u.floatValue = parcel.readFloat();
+ break;
+ }
+
+ case kTypeDouble:
+ {
+ item->u.doubleValue = parcel.readDouble();
+ break;
+ }
+
+ case kTypeString:
+ {
+ item->u.stringValue = new AString(parcel.readCString());
+ break;
+ }
+
+ case kTypeMessage:
+ {
+ sp<AMessage> subMsg = AMessage::FromParcel(parcel);
+ subMsg->incStrong(msg.get());
+
+ item->u.refValue = subMsg.get();
+ break;
+ }
+
+ default:
+ {
+ ALOGE("This type of object cannot cross process boundaries.");
+ TRESPASS();
+ }
+ }
+ }
+
+ return msg;
+}
+
+void AMessage::writeToParcel(Parcel *parcel) const {
+ parcel->writeInt32(static_cast<int32_t>(mWhat));
+ parcel->writeInt32(static_cast<int32_t>(mNumItems));
+
+ for (size_t i = 0; i < mNumItems; ++i) {
+ const Item &item = mItems[i];
+
+ parcel->writeCString(item.mName);
+ parcel->writeInt32(static_cast<int32_t>(item.mType));
+
+ switch (item.mType) {
+ case kTypeInt32:
+ {
+ parcel->writeInt32(item.u.int32Value);
+ break;
+ }
+
+ case kTypeInt64:
+ {
+ parcel->writeInt64(item.u.int64Value);
+ break;
+ }
+
+ case kTypeSize:
+ {
+ parcel->writeInt32(static_cast<int32_t>(item.u.sizeValue));
+ break;
+ }
+
+ case kTypeFloat:
+ {
+ parcel->writeFloat(item.u.floatValue);
+ break;
+ }
+
+ case kTypeDouble:
+ {
+ parcel->writeDouble(item.u.doubleValue);
+ break;
+ }
+
+ case kTypeString:
+ {
+ parcel->writeCString(item.u.stringValue->c_str());
+ break;
+ }
+
+ case kTypeMessage:
+ {
+ static_cast<AMessage *>(item.u.refValue)->writeToParcel(parcel);
+ break;
+ }
+
+ default:
+ {
+ ALOGE("This type of object cannot cross process boundaries.");
+ TRESPASS();
+ }
+ }
+ }
+}
+
+size_t AMessage::countEntries() const {
+ return mNumItems;
+}
+
+const char *AMessage::getEntryNameAt(size_t index, Type *type) const {
+ if (index >= mNumItems) {
+ *type = kTypeInt32;
+
+ return NULL;
+ }
+
+ *type = mItems[index].mType;
+
+ return mItems[index].mName;
+}
+
+} // namespace android