Merge "Mount/Unmount secure containers Persist flags in PackageSetting. Flags are relevant to ApplicationInfo.FLAG_SYSTEM, Application.FLAG_ON_SDCARD, ApplicationInfo.FLAG_FORWARD_LOCK. New pm command to simulate mount/unmount in Pm. This will be removed when MountService/vold event generation gets fixed. Calls from MountService into PackageManager when media gets mounted/unmounted. Scan the packages and grant permissions when the sdcard gets mounted. This api might change again."
diff --git a/Android.mk b/Android.mk
index 7c7bb62..d6beac5 100644
--- a/Android.mk
+++ b/Android.mk
@@ -111,6 +111,7 @@
core/java/android/os/ICheckinService.aidl \
core/java/android/os/IMessenger.aidl \
core/java/android/os/IMountService.aidl \
+ core/java/android/os/INetworkManagementService.aidl \
core/java/android/os/INetStatService.aidl \
core/java/android/os/IParentalControlCallback.aidl \
core/java/android/os/IPermissionController.aidl \
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index ad6540a..e65cdf1 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -34,12 +34,14 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXClient.h>
#include <media/stagefright/OMXCodec.h>
+#include <media/mediametadataretriever.h>
using namespace android;
static long gNumRepetitions;
static long gMaxNumFrames; // 0 means decode all available.
static long gReproduceBug; // if not -1.
+static bool gPreferSoftwareCodec;
static int64_t getNowUs() {
struct timeval tv;
@@ -59,7 +61,9 @@
rawSource = source;
} else {
rawSource = OMXCodec::Create(
- client->interface(), meta, false /* createEncoder */, source);
+ client->interface(), meta, false /* createEncoder */, source,
+ NULL /* matchComponentName */,
+ gPreferSoftwareCodec ? OMXCodec::kPreferSoftwareCodecs : 0);
if (rawSource == NULL) {
fprintf(stderr, "Failed to instantiate decoder for '%s'.\n", mime);
@@ -219,6 +223,8 @@
fprintf(stderr, " -m max-number-of-frames-to-decode in each pass\n");
fprintf(stderr, " -b bug to reproduce\n");
fprintf(stderr, " -p(rofiles) dump decoder profiles supported\n");
+ fprintf(stderr, " -t(humbnail) extract video thumbnail\n");
+ fprintf(stderr, " -s(oftware) prefer software codec\n");
}
int main(int argc, char **argv) {
@@ -227,12 +233,14 @@
bool audioOnly = false;
bool listComponents = false;
bool dumpProfiles = false;
+ bool extractThumbnail = false;
gNumRepetitions = 1;
gMaxNumFrames = 0;
gReproduceBug = -1;
+ gPreferSoftwareCodec = false;
int res;
- while ((res = getopt(argc, argv, "han:lm:b:p")) >= 0) {
+ while ((res = getopt(argc, argv, "han:lm:b:pts")) >= 0) {
switch (res) {
case 'a':
{
@@ -274,6 +282,18 @@
break;
}
+ case 't':
+ {
+ extractThumbnail = true;
+ break;
+ }
+
+ case 's':
+ {
+ gPreferSoftwareCodec = true;
+ break;
+ }
+
case '?':
case 'h':
default:
@@ -288,6 +308,34 @@
argc -= optind;
argv += optind;
+ if (extractThumbnail) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("media.player"));
+ sp<IMediaPlayerService> service =
+ interface_cast<IMediaPlayerService>(binder);
+
+ CHECK(service.get() != NULL);
+
+ sp<IMediaMetadataRetriever> retriever =
+ service->createMetadataRetriever(getpid());
+
+ CHECK(retriever != NULL);
+
+ for (int k = 0; k < argc; ++k) {
+ const char *filename = argv[k];
+
+ CHECK_EQ(retriever->setDataSource(filename), OK);
+ CHECK_EQ(retriever->setMode(METADATA_MODE_FRAME_CAPTURE_ONLY), OK);
+
+ sp<IMemory> mem = retriever->captureFrame();
+
+ printf("captureFrame(%s) => %s\n",
+ filename, mem != NULL ? "OK" : "FAILED");
+ }
+
+ return 0;
+ }
+
if (dumpProfiles) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.player"));
@@ -389,7 +437,8 @@
sp<MetaData> meta;
size_t i;
for (i = 0; i < numTracks; ++i) {
- meta = extractor->getTrackMetaData(i);
+ meta = extractor->getTrackMetaData(
+ i, MediaExtractor::kIncludeExtensiveMetaData);
const char *mime;
meta->findCString(kKeyMIMEType, &mime);
@@ -403,6 +452,12 @@
}
}
+ int64_t thumbTimeUs;
+ if (meta->findInt64(kKeyThumbnailTime, &thumbTimeUs)) {
+ printf("thumbnailTime: %lld us (%.2f secs)\n",
+ thumbTimeUs, thumbTimeUs / 1E6);
+ }
+
mediaSource = extractor->getTrack(i);
}
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
new file mode 100644
index 0000000..bd6cabb
--- /dev/null
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -0,0 +1,105 @@
+/* //device/java/android/android/os/INetworkManagementService.aidl
+**
+** Copyright 2007, 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.
+*/
+
+package android.os;
+
+/**
+ * @hide
+ */
+interface INetworkManagementService
+{
+ /**
+ ** GENERAL
+ **/
+
+ /**
+ * Returns a list of currently known network interfaces
+ */
+ String[] listInterfaces();
+
+ /**
+ * Shuts down the service
+ */
+ void shutdown();
+
+ /**
+ ** TETHERING RELATED
+ **/
+
+
+ /**
+ * Returns true if IP forwarding is enabled
+ */
+ boolean getIpForwardingEnabled();
+
+ /**
+ * Enables/Disables IP Forwarding
+ */
+ void setIpForwardingEnabled(boolean enabled);
+
+ /**
+ * Start tethering services with the specified dhcp server range
+ */
+ void startTethering(String dhcpRangeStart, String dhcpRangeEnd);
+
+ /**
+ * Stop currently running tethering services
+ */
+ void stopTethering();
+
+ /**
+ * Returns true if tethering services are started
+ */
+ boolean isTetheringStarted();
+
+ /**
+ * Tethers the specified interface
+ */
+ void tetherInterface(String iface);
+
+ /**
+ * Untethers the specified interface
+ */
+ void untetherInterface(String iface);
+
+ /**
+ * Returns a list of currently tethered interfaces
+ */
+ String[] listTetheredInterfaces();
+
+ /**
+ * Sets the list of DNS forwarders (in order of priority)
+ */
+ void setDnsForwarders(in String[] dns);
+
+ /**
+ * Returns the list of DNS fowarders (in order of priority)
+ */
+ String[] getDnsForwarders();
+
+ /**
+ * Enables Network Address Translation between two interfaces.
+ * The address and netmask of the external interface is used for
+ * the NAT'ed network.
+ */
+ void enableNat(String internalInterface, String externalInterface);
+
+ /**
+ * Disables Network Address Translation between two interfaces.
+ */
+ void disableNat(String internalInterface, String externalInterface);
+}
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index b876f05..d67169f 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -173,9 +173,32 @@
c.startActivity(i);
}
+ /**
+ * Stores a String extra in an {@link Intent} representing the title of a
+ * page to share. When receiving an {@link Intent#ACTION_SEND} from the
+ * Browser, use this to access the title.
+ * @hide
+ */
+ public final static String EXTRA_SHARE_TITLE = "share_title";
+
+ /**
+ * Stores a Bitmap extra in an {@link Intent} representing the screenshot of
+ * a page to share. When receiving an {@link Intent#ACTION_SEND} from the
+ * Browser, use this to access the screenshot.
+ * @hide
+ */
+ public final static String EXTRA_SHARE_SCREENSHOT = "share_screenshot";
+
+ /**
+ * Stores a Bitmap extra in an {@link Intent} representing the favicon of a
+ * page to share. When receiving an {@link Intent#ACTION_SEND} from the
+ * Browser, use this to access the favicon.
+ * @hide
+ */
+ public final static String EXTRA_SHARE_FAVICON = "share_favicon";
+
public static final void sendString(Context c, String s) {
- sendString(c, s,
- c.getText(com.android.internal.R.string.sendText).toString());
+ sendString(c, s, c.getString(com.android.internal.R.string.sendText));
}
/**
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 93b5b4d..ece23a7 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -474,18 +474,44 @@
public static final String DISPLAY_NAME_SOURCE = "display_name_source";
/**
- * The default text shown as the contact's display name. It is based on
- * available data, see {@link #DISPLAY_NAME_SOURCE}.
+ * <p>
+ * The standard text shown as the contact's display name, based on the best
+ * available information for the contact (for example, it might be the email address
+ * if the name is not available).
+ * The information actually used to compute the name is stored in
+ * {@link #DISPLAY_NAME_SOURCE}.
+ * </p>
+ * <p>
+ * A contacts provider is free to choose whatever representation makes most
+ * sense for its target market.
+ * For example in the default Android Open Source Project implementation,
+ * if the display name is
+ * based on the structured name and the structured name follows
+ * the Western full-name style, then this field contains the "given name first"
+ * version of the full name.
+ * <p>
*
* @see ContactsContract.ContactNameColumns#DISPLAY_NAME_ALTERNATIVE
*/
public static final String DISPLAY_NAME_PRIMARY = "display_name";
/**
- * An alternative representation of the display name. If display name is
+ * <p>
+ * An alternative representation of the display name, such as "family name first"
+ * instead of "given name first" for Western names. If an alternative is not
+ * available, the values should be the same as {@link #DISPLAY_NAME_PRIMARY}.
+ * </p>
+ * <p>
+ * A contacts provider is free to provide alternatives as necessary for
+ * its target market.
+ * For example the default Android Open Source Project contacts provider
+ * currently provides an
+ * alternative in a single case: if the display name is
* based on the structured name and the structured name follows
- * the Western full name style, then this field contains the "family name first"
- * version of the full name. Otherwise, it is the same as DISPLAY_NAME_PRIMARY.
+ * the Western full name style, then the field contains the "family name first"
+ * version of the full name.
+ * Other cases may be added later.
+ * </p>
*/
public static final String DISPLAY_NAME_ALTERNATIVE = "display_name_alt";
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 763f273..49c2d0e 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2268,7 +2268,7 @@
addInArray(child, index);
child.mParent = this;
- child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK) | DRAWN;
+ child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK & ~DRAWING_CACHE_VALID) | DRAWN;
if (child.hasFocus()) {
requestChildFocus(child, child.findFocus());
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 53bb586..3dbfa25 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -131,7 +131,8 @@
the first component from this list which is found to be installed is set as the
preferred activity. -->
<string-array name="default_web_search_providers">
- <item>com.android.quicksearchbox/com.android.googlesearch.GoogleSearch</item>
+ <item>com.google.android.googlequicksearchbox/.google.GoogleSearch</item>
+ <item>com.android.quicksearchbox/.google.GoogleSearch</item>
<item>com.google.android.providers.enhancedgooglesearch/.Launcher</item>
<item>com.android.googlesearch/.GoogleSearch</item>
<item>com.android.websearch/.Search.1</item>
diff --git a/include/media/IMediaDeathNotifier.h b/include/media/IMediaDeathNotifier.h
new file mode 100644
index 0000000..bb3d0d8
--- /dev/null
+++ b/include/media/IMediaDeathNotifier.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_IMEDIADEATHNOTIFIER_H
+#define ANDROID_IMEDIADEATHNOTIFIER_H
+
+#include <utils/threads.h>
+#include <media/IMediaPlayerService.h>
+#include <utils/SortedVector.h>
+
+namespace android {
+
+class IMediaDeathNotifier: virtual public RefBase
+{
+public:
+ IMediaDeathNotifier() { addObitRecipient(this); }
+ virtual ~IMediaDeathNotifier() { removeObitRecipient(this); }
+
+ virtual void died() = 0;
+ static const sp<IMediaPlayerService>& getMediaPlayerService();
+
+private:
+ IMediaDeathNotifier &operator=(const IMediaDeathNotifier &);
+ IMediaDeathNotifier(const IMediaDeathNotifier &);
+
+ static void addObitRecipient(const wp<IMediaDeathNotifier>& recipient);
+ static void removeObitRecipient(const wp<IMediaDeathNotifier>& recipient);
+
+ class DeathNotifier: public IBinder::DeathRecipient
+ {
+ public:
+ DeathNotifier() {}
+ virtual ~DeathNotifier();
+
+ virtual void binderDied(const wp<IBinder>& who);
+ };
+
+ friend class DeathNotifier;
+
+ static Mutex sServiceLock;
+ static sp<IMediaPlayerService> sMediaPlayerService;
+ static sp<DeathNotifier> sDeathNotifier;
+ static SortedVector< wp<IMediaDeathNotifier> > sObitRecipients;
+};
+
+}; // namespace android
+
+#endif // ANDROID_IMEDIADEATHNOTIFIER_H
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 39bd5b1..d38c177 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -42,6 +42,11 @@
typedef void *buffer_id;
typedef void *node_id;
+ // Given the calling process' pid, returns true iff
+ // the implementation of the OMX interface lives in the same
+ // process.
+ virtual bool livesLocally(pid_t pid) = 0;
+
struct ComponentInfo {
String8 mName;
List<String8> mRoles;
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 7132b18..87d23f6 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -21,8 +21,7 @@
#include <ui/Surface.h>
#include <media/IMediaPlayerClient.h>
#include <media/IMediaPlayer.h>
-#include <media/IMediaPlayerService.h>
-#include <utils/SortedVector.h>
+#include <media/IMediaDeathNotifier.h>
namespace android {
@@ -123,12 +122,13 @@
virtual void notify(int msg, int ext1, int ext2) = 0;
};
-class MediaPlayer : public BnMediaPlayerClient
+class MediaPlayer : public BnMediaPlayerClient,
+ public virtual IMediaDeathNotifier
{
public:
MediaPlayer();
~MediaPlayer();
- void onFirstRef();
+ void died();
void disconnect();
status_t setDataSource(const char *url);
status_t setDataSource(int fd, int64_t offset, int64_t length);
@@ -164,19 +164,6 @@
status_t getDuration_l(int *msec);
status_t setDataSource(const sp<IMediaPlayer>& player);
- static const sp<IMediaPlayerService>& getMediaPlayerService();
- static void addObitRecipient(const wp<MediaPlayer>& recipient);
- static void removeObitRecipient(const wp<MediaPlayer>& recipient);
-
- class DeathNotifier: public IBinder::DeathRecipient
- {
- public:
- DeathNotifier() {}
- virtual ~DeathNotifier();
-
- virtual void binderDied(const wp<IBinder>& who);
- };
-
sp<IMediaPlayer> mPlayer;
thread_id_t mLockThreadId;
Mutex mLock;
@@ -196,13 +183,6 @@
float mRightVolume;
int mVideoWidth;
int mVideoHeight;
-
- friend class DeathNotifier;
-
- static Mutex sServiceLock;
- static sp<IMediaPlayerService> sMediaPlayerService;
- static sp<DeathNotifier> sDeathNotifier;
- static SortedVector< wp<MediaPlayer> > sObitRecipients;
};
}; // namespace android
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 8c7392b..9ea6c7b 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -23,6 +23,7 @@
#include <utils/List.h>
#include <utils/Errors.h>
#include <media/IMediaPlayerClient.h>
+#include <media/IMediaDeathNotifier.h>
namespace android {
@@ -145,12 +146,14 @@
virtual void notify(int msg, int ext1, int ext2) = 0;
};
-class MediaRecorder : public BnMediaPlayerClient
+class MediaRecorder : public BnMediaPlayerClient,
+ public virtual IMediaDeathNotifier
{
public:
MediaRecorder();
~MediaRecorder();
+ void died();
status_t initCheck();
status_t setCamera(const sp<ICamera>& camera);
status_t setPreviewSurface(const sp<Surface>& surface);
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 351763c..2c32386 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -109,6 +109,7 @@
};
sp<IOMX> mOMX;
+ bool mOMXLivesLocally;
IOMX::node_id mNode;
uint32_t mQuirks;
bool mIsEncoder;
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index fc234ee..4ae4ec9b 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -24,7 +24,8 @@
IAudioPolicyService.cpp \
MediaScanner.cpp \
MediaScannerClient.cpp \
- autodetect.cpp
+ autodetect.cpp \
+ IMediaDeathNotifier.cpp
LOCAL_SHARED_LIBRARIES := \
libui libcutils libutils libbinder libsonivox libicuuc
diff --git a/media/libmedia/IMediaDeathNotifier.cpp b/media/libmedia/IMediaDeathNotifier.cpp
new file mode 100644
index 0000000..39ac076
--- /dev/null
+++ b/media/libmedia/IMediaDeathNotifier.cpp
@@ -0,0 +1,111 @@
+/*
+** Copyright 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.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "IMediaDeathNotifier"
+#include <utils/Log.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <media/IMediaDeathNotifier.h>
+
+namespace android {
+
+// client singleton for binder interface to services
+Mutex IMediaDeathNotifier::sServiceLock;
+sp<IMediaPlayerService> IMediaDeathNotifier::sMediaPlayerService;
+sp<IMediaDeathNotifier::DeathNotifier> IMediaDeathNotifier::sDeathNotifier;
+SortedVector< wp<IMediaDeathNotifier> > IMediaDeathNotifier::sObitRecipients;
+
+// establish binder interface to MediaPlayerService
+/*static*/const sp<IMediaPlayerService>&
+IMediaDeathNotifier::getMediaPlayerService()
+{
+ LOGV("getMediaPlayerService");
+ Mutex::Autolock _l(sServiceLock);
+ if (sMediaPlayerService.get() == 0) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder;
+ do {
+ binder = sm->getService(String16("media.player"));
+ if (binder != 0) {
+ break;
+ }
+ LOGW("Media player service not published, waiting...");
+ usleep(500000); // 0.5 s
+ } while(true);
+
+ if (sDeathNotifier == NULL) {
+ sDeathNotifier = new DeathNotifier();
+ }
+ binder->linkToDeath(sDeathNotifier);
+ sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
+ }
+ LOGE_IF(sMediaPlayerService == 0, "no media player service!?");
+ return sMediaPlayerService;
+}
+
+/*static*/ void
+IMediaDeathNotifier::addObitRecipient(const wp<IMediaDeathNotifier>& recipient)
+{
+ LOGV("addObitRecipient");
+ Mutex::Autolock _l(sServiceLock);
+ sObitRecipients.add(recipient);
+}
+
+/*static*/ void
+IMediaDeathNotifier::removeObitRecipient(const wp<IMediaDeathNotifier>& recipient)
+{
+ LOGV("removeObitRecipient");
+ Mutex::Autolock _l(sServiceLock);
+ sObitRecipients.remove(recipient);
+}
+
+void
+IMediaDeathNotifier::DeathNotifier::binderDied(const wp<IBinder>& who) {
+ LOGW("media server died");
+
+ // Need to do this with the lock held
+ SortedVector< wp<IMediaDeathNotifier> > list;
+ {
+ Mutex::Autolock _l(sServiceLock);
+ sMediaPlayerService.clear();
+ list = sObitRecipients;
+ }
+
+ // Notify application when media server dies.
+ // Don't hold the static lock during callback in case app
+ // makes a call that needs the lock.
+ size_t count = list.size();
+ for (size_t iter = 0; iter < count; ++iter) {
+ sp<IMediaDeathNotifier> notifier = list[iter].promote();
+ if (notifier != 0) {
+ notifier->died();
+ }
+ }
+}
+
+IMediaDeathNotifier::DeathNotifier::~DeathNotifier()
+{
+ LOGV("DeathNotifier::~DeathNotifier");
+ Mutex::Autolock _l(sServiceLock);
+ sObitRecipients.clear();
+ if (sMediaPlayerService != 0) {
+ sMediaPlayerService->asBinder()->unlinkToDeath(this);
+ }
+}
+
+}; // namespace android
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index b43e48f..277bce1 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -12,6 +12,7 @@
enum {
CONNECT = IBinder::FIRST_CALL_TRANSACTION,
+ LIVES_LOCALLY,
LIST_NODES,
ALLOCATE_NODE,
FREE_NODE,
@@ -75,6 +76,15 @@
: BpInterface<IOMX>(impl) {
}
+ virtual bool livesLocally(pid_t pid) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeInt32(pid);
+ remote()->transact(LIVES_LOCALLY, data, &reply);
+
+ return reply.readInt32() != 0;
+ }
+
virtual status_t listNodes(List<ComponentInfo> *list) {
list->clear();
@@ -369,6 +379,14 @@
status_t BnOMX::onTransact(
uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
switch (code) {
+ case LIVES_LOCALLY:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+ reply->writeInt32(livesLocally((pid_t)data.readInt32()));
+
+ return OK;
+ }
+
case LIST_NODES:
{
CHECK_INTERFACE(IOMX, data, reply);
@@ -408,7 +426,7 @@
if (err == OK) {
reply->writeIntPtr((intptr_t)node);
}
-
+
return NO_ERROR;
}
@@ -419,7 +437,7 @@
node_id node = (void*)data.readIntPtr();
reply->writeInt32(freeNode(node));
-
+
return NO_ERROR;
}
@@ -631,7 +649,7 @@
node_id node = (void*)data.readIntPtr();
const char *parameter_name = data.readCString();
-
+
OMX_INDEXTYPE index;
status_t err = getExtensionIndex(node, parameter_name, &index);
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 040366b..c0664f3 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -34,48 +34,6 @@
namespace android {
-// client singleton for binder interface to service
-Mutex MediaPlayer::sServiceLock;
-sp<IMediaPlayerService> MediaPlayer::sMediaPlayerService;
-sp<MediaPlayer::DeathNotifier> MediaPlayer::sDeathNotifier;
-SortedVector< wp<MediaPlayer> > MediaPlayer::sObitRecipients;
-
-// establish binder interface to service
-const sp<IMediaPlayerService>& MediaPlayer::getMediaPlayerService()
-{
- Mutex::Autolock _l(sServiceLock);
- if (sMediaPlayerService.get() == 0) {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder;
- do {
- binder = sm->getService(String16("media.player"));
- if (binder != 0)
- break;
- LOGW("MediaPlayerService not published, waiting...");
- usleep(500000); // 0.5 s
- } while(true);
- if (sDeathNotifier == NULL) {
- sDeathNotifier = new DeathNotifier();
- }
- binder->linkToDeath(sDeathNotifier);
- sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
- }
- LOGE_IF(sMediaPlayerService==0, "no MediaPlayerService!?");
- return sMediaPlayerService;
-}
-
-void MediaPlayer::addObitRecipient(const wp<MediaPlayer>& recipient)
-{
- Mutex::Autolock _l(sServiceLock);
- sObitRecipients.add(recipient);
-}
-
-void MediaPlayer::removeObitRecipient(const wp<MediaPlayer>& recipient)
-{
- Mutex::Autolock _l(sServiceLock);
- sObitRecipients.remove(recipient);
-}
-
MediaPlayer::MediaPlayer()
{
LOGV("constructor");
@@ -94,15 +52,9 @@
mLockThreadId = 0;
}
-void MediaPlayer::onFirstRef()
-{
- addObitRecipient(this);
-}
-
MediaPlayer::~MediaPlayer()
{
LOGV("destructor");
- removeObitRecipient(this);
disconnect();
IPCThreadState::self()->flushCommands();
}
@@ -630,45 +582,13 @@
}
}
-void MediaPlayer::DeathNotifier::binderDied(const wp<IBinder>& who) {
- LOGW("MediaPlayer server died!");
-
- // Need to do this with the lock held
- SortedVector< wp<MediaPlayer> > list;
- {
- Mutex::Autolock _l(MediaPlayer::sServiceLock);
- MediaPlayer::sMediaPlayerService.clear();
- list = sObitRecipients;
- }
-
- // Notify application when media server dies.
- // Don't hold the static lock during callback in case app
- // makes a call that needs the lock.
- size_t count = list.size();
- for (size_t iter = 0; iter < count; ++iter) {
- sp<MediaPlayer> player = list[iter].promote();
- if ((player != 0) && (player->mPlayer != 0)) {
- player->notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
- }
- }
-}
-
-MediaPlayer::DeathNotifier::~DeathNotifier()
-{
- Mutex::Autolock _l(sServiceLock);
- sObitRecipients.clear();
- if (sMediaPlayerService != 0) {
- sMediaPlayerService->asBinder()->unlinkToDeath(this);
- }
-}
-
/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
{
LOGV("decode(%s)", url);
sp<IMemory> p;
const sp<IMediaPlayerService>& service = getMediaPlayerService();
if (service != 0) {
- p = sMediaPlayerService->decode(url, pSampleRate, pNumChannels, pFormat);
+ p = service->decode(url, pSampleRate, pNumChannels, pFormat);
} else {
LOGE("Unable to locate media service");
}
@@ -676,13 +596,19 @@
}
+void MediaPlayer::died()
+{
+ LOGV("died");
+ notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
+}
+
/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
{
LOGV("decode(%d, %lld, %lld)", fd, offset, length);
sp<IMemory> p;
const sp<IMediaPlayerService>& service = getMediaPlayerService();
if (service != 0) {
- p = sMediaPlayerService->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
+ p = service->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
} else {
LOGE("Unable to locate media service");
}
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 6b63931..7b5dabb 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -24,6 +24,7 @@
#include <utils/String8.h>
#include <media/IMediaPlayerService.h>
#include <media/IMediaRecorder.h>
+#include <media/mediaplayer.h> // for MEDIA_ERROR_SERVER_DIED
namespace android {
@@ -576,19 +577,8 @@
MediaRecorder::MediaRecorder()
{
LOGV("constructor");
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder;
- do {
- binder = sm->getService(String16("media.player"));
- if (binder != NULL) {
- break;
- }
- LOGW("MediaPlayerService not published, waiting...");
- usleep(500000); // 0.5 s
- } while(true);
-
- sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+ const sp<IMediaPlayerService>& service(getMediaPlayerService());
if (service != NULL) {
mMediaRecorder = service->createMediaRecorder(getpid());
}
@@ -637,5 +627,11 @@
}
}
+void MediaRecorder::died()
+{
+ LOGV("died");
+ notify(MEDIA_RECORDER_EVENT_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
+}
+
}; // namespace android
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index e36e78c..26b9357 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -29,6 +29,7 @@
MPEG4Extractor.cpp \
MPEG4Writer.cpp \
MediaExtractor.cpp \
+ SampleIterator.cpp \
SampleTable.cpp \
ShoutcastSource.cpp \
StagefrightMediaScanner.cpp \
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 07a5a82..0e9900b 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -232,8 +232,9 @@
uint32_t sampleIndex;
uint32_t sampleTime;
if (track->sampleTable->findThumbnailSample(&sampleIndex) == OK
- && track->sampleTable->getDecodingTime(
- sampleIndex, &sampleTime) == OK) {
+ && track->sampleTable->getMetaDataForSample(
+ sampleIndex, NULL /* offset */, NULL /* size */,
+ &sampleTime) == OK) {
track->meta->setInt64(
kKeyThumbnailTime,
((int64_t)sampleTime * 1000000) / track->timescale);
@@ -929,20 +930,16 @@
if (mBuffer == NULL) {
newBuffer = true;
- status_t err = mSampleTable->getSampleOffsetAndSize(
- mCurrentSampleIndex, &offset, &size);
-
- if (err != OK) {
- return err;
- }
-
- err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts);
+ status_t err =
+ mSampleTable->getMetaDataForSample(
+ mCurrentSampleIndex, &offset, &size, &dts);
if (err != OK) {
return err;
}
err = mGroup->acquire_buffer(&mBuffer);
+
if (err != OK) {
CHECK_EQ(mBuffer, NULL);
return err;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index c4d3b5d..c583b93 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1016,6 +1016,7 @@
const char *componentName,
const sp<MediaSource> &source)
: mOMX(omx),
+ mOMXLivesLocally(omx->livesLocally(getpid())),
mNode(node),
mQuirks(quirks),
mIsEncoder(isEncoder),
@@ -1191,12 +1192,22 @@
IOMX::buffer_id buffer;
if (portIndex == kPortIndexInput
&& (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
- err = mOMX->allocateBufferWithBackup(
- mNode, portIndex, mem, &buffer);
+ if (mOMXLivesLocally) {
+ err = mOMX->allocateBuffer(
+ mNode, portIndex, def.nBufferSize, &buffer);
+ } else {
+ err = mOMX->allocateBufferWithBackup(
+ mNode, portIndex, mem, &buffer);
+ }
} else if (portIndex == kPortIndexOutput
&& (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
- err = mOMX->allocateBufferWithBackup(
- mNode, portIndex, mem, &buffer);
+ if (mOMXLivesLocally) {
+ err = mOMX->allocateBuffer(
+ mNode, portIndex, def.nBufferSize, &buffer);
+ } else {
+ err = mOMX->allocateBufferWithBackup(
+ mNode, portIndex, mem, &buffer);
+ }
} else {
err = mOMX->useBuffer(mNode, portIndex, mem, &buffer);
}
diff --git a/media/libstagefright/SampleIterator.cpp b/media/libstagefright/SampleIterator.cpp
new file mode 100644
index 0000000..faad42ba
--- /dev/null
+++ b/media/libstagefright/SampleIterator.cpp
@@ -0,0 +1,310 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SampleIterator"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include "include/SampleIterator.h"
+
+#include <arpa/inet.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/Utils.h>
+
+#include "include/SampleTable.h"
+
+namespace android {
+
+SampleIterator::SampleIterator(SampleTable *table)
+ : mTable(table),
+ mInitialized(false),
+ mTimeToSampleIndex(0),
+ mTTSSampleIndex(0),
+ mTTSSampleTime(0),
+ mTTSCount(0),
+ mTTSDuration(0) {
+ reset();
+}
+
+void SampleIterator::reset() {
+ mSampleToChunkIndex = 0;
+ mFirstChunk = 0;
+ mFirstChunkSampleIndex = 0;
+ mStopChunk = 0;
+ mStopChunkSampleIndex = 0;
+ mSamplesPerChunk = 0;
+ mChunkDesc = 0;
+}
+
+status_t SampleIterator::seekTo(uint32_t sampleIndex) {
+ LOGV("seekTo(%d)", sampleIndex);
+
+ if (mTable->mSampleToChunkOffset < 0
+ || mTable->mChunkOffsetOffset < 0
+ || mTable->mSampleSizeOffset < 0
+ || mTable->mTimeToSampleCount == 0) {
+
+ return ERROR_MALFORMED;
+ }
+
+ if (mInitialized && mCurrentSampleIndex == sampleIndex) {
+ return OK;
+ }
+
+ if (!mInitialized || sampleIndex < mFirstChunkSampleIndex) {
+ reset();
+ }
+
+ if (sampleIndex >= mStopChunkSampleIndex) {
+ status_t err;
+ if ((err = findChunkRange(sampleIndex)) != OK) {
+ LOGE("findChunkRange failed");
+ return err;
+ }
+ }
+
+ CHECK(sampleIndex < mStopChunkSampleIndex);
+
+ uint32_t chunk =
+ (sampleIndex - mFirstChunkSampleIndex) / mSamplesPerChunk
+ + mFirstChunk;
+
+ if (!mInitialized || chunk != mCurrentChunkIndex) {
+ mCurrentChunkIndex = chunk;
+
+ status_t err;
+ if ((err = getChunkOffset(chunk, &mCurrentChunkOffset)) != OK) {
+ LOGE("getChunkOffset return error");
+ return err;
+ }
+
+ mCurrentChunkSampleSizes.clear();
+
+ uint32_t firstChunkSampleIndex =
+ mFirstChunkSampleIndex
+ + mSamplesPerChunk * (mCurrentChunkIndex - mFirstChunk);
+
+ for (uint32_t i = 0; i < mSamplesPerChunk; ++i) {
+ size_t sampleSize;
+ if ((err = getSampleSizeDirect(
+ firstChunkSampleIndex + i, &sampleSize)) != OK) {
+ LOGE("getSampleSizeDirect return error");
+ return err;
+ }
+
+ mCurrentChunkSampleSizes.push(sampleSize);
+ }
+ }
+
+ uint32_t chunkRelativeSampleIndex =
+ (sampleIndex - mFirstChunkSampleIndex) % mSamplesPerChunk;
+
+ mCurrentSampleOffset = mCurrentChunkOffset;
+ for (uint32_t i = 0; i < chunkRelativeSampleIndex; ++i) {
+ mCurrentSampleOffset += mCurrentChunkSampleSizes[i];
+ }
+
+ mCurrentSampleSize = mCurrentChunkSampleSizes[chunkRelativeSampleIndex];
+ if (sampleIndex < mTTSSampleIndex) {
+ mTimeToSampleIndex = 0;
+ mTTSSampleIndex = 0;
+ mTTSSampleTime = 0;
+ mTTSCount = 0;
+ mTTSDuration = 0;
+ }
+
+ status_t err;
+ if ((err = findSampleTime(sampleIndex, &mCurrentSampleTime)) != OK) {
+ LOGE("findSampleTime return error");
+ return err;
+ }
+
+ mCurrentSampleIndex = sampleIndex;
+
+ mInitialized = true;
+
+ return OK;
+}
+
+status_t SampleIterator::findChunkRange(uint32_t sampleIndex) {
+ CHECK(sampleIndex >= mFirstChunkSampleIndex);
+
+ while (sampleIndex >= mStopChunkSampleIndex) {
+ if (mSampleToChunkIndex == mTable->mNumSampleToChunkOffsets) {
+ return ERROR_OUT_OF_RANGE;
+ }
+
+ mFirstChunkSampleIndex = mStopChunkSampleIndex;
+
+ const SampleTable::SampleToChunkEntry *entry =
+ &mTable->mSampleToChunkEntries[mSampleToChunkIndex];
+
+ mFirstChunk = entry->startChunk;
+ mSamplesPerChunk = entry->samplesPerChunk;
+ mChunkDesc = entry->chunkDesc;
+
+ if (mSampleToChunkIndex + 1 < mTable->mNumSampleToChunkOffsets) {
+ mStopChunk = entry[1].startChunk;
+
+ mStopChunkSampleIndex =
+ mFirstChunkSampleIndex
+ + (mStopChunk - mFirstChunk) * mSamplesPerChunk;
+ } else {
+ mStopChunk = 0xffffffff;
+ mStopChunkSampleIndex = 0xffffffff;
+ }
+
+ ++mSampleToChunkIndex;
+ }
+
+ return OK;
+}
+
+status_t SampleIterator::getChunkOffset(uint32_t chunk, off_t *offset) {
+ *offset = 0;
+
+ if (chunk >= mTable->mNumChunkOffsets) {
+ return ERROR_OUT_OF_RANGE;
+ }
+
+ if (mTable->mChunkOffsetType == SampleTable::kChunkOffsetType32) {
+ uint32_t offset32;
+
+ if (mTable->mDataSource->readAt(
+ mTable->mChunkOffsetOffset + 8 + 4 * chunk,
+ &offset32,
+ sizeof(offset32)) < (ssize_t)sizeof(offset32)) {
+ return ERROR_IO;
+ }
+
+ *offset = ntohl(offset32);
+ } else {
+ CHECK_EQ(mTable->mChunkOffsetType, SampleTable::kChunkOffsetType64);
+
+ uint64_t offset64;
+ if (mTable->mDataSource->readAt(
+ mTable->mChunkOffsetOffset + 8 + 8 * chunk,
+ &offset64,
+ sizeof(offset64)) < (ssize_t)sizeof(offset64)) {
+ return ERROR_IO;
+ }
+
+ *offset = ntoh64(offset64);
+ }
+
+ return OK;
+}
+
+status_t SampleIterator::getSampleSizeDirect(
+ uint32_t sampleIndex, size_t *size) {
+ *size = 0;
+
+ if (sampleIndex >= mTable->mNumSampleSizes) {
+ return ERROR_OUT_OF_RANGE;
+ }
+
+ if (mTable->mDefaultSampleSize > 0) {
+ *size = mTable->mDefaultSampleSize;
+ return OK;
+ }
+
+ switch (mTable->mSampleSizeFieldSize) {
+ case 32:
+ {
+ if (mTable->mDataSource->readAt(
+ mTable->mSampleSizeOffset + 12 + 4 * sampleIndex,
+ size, sizeof(*size)) < (ssize_t)sizeof(*size)) {
+ return ERROR_IO;
+ }
+
+ *size = ntohl(*size);
+ break;
+ }
+
+ case 16:
+ {
+ uint16_t x;
+ if (mTable->mDataSource->readAt(
+ mTable->mSampleSizeOffset + 12 + 2 * sampleIndex,
+ &x, sizeof(x)) < (ssize_t)sizeof(x)) {
+ return ERROR_IO;
+ }
+
+ *size = ntohs(x);
+ break;
+ }
+
+ case 8:
+ {
+ uint8_t x;
+ if (mTable->mDataSource->readAt(
+ mTable->mSampleSizeOffset + 12 + sampleIndex,
+ &x, sizeof(x)) < (ssize_t)sizeof(x)) {
+ return ERROR_IO;
+ }
+
+ *size = x;
+ break;
+ }
+
+ default:
+ {
+ CHECK_EQ(mTable->mSampleSizeFieldSize, 4);
+
+ uint8_t x;
+ if (mTable->mDataSource->readAt(
+ mTable->mSampleSizeOffset + 12 + sampleIndex / 2,
+ &x, sizeof(x)) < (ssize_t)sizeof(x)) {
+ return ERROR_IO;
+ }
+
+ *size = (sampleIndex & 1) ? x & 0x0f : x >> 4;
+ break;
+ }
+ }
+
+ return OK;
+}
+
+status_t SampleIterator::findSampleTime(
+ uint32_t sampleIndex, uint32_t *time) {
+ if (sampleIndex >= mTable->mNumSampleSizes) {
+ return ERROR_OUT_OF_RANGE;
+ }
+
+ while (sampleIndex >= mTTSSampleIndex + mTTSCount) {
+ if (mTimeToSampleIndex == mTable->mTimeToSampleCount) {
+ return ERROR_OUT_OF_RANGE;
+ }
+
+ mTTSSampleIndex += mTTSCount;
+ mTTSSampleTime += mTTSCount * mTTSDuration;
+
+ mTTSCount = mTable->mTimeToSample[2 * mTimeToSampleIndex];
+ mTTSDuration = mTable->mTimeToSample[2 * mTimeToSampleIndex + 1];
+
+ ++mTimeToSampleIndex;
+ }
+
+ *time = mTTSSampleTime + mTTSDuration * (sampleIndex - mTTSSampleIndex);
+
+ return OK;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 2de96d4..89a522e 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -15,9 +15,11 @@
*/
#define LOG_TAG "SampleTable"
+//#define LOG_NDEBUG 0
#include <utils/Log.h>
#include "include/SampleTable.h"
+#include "include/SampleIterator.h"
#include <arpa/inet.h>
@@ -27,10 +29,16 @@
namespace android {
-static const uint32_t kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o');
-static const uint32_t kChunkOffsetType64 = FOURCC('c', 'o', '6', '4');
-static const uint32_t kSampleSizeType32 = FOURCC('s', 't', 's', 'z');
-static const uint32_t kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2');
+// static
+const uint32_t SampleTable::kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o');
+// static
+const uint32_t SampleTable::kChunkOffsetType64 = FOURCC('c', 'o', '6', '4');
+// static
+const uint32_t SampleTable::kSampleSizeType32 = FOURCC('s', 't', 's', 'z');
+// static
+const uint32_t SampleTable::kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2');
+
+////////////////////////////////////////////////////////////////////////////////
SampleTable::SampleTable(const sp<DataSource> &source)
: mDataSource(source),
@@ -46,12 +54,20 @@
mTimeToSampleCount(0),
mTimeToSample(NULL),
mSyncSampleOffset(-1),
- mNumSyncSamples(0) {
+ mNumSyncSamples(0),
+ mSampleToChunkEntries(NULL) {
+ mSampleIterator = new SampleIterator(this);
}
SampleTable::~SampleTable() {
+ delete[] mSampleToChunkEntries;
+ mSampleToChunkEntries = NULL;
+
delete[] mTimeToSample;
mTimeToSample = NULL;
+
+ delete mSampleIterator;
+ mSampleIterator = NULL;
}
status_t SampleTable::setChunkOffsetParams(
@@ -124,6 +140,25 @@
return ERROR_MALFORMED;
}
+ mSampleToChunkEntries =
+ new SampleToChunkEntry[mNumSampleToChunkOffsets];
+
+ for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) {
+ uint8_t buffer[12];
+ if (mDataSource->readAt(
+ mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer))
+ != (ssize_t)sizeof(buffer)) {
+ return ERROR_IO;
+ }
+
+ CHECK(U32_AT(buffer) >= 1); // chunk index is 1 based in the spec.
+
+ // We want the chunk index to be 0-based.
+ mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1;
+ mSampleToChunkEntries[i].samplesPerChunk = U32_AT(&buffer[4]);
+ mSampleToChunkEntries[i].chunkDesc = U32_AT(&buffer[8]);
+ }
+
return OK;
}
@@ -250,217 +285,10 @@
return mNumChunkOffsets;
}
-status_t SampleTable::getChunkOffset(uint32_t chunk_index, off_t *offset) {
- *offset = 0;
-
- if (mChunkOffsetOffset < 0) {
- return ERROR_MALFORMED;
- }
-
- if (chunk_index >= mNumChunkOffsets) {
- return ERROR_OUT_OF_RANGE;
- }
-
- if (mChunkOffsetType == kChunkOffsetType32) {
- uint32_t offset32;
-
- if (mDataSource->readAt(
- mChunkOffsetOffset + 8 + 4 * chunk_index,
- &offset32,
- sizeof(offset32)) < (ssize_t)sizeof(offset32)) {
- return ERROR_IO;
- }
-
- *offset = ntohl(offset32);
- } else {
- CHECK_EQ(mChunkOffsetType, kChunkOffsetType64);
-
- uint64_t offset64;
- if (mDataSource->readAt(
- mChunkOffsetOffset + 8 + 8 * chunk_index,
- &offset64,
- sizeof(offset64)) < (ssize_t)sizeof(offset64)) {
- return ERROR_IO;
- }
-
- *offset = ntoh64(offset64);
- }
-
- return OK;
-}
-
-status_t SampleTable::getChunkForSample(
- uint32_t sample_index,
- uint32_t *chunk_index,
- uint32_t *chunk_relative_sample_index,
- uint32_t *desc_index) {
- *chunk_index = 0;
- *chunk_relative_sample_index = 0;
- *desc_index = 0;
-
- if (mSampleToChunkOffset < 0) {
- return ERROR_MALFORMED;
- }
-
- if (sample_index >= countSamples()) {
- return ERROR_END_OF_STREAM;
- }
-
- uint32_t first_chunk = 0;
- uint32_t samples_per_chunk = 0;
- uint32_t chunk_desc_index = 0;
-
- uint32_t index = 0;
- while (index < mNumSampleToChunkOffsets) {
- uint8_t buffer[12];
- if (mDataSource->readAt(mSampleToChunkOffset + 8 + index * 12,
- buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
- return ERROR_IO;
- }
-
- uint32_t stop_chunk = U32_AT(buffer);
- if (sample_index < (stop_chunk - first_chunk) * samples_per_chunk) {
- break;
- }
-
- sample_index -= (stop_chunk - first_chunk) * samples_per_chunk;
- first_chunk = stop_chunk;
- samples_per_chunk = U32_AT(&buffer[4]);
- chunk_desc_index = U32_AT(&buffer[8]);
-
- ++index;
- }
-
- *chunk_index = sample_index / samples_per_chunk + first_chunk - 1;
- *chunk_relative_sample_index = sample_index % samples_per_chunk;
- *desc_index = chunk_desc_index;
-
- return OK;
-}
-
uint32_t SampleTable::countSamples() const {
return mNumSampleSizes;
}
-status_t SampleTable::getSampleSize(
- uint32_t sample_index, size_t *sample_size) {
- *sample_size = 0;
-
- if (mSampleSizeOffset < 0) {
- return ERROR_MALFORMED;
- }
-
- if (sample_index >= mNumSampleSizes) {
- return ERROR_OUT_OF_RANGE;
- }
-
- if (mDefaultSampleSize > 0) {
- *sample_size = mDefaultSampleSize;
- return OK;
- }
-
- switch (mSampleSizeFieldSize) {
- case 32:
- {
- if (mDataSource->readAt(
- mSampleSizeOffset + 12 + 4 * sample_index,
- sample_size, sizeof(*sample_size)) < (ssize_t)sizeof(*sample_size)) {
- return ERROR_IO;
- }
-
- *sample_size = ntohl(*sample_size);
- break;
- }
-
- case 16:
- {
- uint16_t x;
- if (mDataSource->readAt(
- mSampleSizeOffset + 12 + 2 * sample_index,
- &x, sizeof(x)) < (ssize_t)sizeof(x)) {
- return ERROR_IO;
- }
-
- *sample_size = ntohs(x);
- break;
- }
-
- case 8:
- {
- uint8_t x;
- if (mDataSource->readAt(
- mSampleSizeOffset + 12 + sample_index,
- &x, sizeof(x)) < (ssize_t)sizeof(x)) {
- return ERROR_IO;
- }
-
- *sample_size = x;
- break;
- }
-
- default:
- {
- CHECK_EQ(mSampleSizeFieldSize, 4);
-
- uint8_t x;
- if (mDataSource->readAt(
- mSampleSizeOffset + 12 + sample_index / 2,
- &x, sizeof(x)) < (ssize_t)sizeof(x)) {
- return ERROR_IO;
- }
-
- *sample_size = (sample_index & 1) ? x & 0x0f : x >> 4;
- break;
- }
- }
-
- return OK;
-}
-
-status_t SampleTable::getSampleOffsetAndSize(
- uint32_t sample_index, off_t *offset, size_t *size) {
- Mutex::Autolock autoLock(mLock);
-
- *offset = 0;
- *size = 0;
-
- uint32_t chunk_index;
- uint32_t chunk_relative_sample_index;
- uint32_t desc_index;
- status_t err = getChunkForSample(
- sample_index, &chunk_index, &chunk_relative_sample_index,
- &desc_index);
-
- if (err != OK) {
- return err;
- }
-
- err = getChunkOffset(chunk_index, offset);
-
- if (err != OK) {
- return err;
- }
-
- for (uint32_t j = 0; j < chunk_relative_sample_index; ++j) {
- size_t sample_size;
- err = getSampleSize(sample_index - j - 1, &sample_size);
-
- if (err != OK) {
- return err;
- }
-
- *offset += sample_size;
- }
-
- err = getSampleSize(sample_index, size);
-
- if (err != OK) {
- return err;
- }
-
- return OK;
-}
-
status_t SampleTable::getMaxSampleSize(size_t *max_size) {
Mutex::Autolock autoLock(mLock);
@@ -468,7 +296,7 @@
for (uint32_t i = 0; i < mNumSampleSizes; ++i) {
size_t sample_size;
- status_t err = getSampleSize(i, &sample_size);
+ status_t err = getSampleSize_l(i, &sample_size);
if (err != OK) {
return err;
@@ -482,34 +310,6 @@
return OK;
}
-status_t SampleTable::getDecodingTime(uint32_t sample_index, uint32_t *time) {
- // XXX FIXME idiotic (for the common use-case) O(n) algorithm below...
-
- Mutex::Autolock autoLock(mLock);
-
- if (sample_index >= mNumSampleSizes) {
- return ERROR_OUT_OF_RANGE;
- }
-
- uint32_t cur_sample = 0;
- *time = 0;
- for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
- uint32_t n = mTimeToSample[2 * i];
- uint32_t delta = mTimeToSample[2 * i + 1];
-
- if (sample_index < cur_sample + n) {
- *time += delta * (sample_index - cur_sample);
-
- return OK;
- }
-
- *time += delta * n;
- cur_sample += n;
- }
-
- return ERROR_OUT_OF_RANGE;
-}
-
uint32_t abs_difference(uint32_t time1, uint32_t time2) {
return time1 > time2 ? time1 - time2 : time2 - time1;
}
@@ -539,7 +339,7 @@
}
if (flags & kSyncSample_Flag) {
- return findClosestSyncSample(*sample_index, sample_index);
+ return findClosestSyncSample_l(*sample_index, sample_index);
}
return OK;
@@ -552,7 +352,7 @@
return ERROR_OUT_OF_RANGE;
}
-status_t SampleTable::findClosestSyncSample(
+status_t SampleTable::findClosestSyncSample_l(
uint32_t start_sample_index, uint32_t *sample_index) {
*sample_index = 0;
@@ -590,6 +390,8 @@
}
status_t SampleTable::findThumbnailSample(uint32_t *sample_index) {
+ Mutex::Autolock autoLock(mLock);
+
if (mSyncSampleOffset < 0) {
// All samples are sync-samples.
*sample_index = 0;
@@ -620,7 +422,7 @@
// Now x is a sample index.
size_t sampleSize;
- status_t err = getSampleSize(x, &sampleSize);
+ status_t err = getSampleSize_l(x, &sampleSize);
if (err != OK) {
return err;
}
@@ -636,5 +438,38 @@
return OK;
}
+status_t SampleTable::getSampleSize_l(
+ uint32_t sampleIndex, size_t *sampleSize) {
+ return mSampleIterator->getSampleSizeDirect(
+ sampleIndex, sampleSize);
+}
+
+status_t SampleTable::getMetaDataForSample(
+ uint32_t sampleIndex,
+ off_t *offset,
+ size_t *size,
+ uint32_t *decodingTime) {
+ Mutex::Autolock autoLock(mLock);
+
+ status_t err;
+ if ((err = mSampleIterator->seekTo(sampleIndex)) != OK) {
+ return err;
+ }
+
+ if (offset) {
+ *offset = mSampleIterator->getSampleOffset();
+ }
+
+ if (size) {
+ *size = mSampleIterator->getSampleSize();
+ }
+
+ if (decodingTime) {
+ *decodingTime = mSampleIterator->getSampleTime();
+ }
+
+ return OK;
+}
+
} // namespace android
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 2b3ef1a..6d64717 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -33,7 +33,11 @@
mSize(0),
mFirstFrameOffset(0),
mVersion(ID3_UNKNOWN) {
- mIsValid = parse(source);
+ mIsValid = parseV2(source);
+
+ if (!mIsValid) {
+ mIsValid = parseV1(source);
+ }
}
ID3::~ID3() {
@@ -51,7 +55,7 @@
return mVersion;
}
-bool ID3::parse(const sp<DataSource> &source) {
+bool ID3::parseV2(const sp<DataSource> &source) {
struct id3_header {
char id[3];
uint8_t version_major;
@@ -119,7 +123,7 @@
}
if (header.flags & 0x80) {
- LOGI("removing unsynchronization");
+ LOGV("removing unsynchronization");
removeUnsynchronization();
}
@@ -128,12 +132,18 @@
// Version 2.3 has an optional extended header.
if (mSize < 4) {
+ free(mData);
+ mData = NULL;
+
return false;
}
size_t extendedHeaderSize = U32_AT(&mData[0]) + 4;
if (extendedHeaderSize > mSize) {
+ free(mData);
+ mData = NULL;
+
return false;
}
@@ -147,6 +157,9 @@
size_t paddingSize = U32_AT(&mData[6]);
if (mFirstFrameOffset + paddingSize > mSize) {
+ free(mData);
+ mData = NULL;
+
return false;
}
@@ -154,7 +167,7 @@
}
if (extendedFlags & 0x8000) {
- LOGI("have crc");
+ LOGV("have crc");
}
}
}
@@ -221,9 +234,37 @@
if (mParent.mVersion == ID3_V2_2) {
id->setTo((const char *)&mParent.mData[mOffset], 3);
- } else {
- CHECK_EQ(mParent.mVersion, ID3_V2_3);
+ } else if (mParent.mVersion == ID3_V2_3) {
id->setTo((const char *)&mParent.mData[mOffset], 4);
+ } else {
+ CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1);
+
+ switch (mOffset) {
+ case 3:
+ id->setTo("TT2");
+ break;
+ case 33:
+ id->setTo("TP1");
+ break;
+ case 63:
+ id->setTo("TAL");
+ break;
+ case 93:
+ id->setTo("TYE");
+ break;
+ case 97:
+ id->setTo("COM");
+ break;
+ case 126:
+ id->setTo("TRK");
+ break;
+ case 127:
+ id->setTo("TCO");
+ break;
+ default:
+ CHECK(!"should not be here.");
+ break;
+ }
}
}
@@ -273,6 +314,20 @@
return;
}
+ if (mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1) {
+ if (mOffset == 126 || mOffset == 127) {
+ // Special treatment for the track number and genre.
+ char tmp[16];
+ sprintf(tmp, "%d", (int)*mFrameData);
+
+ id->setTo(tmp);
+ return;
+ }
+
+ id->setTo((const char *)mFrameData, mFrameSize);
+ return;
+ }
+
size_t n = mFrameSize - getHeaderLength() - 1;
if (*mFrameData == 0x00) {
@@ -280,7 +335,8 @@
convertISO8859ToString8(mFrameData + 1, n, id);
} else {
// UCS-2
- id->setTo((const char16_t *)(mFrameData + 1), n);
+ // API wants number of characters, not number of bytes...
+ id->setTo((const char16_t *)(mFrameData + 1), n / 2);
}
}
@@ -299,9 +355,11 @@
size_t ID3::Iterator::getHeaderLength() const {
if (mParent.mVersion == ID3_V2_2) {
return 6;
- } else {
- CHECK_EQ(mParent.mVersion, ID3_V2_3);
+ } else if (mParent.mVersion == ID3_V2_3) {
return 10;
+ } else {
+ CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1);
+ return 0;
}
}
@@ -345,9 +403,7 @@
if (!strcmp(id, mID)) {
break;
}
- } else {
- CHECK_EQ(mParent.mVersion, ID3_V2_3);
-
+ } else if (mParent.mVersion == ID3_V2_3) {
if (mOffset + 10 > mParent.mSize) {
return;
}
@@ -377,6 +433,52 @@
if (!strcmp(id, mID)) {
break;
}
+ } else {
+ CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1);
+
+ if (mOffset >= mParent.mSize) {
+ return;
+ }
+
+ mFrameData = &mParent.mData[mOffset];
+
+ switch (mOffset) {
+ case 3:
+ case 33:
+ case 63:
+ mFrameSize = 30;
+ break;
+ case 93:
+ mFrameSize = 4;
+ break;
+ case 97:
+ if (mParent.mVersion == ID3_V1) {
+ mFrameSize = 30;
+ } else {
+ mFrameSize = 29;
+ }
+ break;
+ case 126:
+ mFrameSize = 1;
+ break;
+ case 127:
+ mFrameSize = 1;
+ break;
+ default:
+ CHECK(!"Should not be here, invalid offset.");
+ break;
+ }
+
+ if (!mID) {
+ break;
+ }
+
+ String8 id;
+ getID(&id);
+
+ if (id == mID) {
+ break;
+ }
}
mOffset += mFrameSize;
@@ -461,5 +563,40 @@
return NULL;
}
+bool ID3::parseV1(const sp<DataSource> &source) {
+ const size_t V1_TAG_SIZE = 128;
+
+ off_t size;
+ if (source->getSize(&size) != OK || size < (off_t)V1_TAG_SIZE) {
+ return false;
+ }
+
+ mData = (uint8_t *)malloc(V1_TAG_SIZE);
+ if (source->readAt(size - V1_TAG_SIZE, mData, V1_TAG_SIZE)
+ != (ssize_t)V1_TAG_SIZE) {
+ free(mData);
+ mData = NULL;
+
+ return false;
+ }
+
+ if (memcmp("TAG", mData, 3)) {
+ free(mData);
+ mData = NULL;
+
+ return false;
+ }
+
+ mSize = V1_TAG_SIZE;
+ mFirstFrameOffset = 3;
+
+ if (mData[V1_TAG_SIZE - 3] != 0) {
+ mVersion = ID3_V1;
+ } else {
+ mVersion = ID3_V1_1;
+ }
+
+ return true;
+}
} // namespace android
diff --git a/media/libstagefright/id3/testid3.cpp b/media/libstagefright/id3/testid3.cpp
index 305b065..0741045 100644
--- a/media/libstagefright/id3/testid3.cpp
+++ b/media/libstagefright/id3/testid3.cpp
@@ -16,6 +16,8 @@
#include "../include/ID3.h"
+#include <sys/stat.h>
+
#include <ctype.h>
#include <dirent.h>
@@ -108,6 +110,12 @@
}
void scan(const char *path) {
+ struct stat st;
+ if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
+ scanFile(path);
+ return;
+ }
+
DIR *dir = opendir(path);
if (dir == NULL) {
diff --git a/media/libstagefright/include/ID3.h b/media/libstagefright/include/ID3.h
index 79931ac..da042a3 100644
--- a/media/libstagefright/include/ID3.h
+++ b/media/libstagefright/include/ID3.h
@@ -28,6 +28,8 @@
struct ID3 {
enum Version {
ID3_UNKNOWN,
+ ID3_V1,
+ ID3_V1_1,
ID3_V2_2,
ID3_V2_3
};
@@ -74,7 +76,8 @@
size_t mFirstFrameOffset;
Version mVersion;
- bool parse(const sp<DataSource> &source);
+ bool parseV1(const sp<DataSource> &source);
+ bool parseV2(const sp<DataSource> &source);
void removeUnsynchronization();
ID3(const ID3 &);
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index ce0b0d55aa..b559101 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -31,6 +31,8 @@
public:
OMX();
+ virtual bool livesLocally(pid_t pid);
+
virtual status_t listNodes(List<ComponentInfo> *list);
virtual status_t allocateNode(
diff --git a/media/libstagefright/include/SampleIterator.h b/media/libstagefright/include/SampleIterator.h
new file mode 100644
index 0000000..a5eaed9
--- /dev/null
+++ b/media/libstagefright/include/SampleIterator.h
@@ -0,0 +1,75 @@
+/*
+ * 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 <utils/Vector.h>
+
+namespace android {
+
+struct SampleTable;
+
+struct SampleIterator {
+ SampleIterator(SampleTable *table);
+
+ status_t seekTo(uint32_t sampleIndex);
+
+ uint32_t getChunkIndex() const { return mCurrentChunkIndex; }
+ uint32_t getDescIndex() const { return mChunkDesc; }
+ off_t getSampleOffset() const { return mCurrentSampleOffset; }
+ size_t getSampleSize() const { return mCurrentSampleSize; }
+ uint32_t getSampleTime() const { return mCurrentSampleTime; }
+
+ status_t getSampleSizeDirect(
+ uint32_t sampleIndex, size_t *size);
+
+private:
+ SampleTable *mTable;
+
+ bool mInitialized;
+
+ uint32_t mSampleToChunkIndex;
+ uint32_t mFirstChunk;
+ uint32_t mFirstChunkSampleIndex;
+ uint32_t mStopChunk;
+ uint32_t mStopChunkSampleIndex;
+ uint32_t mSamplesPerChunk;
+ uint32_t mChunkDesc;
+
+ uint32_t mCurrentChunkIndex;
+ off_t mCurrentChunkOffset;
+ Vector<size_t> mCurrentChunkSampleSizes;
+
+ uint32_t mTimeToSampleIndex;
+ uint32_t mTTSSampleIndex;
+ uint32_t mTTSSampleTime;
+ uint32_t mTTSCount;
+ uint32_t mTTSDuration;
+
+ uint32_t mCurrentSampleIndex;
+ off_t mCurrentSampleOffset;
+ size_t mCurrentSampleSize;
+ uint32_t mCurrentSampleTime;
+
+ void reset();
+ status_t findChunkRange(uint32_t sampleIndex);
+ status_t getChunkOffset(uint32_t chunk, off_t *offset);
+ status_t findSampleTime(uint32_t sampleIndex, uint32_t *time);
+
+ SampleIterator(const SampleIterator &);
+ SampleIterator &operator=(const SampleIterator &);
+};
+
+} // namespace android
+
diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h
index ead3431..533ce84 100644
--- a/media/libstagefright/include/SampleTable.h
+++ b/media/libstagefright/include/SampleTable.h
@@ -28,6 +28,7 @@
namespace android {
class DataSource;
+struct SampleIterator;
class SampleTable : public RefBase {
public:
@@ -50,21 +51,16 @@
////////////////////////////////////////////////////////////////////////////
uint32_t countChunkOffsets() const;
- status_t getChunkOffset(uint32_t chunk_index, off_t *offset);
-
- status_t getChunkForSample(
- uint32_t sample_index, uint32_t *chunk_index,
- uint32_t *chunk_relative_sample_index, uint32_t *desc_index);
uint32_t countSamples() const;
- status_t getSampleSize(uint32_t sample_index, size_t *sample_size);
-
- status_t getSampleOffsetAndSize(
- uint32_t sample_index, off_t *offset, size_t *size);
status_t getMaxSampleSize(size_t *size);
- status_t getDecodingTime(uint32_t sample_index, uint32_t *time);
+ status_t getMetaDataForSample(
+ uint32_t sampleIndex,
+ off_t *offset,
+ size_t *size,
+ uint32_t *decodingTime);
enum {
kSyncSample_Flag = 1
@@ -72,15 +68,17 @@
status_t findClosestSample(
uint32_t req_time, uint32_t *sample_index, uint32_t flags);
- status_t findClosestSyncSample(
- uint32_t start_sample_index, uint32_t *sample_index);
-
status_t findThumbnailSample(uint32_t *sample_index);
protected:
~SampleTable();
private:
+ static const uint32_t kChunkOffsetType32;
+ static const uint32_t kChunkOffsetType64;
+ static const uint32_t kSampleSizeType32;
+ static const uint32_t kSampleSizeTypeCompact;
+
sp<DataSource> mDataSource;
Mutex mLock;
@@ -102,6 +100,22 @@
off_t mSyncSampleOffset;
uint32_t mNumSyncSamples;
+ SampleIterator *mSampleIterator;
+
+ struct SampleToChunkEntry {
+ uint32_t startChunk;
+ uint32_t samplesPerChunk;
+ uint32_t chunkDesc;
+ };
+ SampleToChunkEntry *mSampleToChunkEntries;
+
+ friend struct SampleIterator;
+
+ status_t findClosestSyncSample_l(
+ uint32_t start_sample_index, uint32_t *sample_index);
+
+ status_t getSampleSize_l(uint32_t sample_index, size_t *sample_size);
+
SampleTable(const SampleTable &);
SampleTable &operator=(const SampleTable &);
};
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 8c3f252..2121321 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -135,50 +135,6 @@
////////////////////////////////////////////////////////////////////////////////
-class BufferMeta {
-public:
- BufferMeta(OMX *owner, const sp<IMemory> &mem, bool is_backup = false)
- : mOwner(owner),
- mMem(mem),
- mIsBackup(is_backup) {
- }
-
- BufferMeta(OMX *owner, size_t size)
- : mOwner(owner),
- mSize(size),
- mIsBackup(false) {
- }
-
- void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
- if (!mIsBackup) {
- return;
- }
-
- memcpy((OMX_U8 *)mMem->pointer() + header->nOffset,
- header->pBuffer + header->nOffset,
- header->nFilledLen);
- }
-
- void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
- if (!mIsBackup) {
- return;
- }
-
- memcpy(header->pBuffer + header->nOffset,
- (const OMX_U8 *)mMem->pointer() + header->nOffset,
- header->nFilledLen);
- }
-
-private:
- OMX *mOwner;
- sp<IMemory> mMem;
- size_t mSize;
- bool mIsBackup;
-
- BufferMeta(const BufferMeta &);
- BufferMeta &operator=(const BufferMeta &);
-};
-
OMX::OMX()
: mMaster(new OMXMaster),
mDispatcher(new CallbackDispatcher(this)),
@@ -208,6 +164,10 @@
instance->onObserverDied(mMaster);
}
+bool OMX::livesLocally(pid_t pid) {
+ return pid == getpid();
+}
+
status_t OMX::listNodes(List<ComponentInfo> *list) {
list->clear();
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 2e23899..5b45c1c 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -586,14 +586,14 @@
double r = uniform_rand();
- if (r < 0.5) {
+ if (i > 0 && r < 0.5) {
// 50% chance of just continuing to decode from last position.
requestedSeekTimeUs = -1;
LOGI("requesting linear read");
} else {
- if (r < 0.55) {
+ if (i > 0 && r < 0.55) {
// 5% chance of seeking beyond end of stream.
requestedSeekTimeUs = durationUs;
diff --git a/media/tests/omxjpegdecoder/Android.mk b/media/tests/omxjpegdecoder/Android.mk
index f679f19..b7c18bc 100644
--- a/media/tests/omxjpegdecoder/Android.mk
+++ b/media/tests/omxjpegdecoder/Android.mk
@@ -33,7 +33,8 @@
libskia \
libstagefright \
libbinder \
- libutils
+ libutils \
+ libjpeg
LOCAL_C_INCLUDES := \
$(JNI_H_INCLUDE) \
diff --git a/preloaded-classes b/preloaded-classes
index ec4d74c..90bbb37 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -753,10 +753,8 @@
java.math.Multiplication
java.net.ContentHandler
java.net.InetAddress
-java.net.InetAddress$CacheElement
java.net.InetAddress$WaitReachable
java.net.JarURLConnection
-java.net.NegativeCache
java.net.NetPermission
java.net.ProxySelectorImpl
java.net.Socket$ConnectLock
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 406897d..1c82c94 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -1203,12 +1203,10 @@
// Remove expired alerts
if (intentsToRemove != null) {
for (PendingIntent i : intentsToRemove) {
- mProximityAlerts.remove(i);
- ProximityAlert alert = mProximityAlerts.get(i);
+ ProximityAlert alert = mProximityAlerts.remove(i);
mProximitiesEntered.remove(alert);
}
}
-
}
// Note: this is called with the lock held.
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
new file mode 100644
index 0000000..97fa0cc
--- /dev/null
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+package com.android.server;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.INetworkManagementService;
+import android.os.Handler;
+import android.text.TextUtils;
+import android.util.Log;
+import java.util.ArrayList;
+
+import android.provider.Settings;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+
+import java.io.File;
+import java.io.FileReader;
+import java.lang.IllegalStateException;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * @hide
+ */
+class NetworkManagementService extends INetworkManagementService.Stub {
+
+ private static final String TAG = "NetworkManagmentService";
+
+ class NetdResponseCode {
+ public static final int InterfaceListResult = 110;
+ public static final int TetherInterfaceListResult = 111;
+ public static final int TetherDnsFwdTgtListResult = 112;
+
+ public static final int TetherStatusResult = 210;
+ public static final int IpFwdStatusResult = 211;
+ }
+
+ /**
+ * Binder context for this service
+ */
+ private Context mContext;
+
+ /**
+ * connector object for communicating with netd
+ */
+ private NativeDaemonConnector mConnector;
+
+ /**
+ * Constructs a new NetworkManagementService instance
+ *
+ * @param context Binder context for this service
+ */
+ private NetworkManagementService(Context context) {
+ mContext = context;
+
+ mConnector = new NativeDaemonConnector(
+ new NetdCallbackReceiver(), "netd", 10, "NetdConnector");
+ Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName());
+ thread.start();
+ }
+
+ //
+ // Netd Callback handling
+ //
+
+ class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
+ public void onDaemonConnected() {
+ new Thread() {
+ public void run() {
+ // XXX: Run some tests
+ }
+ }.start();
+ }
+ public boolean onEvent(int code, String raw, String[] cooked) {
+ return false;
+ }
+ }
+
+ //
+ // INetworkManagementService members
+ //
+
+ public String[] listInterfaces() throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+ ArrayList<String> rsp = mConnector.doCommand("list_interfaces");
+
+ String[] rdata = new String[rsp.size()];
+ int idx = 0;
+
+ for (String line : rsp) {
+ String []tok = line.split(" ");
+ int code = Integer.parseInt(tok[0]);
+ if (code == NetdResponseCode.InterfaceListResult) {
+ if (tok.length !=2) {
+ throw new IllegalStateException(
+ String.format("Malformatted list entry '%s'", line));
+ }
+ rdata[idx++] = tok[1];
+ } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) {
+ return rdata;
+ } else {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ }
+ throw new IllegalStateException("Got an empty response");
+ }
+
+ public void shutdown() {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.SHUTDOWN)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires SHUTDOWN permission");
+ }
+
+ Log.d(TAG, "Shutting down");
+ }
+
+ public boolean getIpForwardingEnabled() throws IllegalStateException{
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+ ArrayList<String> rsp = mConnector.doCommand("ipfwd status");
+
+ for (String line : rsp) {
+ String []tok = line.split(" ");
+ int code = Integer.parseInt(tok[0]);
+ if (code == NetdResponseCode.IpFwdStatusResult) {
+ // 211 Forwarding <enabled/disabled>
+ if (tok.length !=2) {
+ throw new IllegalStateException(
+ String.format("Malformatted list entry '%s'", line));
+ }
+ if (tok[2].equals("enabled"))
+ return true;
+ return false;
+ } else {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ }
+ throw new IllegalStateException("Got an empty response");
+ }
+
+ public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
+ }
+
+ public void startTethering(String dhcpRangeStart, String dhcpRangeEnd)
+ throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mConnector.doCommand(String.format("tether start %s %s", dhcpRangeStart, dhcpRangeEnd));
+ }
+
+ public void stopTethering() throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mConnector.doCommand("tether stop");
+ }
+
+ public boolean isTetheringStarted() throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+ ArrayList<String> rsp = mConnector.doCommand("tether status");
+
+ for (String line : rsp) {
+ String []tok = line.split(" ");
+ int code = Integer.parseInt(tok[0]);
+ if (code == NetdResponseCode.TetherStatusResult) {
+ // XXX: Tethering services <started/stopped> <TBD>...
+ if (tok[2].equals("started"))
+ return true;
+ return false;
+ } else {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ }
+ throw new IllegalStateException("Got an empty response");
+ }
+
+ public void tetherInterface(String iface) throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mConnector.doCommand("tether interface add " + iface);
+ }
+
+ public void untetherInterface(String iface) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mConnector.doCommand("tether interface remove " + iface);
+ }
+
+ public String[] listTetheredInterfaces() throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+ ArrayList<String> rsp = mConnector.doCommand("tether interface list");
+
+ String[] rdata = new String[rsp.size()];
+ int idx = 0;
+
+ for (String line : rsp) {
+ String []tok = line.split(" ");
+ int code = Integer.parseInt(tok[0]);
+ if (code == NetdResponseCode.TetherInterfaceListResult) {
+ if (tok.length !=2) {
+ throw new IllegalStateException(
+ String.format("Malformatted list entry '%s'", line));
+ }
+ rdata[idx++] = tok[1];
+ } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) {
+ return rdata;
+ } else {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ }
+ throw new IllegalStateException("Got an empty response");
+ }
+
+ public void setDnsForwarders(String[] dns) throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ try {
+ String cmd = "tether dns set ";
+ for (String s : dns) {
+ cmd += InetAddress.getByName(s).toString() + " ";
+ }
+ mConnector.doCommand(cmd);
+ } catch (UnknownHostException e) {
+ throw new IllegalStateException("Error resolving dns name", e);
+ }
+ }
+
+ public String[] getDnsForwarders() throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+ ArrayList<String> rsp = mConnector.doCommand("tether dns list");
+
+ String[] rdata = new String[rsp.size()];
+ int idx = 0;
+
+ for (String line : rsp) {
+ String []tok = line.split(" ");
+ int code = Integer.parseInt(tok[0]);
+ if (code == NetdResponseCode.TetherDnsFwdTgtListResult) {
+ if (tok.length !=2) {
+ throw new IllegalStateException(
+ String.format("Malformatted list entry '%s'", line));
+ }
+ rdata[idx++] = tok[1];
+ } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) {
+ return rdata;
+ } else {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ }
+ throw new IllegalStateException("Got an empty response");
+ }
+
+ public void enableNat(String internalInterface, String externalInterface)
+ throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mConnector.doCommand(
+ String.format("nat enable %s %s", internalInterface, externalInterface));
+ }
+
+ public void disableNat(String internalInterface, String externalInterface)
+ throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mConnector.doCommand(
+ String.format("nat disable %s %s", internalInterface, externalInterface));
+ }
+}
+