summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/java/android/media/MediaMetadataRetriever.java20
-rw-r--r--media/jni/android_media_MediaScanner.cpp258
-rwxr-xr-xmedia/jni/mediaeditor/Android.mk3
-rw-r--r--media/libmedia/MediaProfiles.cpp3
-rw-r--r--media/libstagefright/Android.mk57
-rw-r--r--media/libstagefright/AwesomePlayer.cpp11
-rw-r--r--media/libstagefright/DRMExtractor.cpp10
-rw-r--r--media/libstagefright/DataSource.cpp4
-rw-r--r--media/libstagefright/FileSource.cpp6
-rw-r--r--media/libstagefright/HTTPBase.cpp45
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp112
-rw-r--r--media/libstagefright/NuCachedSource2.cpp4
-rw-r--r--media/libstagefright/NuHTTPDataSource.cpp6
-rw-r--r--media/libstagefright/StagefrightMetadataRetriever.cpp49
-rw-r--r--media/libstagefright/chromium_http/Android.mk25
-rw-r--r--media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp327
-rw-r--r--media/libstagefright/chromium_http/support.cpp457
-rw-r--r--media/libstagefright/chromium_http/support.h159
-rw-r--r--media/libstagefright/codecs/mp3dec/MP3Decoder.cpp10
-rw-r--r--media/libstagefright/httplive/LiveSession.cpp13
-rw-r--r--media/libstagefright/include/AwesomePlayer.h6
-rw-r--r--media/libstagefright/include/ChromiumHTTPDataSource.h127
-rw-r--r--media/libstagefright/include/DRMExtractor.h2
-rw-r--r--media/libstagefright/include/HTTPBase.h53
-rw-r--r--media/libstagefright/include/LiveSession.h4
-rw-r--r--media/libstagefright/include/MPEG4Extractor.h6
-rw-r--r--media/libstagefright/include/NuCachedSource2.h4
-rw-r--r--media/libstagefright/include/NuHTTPDataSource.h20
-rw-r--r--media/tests/omxjpegdecoder/Android.mk5
29 files changed, 1656 insertions, 150 deletions
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 77e939e..13e1732 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -398,5 +398,25 @@ public class MediaMetadataRetriever
* The metadata key to retrieve the music album compilation status.
*/
public static final int METADATA_KEY_COMPILATION = 15;
+ /**
+ * If this key exists the media contains audio content.
+ */
+ public static final int METADATA_KEY_HAS_AUDIO = 16;
+ /**
+ * If this key exists the media contains video content.
+ */
+ public static final int METADATA_KEY_HAS_VIDEO = 17;
+ /**
+ * If the media contains video, this key retrieves its width.
+ */
+ public static final int METADATA_KEY_VIDEO_WIDTH = 18;
+ /**
+ * If the media contains video, this key retrieves its height.
+ */
+ public static final int METADATA_KEY_VIDEO_HEIGHT = 19;
+ /**
+ * This key retrieves the average bitrate (in bits/sec), if available.
+ */
+ public static final int METADATA_KEY_BITRATE = 20;
// Add more here...
}
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index a5176fa..8bbb997 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -1,4 +1,4 @@
-/* //device/libs/media_jni/MediaScanner.cpp
+/*
**
** Copyright 2007, The Android Open Source Project
**
@@ -15,36 +15,36 @@
** limitations under the License.
*/
-#define LOG_TAG "MediaScanner"
-#include "utils/Log.h"
-
-#include <media/mediascanner.h>
-#include <stdio.h>
-#include <assert.h>
-#include <limits.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <cutils/properties.h>
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaScannerJNI"
+#include <utils/Log.h>
#include <utils/threads.h>
+#include <media/mediascanner.h>
+#include <media/stagefright/StagefrightMediaScanner.h>
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
-#include <media/stagefright/StagefrightMediaScanner.h>
-
-// ----------------------------------------------------------------------------
-
using namespace android;
-// ----------------------------------------------------------------------------
struct fields_t {
jfieldID context;
};
static fields_t fields;
-// ----------------------------------------------------------------------------
+static const char* const kClassMediaScannerClient =
+ "android/media/MediaScannerClient";
+
+static const char* const kClassMediaScanner =
+ "android/media/MediaScanner";
+
+static const char* const kRunTimeException =
+ "java/lang/RuntimeException";
+
+static const char* const kIllegalArgumentException =
+ "java/lang/IllegalArgumentException";
class MyMediaScannerClient : public MediaScannerClient
{
@@ -56,33 +56,53 @@ public:
mHandleStringTagMethodID(0),
mSetMimeTypeMethodID(0)
{
- jclass mediaScannerClientInterface = env->FindClass("android/media/MediaScannerClient");
+ LOGV("MyMediaScannerClient constructor");
+ jclass mediaScannerClientInterface =
+ env->FindClass(kClassMediaScannerClient);
+
if (mediaScannerClientInterface == NULL) {
- fprintf(stderr, "android/media/MediaScannerClient not found\n");
- }
- else {
- mScanFileMethodID = env->GetMethodID(mediaScannerClientInterface, "scanFile",
- "(Ljava/lang/String;JJZ)V");
- mHandleStringTagMethodID = env->GetMethodID(mediaScannerClientInterface, "handleStringTag",
- "(Ljava/lang/String;Ljava/lang/String;)V");
- mSetMimeTypeMethodID = env->GetMethodID(mediaScannerClientInterface, "setMimeType",
- "(Ljava/lang/String;)V");
- mAddNoMediaFolderMethodID = env->GetMethodID(mediaScannerClientInterface, "addNoMediaFolder",
- "(Ljava/lang/String;)V");
+ LOGE("Class %s not found", kClassMediaScannerClient);
+ } else {
+ mScanFileMethodID = env->GetMethodID(
+ mediaScannerClientInterface,
+ "scanFile",
+ "(Ljava/lang/String;JJZ)V");
+
+ mHandleStringTagMethodID = env->GetMethodID(
+ mediaScannerClientInterface,
+ "handleStringTag",
+ "(Ljava/lang/String;Ljava/lang/String;)V");
+
+ mSetMimeTypeMethodID = env->GetMethodID(
+ mediaScannerClientInterface,
+ "setMimeType",
+ "(Ljava/lang/String;)V");
+
+ mAddNoMediaFolderMethodID = env->GetMethodID(
+ mediaScannerClientInterface,
+ "addNoMediaFolder",
+ "(Ljava/lang/String;)V");
}
}
-
+
virtual ~MyMediaScannerClient()
{
+ LOGV("MyMediaScannerClient destructor");
mEnv->DeleteGlobalRef(mClient);
}
-
- // returns true if it succeeded, false if an exception occured in the Java code
+
+ // Returns true if it succeeded, false if an exception occured
+ // in the Java code
virtual bool scanFile(const char* path, long long lastModified,
long long fileSize, bool isDirectory)
{
+ LOGV("scanFile: path(%s), time(%lld), size(%lld) and isDir(%d)",
+ path, lastModified, fileSize, isDirectory);
+
jstring pathStr;
- if ((pathStr = mEnv->NewStringUTF(path)) == NULL) return false;
+ if ((pathStr = mEnv->NewStringUTF(path)) == NULL) {
+ return false;
+ }
mEnv->CallVoidMethod(mClient, mScanFileMethodID, pathStr, lastModified,
fileSize, isDirectory);
@@ -91,25 +111,36 @@ public:
return (!mEnv->ExceptionCheck());
}
- // returns true if it succeeded, false if an exception occured in the Java code
+ // Returns true if it succeeded, false if an exception occured
+ // in the Java code
virtual bool handleStringTag(const char* name, const char* value)
{
+ LOGV("handleStringTag: name(%s) and value(%s)", name, value);
jstring nameStr, valueStr;
- if ((nameStr = mEnv->NewStringUTF(name)) == NULL) return false;
- if ((valueStr = mEnv->NewStringUTF(value)) == NULL) return false;
+ if ((nameStr = mEnv->NewStringUTF(name)) == NULL) {
+ return false;
+ }
+ if ((valueStr = mEnv->NewStringUTF(value)) == NULL) {
+ return false;
+ }
- mEnv->CallVoidMethod(mClient, mHandleStringTagMethodID, nameStr, valueStr);
+ mEnv->CallVoidMethod(
+ mClient, mHandleStringTagMethodID, nameStr, valueStr);
mEnv->DeleteLocalRef(nameStr);
mEnv->DeleteLocalRef(valueStr);
return (!mEnv->ExceptionCheck());
}
- // returns true if it succeeded, false if an exception occured in the Java code
+ // Returns true if it succeeded, false if an exception occured
+ // in the Java code
virtual bool setMimeType(const char* mimeType)
{
+ LOGV("setMimeType: %s", mimeType);
jstring mimeTypeStr;
- if ((mimeTypeStr = mEnv->NewStringUTF(mimeType)) == NULL) return false;
+ if ((mimeTypeStr = mEnv->NewStringUTF(mimeType)) == NULL) {
+ return false;
+ }
mEnv->CallVoidMethod(mClient, mSetMimeTypeMethodID, mimeTypeStr);
@@ -117,11 +148,15 @@ public:
return (!mEnv->ExceptionCheck());
}
- // returns true if it succeeded, false if an exception occured in the Java code
+ // Returns true if it succeeded, false if an exception occured
+ // in the Java code
virtual bool addNoMediaFolder(const char* path)
{
+ LOGV("addNoMediaFolder: path(%s)", path);
jstring pathStr;
- if ((pathStr = mEnv->NewStringUTF(path)) == NULL) return false;
+ if ((pathStr = mEnv->NewStringUTF(path)) == NULL) {
+ return false;
+ }
mEnv->CallVoidMethod(mClient, mAddNoMediaFolderMethodID, pathStr);
@@ -133,33 +168,35 @@ public:
private:
JNIEnv *mEnv;
jobject mClient;
- jmethodID mScanFileMethodID;
- jmethodID mHandleStringTagMethodID;
+ jmethodID mScanFileMethodID;
+ jmethodID mHandleStringTagMethodID;
jmethodID mSetMimeTypeMethodID;
jmethodID mAddNoMediaFolderMethodID;
};
-// ----------------------------------------------------------------------------
-
static bool ExceptionCheck(void* env)
{
+ LOGV("ExceptionCheck");
return ((JNIEnv *)env)->ExceptionCheck();
}
static void
-android_media_MediaScanner_processDirectory(JNIEnv *env, jobject thiz, jstring path, jobject client)
+android_media_MediaScanner_processDirectory(
+ JNIEnv *env, jobject thiz, jstring path, jobject client)
{
- MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context);
+ LOGV("processDirectory");
+ MediaScanner *mp =
+ (MediaScanner *)env->GetIntField(thiz, fields.context);
if (path == NULL) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ jniThrowException(env, kIllegalArgumentException, NULL);
return;
}
const char *pathStr = env->GetStringUTFChars(path, NULL);
if (pathStr == NULL) { // Out of memory
- jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+ jniThrowException(env, kRunTimeException, "Out of memory");
return;
}
@@ -169,24 +206,30 @@ android_media_MediaScanner_processDirectory(JNIEnv *env, jobject thiz, jstring p
}
static void
-android_media_MediaScanner_processFile(JNIEnv *env, jobject thiz, jstring path, jstring mimeType, jobject client)
+android_media_MediaScanner_processFile(
+ JNIEnv *env, jobject thiz, jstring path,
+ jstring mimeType, jobject client)
{
- MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context);
+ LOGV("processFile");
+ MediaScanner *mp =
+ (MediaScanner *)env->GetIntField(thiz, fields.context);
if (path == NULL) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ jniThrowException(env, kIllegalArgumentException, NULL);
return;
}
-
+
const char *pathStr = env->GetStringUTFChars(path, NULL);
if (pathStr == NULL) { // Out of memory
- jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+ jniThrowException(env, kRunTimeException, "Out of memory");
return;
}
- const char *mimeTypeStr = (mimeType ? env->GetStringUTFChars(mimeType, NULL) : NULL);
+
+ const char *mimeTypeStr =
+ (mimeType ? env->GetStringUTFChars(mimeType, NULL) : NULL);
if (mimeType && mimeTypeStr == NULL) { // Out of memory
env->ReleaseStringUTFChars(path, pathStr);
- jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+ jniThrowException(env, kRunTimeException, "Out of memory");
return;
}
@@ -199,17 +242,20 @@ android_media_MediaScanner_processFile(JNIEnv *env, jobject thiz, jstring path,
}
static void
-android_media_MediaScanner_setLocale(JNIEnv *env, jobject thiz, jstring locale)
+android_media_MediaScanner_setLocale(
+ JNIEnv *env, jobject thiz, jstring locale)
{
- MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context);
+ LOGV("setLocale");
+ MediaScanner *mp =
+ (MediaScanner *)env->GetIntField(thiz, fields.context);
if (locale == NULL) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ jniThrowException(env, kIllegalArgumentException, NULL);
return;
}
const char *localeStr = env->GetStringUTFChars(locale, NULL);
if (localeStr == NULL) { // Out of memory
- jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+ jniThrowException(env, kRunTimeException, "Out of memory");
return;
}
mp->setLocale(localeStr);
@@ -218,12 +264,15 @@ android_media_MediaScanner_setLocale(JNIEnv *env, jobject thiz, jstring locale)
}
static jbyteArray
-android_media_MediaScanner_extractAlbumArt(JNIEnv *env, jobject thiz, jobject fileDescriptor)
+android_media_MediaScanner_extractAlbumArt(
+ JNIEnv *env, jobject thiz, jobject fileDescriptor)
{
- MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context);
+ LOGV("extractAlbumArt");
+ MediaScanner *mp =
+ (MediaScanner *)env->GetIntField(thiz, fields.context);
if (fileDescriptor == NULL) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ jniThrowException(env, kIllegalArgumentException, NULL);
return NULL;
}
@@ -233,14 +282,14 @@ android_media_MediaScanner_extractAlbumArt(JNIEnv *env, jobject thiz, jobject fi
return NULL;
}
long len = *((long*)data);
-
+
jbyteArray array = env->NewByteArray(len);
if (array != NULL) {
jbyte* bytes = env->GetByteArrayElements(array, NULL);
memcpy(bytes, data + 4, len);
env->ReleaseByteArrayElements(array, bytes, 0);
}
-
+
done:
free(data);
// if NewByteArray() returned NULL, an out-of-memory
@@ -256,17 +305,18 @@ done:
static void
android_media_MediaScanner_native_init(JNIEnv *env)
{
- jclass clazz;
-
- clazz = env->FindClass("android/media/MediaScanner");
+ LOGV("native_init");
+ jclass clazz = env->FindClass(kClassMediaScanner);
if (clazz == NULL) {
- jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaScanner");
+ const char* err = "Can't find android/media/MediaScanner";
+ jniThrowException(env, kRunTimeException, err);
return;
}
fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
if (fields.context == NULL) {
- jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaScanner.mNativeContext");
+ const char* err = "Can't find MediaScanner.mNativeContext";
+ jniThrowException(env, kRunTimeException, err);
return;
}
}
@@ -274,10 +324,11 @@ android_media_MediaScanner_native_init(JNIEnv *env)
static void
android_media_MediaScanner_native_setup(JNIEnv *env, jobject thiz)
{
+ LOGV("native_setup");
MediaScanner *mp = new StagefrightMediaScanner;
if (mp == NULL) {
- jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+ jniThrowException(env, kRunTimeException, "Out of memory");
return;
}
@@ -287,38 +338,67 @@ android_media_MediaScanner_native_setup(JNIEnv *env, jobject thiz)
static void
android_media_MediaScanner_native_finalize(JNIEnv *env, jobject thiz)
{
- MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context);
-
- //printf("##### android_media_MediaScanner_native_finalize: ctx=0x%p\n", ctx);
+ LOGV("native_finalize");
+ MediaScanner *mp =
+ (MediaScanner *)env->GetIntField(thiz, fields.context);
- if (mp == 0)
+ if (mp == 0) {
return;
+ }
delete mp;
}
-// ----------------------------------------------------------------------------
-
static JNINativeMethod gMethods[] = {
- {"processDirectory", "(Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
- (void *)android_media_MediaScanner_processDirectory},
- {"processFile", "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
- (void *)android_media_MediaScanner_processFile},
- {"setLocale", "(Ljava/lang/String;)V", (void *)android_media_MediaScanner_setLocale},
- {"extractAlbumArt", "(Ljava/io/FileDescriptor;)[B", (void *)android_media_MediaScanner_extractAlbumArt},
- {"native_init", "()V", (void *)android_media_MediaScanner_native_init},
- {"native_setup", "()V", (void *)android_media_MediaScanner_native_setup},
- {"native_finalize", "()V", (void *)android_media_MediaScanner_native_finalize},
-};
+ {
+ "processDirectory",
+ "(Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
+ (void *)android_media_MediaScanner_processDirectory
+ },
+
+ {
+ "processFile",
+ "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
+ (void *)android_media_MediaScanner_processFile
+ },
-static const char* const kClassPathName = "android/media/MediaScanner";
+ {
+ "setLocale",
+ "(Ljava/lang/String;)V",
+ (void *)android_media_MediaScanner_setLocale
+ },
+
+ {
+ "extractAlbumArt",
+ "(Ljava/io/FileDescriptor;)[B",
+ (void *)android_media_MediaScanner_extractAlbumArt
+ },
+
+ {
+ "native_init",
+ "()V",
+ (void *)android_media_MediaScanner_native_init
+ },
+
+ {
+ "native_setup",
+ "()V",
+ (void *)android_media_MediaScanner_native_setup
+ },
+
+ {
+ "native_finalize",
+ "()V",
+ (void *)android_media_MediaScanner_native_finalize
+ },
+};
// This function only registers the native methods, and is called from
// JNI_OnLoad in android_media_MediaPlayer.cpp
int register_android_media_MediaScanner(JNIEnv *env)
{
return AndroidRuntime::registerNativeMethods(env,
- "android/media/MediaScanner", gMethods, NELEM(gMethods));
+ kClassMediaScanner, gMethods, NELEM(gMethods));
}
diff --git a/media/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk
index 6a7116c..f054deb 100755
--- a/media/jni/mediaeditor/Android.mk
+++ b/media/jni/mediaeditor/Android.mk
@@ -68,9 +68,6 @@ LOCAL_CFLAGS += \
-DUSE_STAGEFRIGHT_READERS \
-DUSE_STAGEFRIGHT_3GPP_READER
-
-LOCAL_LDFLAGS += -fuse-ld=bfd
-
LOCAL_STATIC_LIBRARIES := \
libvideoeditor_core \
libstagefright_color_conversion \
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index 7fb7aed..ca5bc38 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -721,6 +721,9 @@ MediaProfiles::createDefaultCamcorderProfiles(MediaProfiles *profiles)
createDefaultCamcorderTimeLapseHighProfiles(&highTimeLapseProfile, &highSpecificTimeLapseProfile);
profiles->mCamcorderProfiles.add(highTimeLapseProfile);
profiles->mCamcorderProfiles.add(highSpecificTimeLapseProfile);
+
+ // We only have the back-facing camera support by default.
+ profiles->mCameraIds.add(0);
}
/*static*/ void
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 88069e9..e445b74 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -19,6 +19,7 @@ LOCAL_SRC_FILES:= \
ESDS.cpp \
FileSource.cpp \
FLACExtractor.cpp \
+ HTTPBase.cpp \
HTTPStream.cpp \
JPEGSource.cpp \
MP3Extractor.cpp \
@@ -75,7 +76,7 @@ LOCAL_SHARED_LIBRARIES := \
libdrmframework \
libcrypto \
libssl \
- libgui
+ libgui \
LOCAL_STATIC_LIBRARIES := \
libstagefright_color_conversion \
@@ -101,6 +102,60 @@ LOCAL_STATIC_LIBRARIES := \
libstagefright_g711dec \
libFLAC \
+################################################################################
+
+# The following was shamelessly copied from external/webkit/Android.mk and
+# currently must follow the same logic to determine how webkit was built and
+# if it's safe to link against libchromium.net
+
+# V8 also requires an ARMv7 CPU, and since we must use jsc, we cannot
+# use the Chrome http stack either.
+ifneq ($(strip $(ARCH_ARM_HAVE_ARMV7A)),true)
+ USE_ALT_HTTP := true
+endif
+
+# See if the user has specified a stack they want to use
+HTTP_STACK = $(HTTP)
+# We default to the Chrome HTTP stack.
+DEFAULT_HTTP = chrome
+ALT_HTTP = android
+
+ifneq ($(HTTP_STACK),chrome)
+ ifneq ($(HTTP_STACK),android)
+ # No HTTP stack is specified, pickup the one we want as default.
+ ifeq ($(USE_ALT_HTTP),true)
+ HTTP_STACK = $(ALT_HTTP)
+ else
+ HTTP_STACK = $(DEFAULT_HTTP)
+ endif
+ endif
+endif
+
+ifeq ($(HTTP_STACK),chrome)
+
+LOCAL_SHARED_LIBRARIES += \
+ liblog \
+ libicuuc \
+ libicui18n \
+ libz \
+ libdl \
+
+LOCAL_STATIC_LIBRARIES += \
+ libstagefright_chromium_http \
+ libchromium_net \
+ libwebcore \
+
+ifneq ($(TARGET_SIMULATOR),true)
+LOCAL_SHARED_LIBRARIES += libstlport
+include external/stlport/libstlport.mk
+endif
+
+LOCAL_CPPFLAGS += -DCHROMIUM_AVAILABLE=1
+
+endif # ifeq ($(HTTP_STACK),chrome)
+
+################################################################################
+
LOCAL_SHARED_LIBRARIES += \
libstagefright_amrnb_common \
libstagefright_enc_common \
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 5734c7e..0de1988 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -304,7 +304,7 @@ status_t AwesomePlayer::setDataSource_l(
return UNKNOWN_ERROR;
}
- dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
+ dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
if (mDecryptHandle != NULL) {
CHECK(mDrmManagerClient);
if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
@@ -1611,8 +1611,10 @@ status_t AwesomePlayer::finishSetDataSource_l() {
if (!strncasecmp("http://", mUri.string(), 7)
|| !strncasecmp("https://", mUri.string(), 8)) {
- mConnectingDataSource = new NuHTTPDataSource(
- (mFlags & INCOGNITO) ? NuHTTPDataSource::kFlagIncognito : 0);
+ mConnectingDataSource = HTTPBase::Create(
+ (mFlags & INCOGNITO)
+ ? HTTPBase::kFlagIncognito
+ : 0);
mLock.unlock();
status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
@@ -1701,7 +1703,8 @@ status_t AwesomePlayer::finishSetDataSource_l() {
return UNKNOWN_ERROR;
}
- dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
+ dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
+
if (mDecryptHandle != NULL) {
CHECK(mDrmManagerClient);
if (RightsStatus::RIGHTS_VALID == mDecryptHandle->status) {
diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp
index 2809df5..c4ed516 100644
--- a/media/libstagefright/DRMExtractor.cpp
+++ b/media/libstagefright/DRMExtractor.cpp
@@ -41,7 +41,7 @@ namespace android {
class DRMSource : public MediaSource {
public:
DRMSource(const sp<MediaSource> &mediaSource,
- DecryptHandle *decryptHandle,
+ const sp<DecryptHandle> &decryptHandle,
DrmManagerClient *managerClient,
int32_t trackId, DrmBuffer *ipmpBox);
@@ -56,7 +56,7 @@ protected:
private:
sp<MediaSource> mOriginalMediaSource;
- DecryptHandle* mDecryptHandle;
+ sp<DecryptHandle> mDecryptHandle;
DrmManagerClient* mDrmManagerClient;
size_t mTrackId;
mutable Mutex mDRMLock;
@@ -70,7 +70,7 @@ private:
////////////////////////////////////////////////////////////////////////////////
DRMSource::DRMSource(const sp<MediaSource> &mediaSource,
- DecryptHandle *decryptHandle,
+ const sp<DecryptHandle> &decryptHandle,
DrmManagerClient *managerClient,
int32_t trackId, DrmBuffer *ipmpBox)
: mOriginalMediaSource(mediaSource),
@@ -245,7 +245,7 @@ DRMExtractor::DRMExtractor(const sp<DataSource> &source, const char* mime)
mOriginalExtractor->setDrmFlag(true);
mOriginalExtractor->getMetaData()->setInt32(kKeyIsDRM, 1);
- source->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
+ source->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
}
DRMExtractor::~DRMExtractor() {
@@ -281,7 +281,7 @@ sp<MetaData> DRMExtractor::getMetaData() {
bool SniffDRM(
const sp<DataSource> &source, String8 *mimeType, float *confidence,
sp<AMessage> *) {
- DecryptHandle *decryptHandle = source->DrmInitialization();
+ sp<DecryptHandle> decryptHandle = source->DrmInitialization();
if (decryptHandle != NULL) {
if (decryptHandle->decryptApiType == DecryptApiType::CONTAINER_BASED) {
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 3b38208..b5c51f4 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -21,7 +21,7 @@
#include "include/OggExtractor.h"
#include "include/MPEG2TSExtractor.h"
#include "include/NuCachedSource2.h"
-#include "include/NuHTTPDataSource.h"
+#include "include/HTTPBase.h"
#include "include/DRMExtractor.h"
#include "include/FLACExtractor.h"
#include "include/AACExtractor.h"
@@ -127,7 +127,7 @@ sp<DataSource> DataSource::CreateFromURI(
source = new FileSource(uri + 7);
} else if (!strncasecmp("http://", uri, 7)
|| !strncasecmp("https://", uri, 8)) {
- sp<NuHTTPDataSource> httpSource = new NuHTTPDataSource;
+ sp<HTTPBase> httpSource = HTTPBase::Create();
if (httpSource->connect(uri, headers) != OK) {
return NULL;
}
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index 02a78c9..f2f3500 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -125,7 +125,7 @@ status_t FileSource::getSize(off64_t *size) {
return OK;
}
-DecryptHandle* FileSource::DrmInitialization() {
+sp<DecryptHandle> FileSource::DrmInitialization() {
if (mDrmManagerClient == NULL) {
mDrmManagerClient = new DrmManagerClient();
}
@@ -147,8 +147,8 @@ DecryptHandle* FileSource::DrmInitialization() {
return mDecryptHandle;
}
-void FileSource::getDrmInfo(DecryptHandle **handle, DrmManagerClient **client) {
- *handle = mDecryptHandle;
+void FileSource::getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client) {
+ handle = mDecryptHandle;
*client = mDrmManagerClient;
}
diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp
new file mode 100644
index 0000000..58b17a7
--- /dev/null
+++ b/media/libstagefright/HTTPBase.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/HTTPBase.h"
+
+#if CHROMIUM_AVAILABLE
+#include "include/ChromiumHTTPDataSource.h"
+#endif
+
+#include "include/NuHTTPDataSource.h"
+
+#include <cutils/properties.h>
+
+namespace android {
+
+HTTPBase::HTTPBase() {}
+
+// static
+sp<HTTPBase> HTTPBase::Create(uint32_t flags) {
+#if CHROMIUM_AVAILABLE
+ char value[PROPERTY_VALUE_MAX];
+ if (!property_get("media.stagefright.use-chromium", value, NULL)
+ || (strcasecmp("false", value) && strcmp("0", value))) {
+ return new ChromiumHTTPDataSource(flags);
+ } else
+#endif
+ {
+ return new NuHTTPDataSource(flags);
+ }
+}
+
+} // namespace android
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 7b96d01..1ca2d6d 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -262,7 +262,7 @@ static const char *FourCC2MIME(uint32_t fourcc) {
MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source)
: mDataSource(source),
- mHaveMetadata(false),
+ mInitCheck(NO_INIT),
mHasVideo(false),
mFirstTrack(NULL),
mLastTrack(NULL),
@@ -361,8 +361,8 @@ sp<MetaData> MPEG4Extractor::getTrackMetaData(
}
status_t MPEG4Extractor::readMetaData() {
- if (mHaveMetadata) {
- return OK;
+ if (mInitCheck != NO_INIT) {
+ return mInitCheck;
}
off64_t offset = 0;
@@ -370,17 +370,20 @@ status_t MPEG4Extractor::readMetaData() {
while ((err = parseChunk(&offset, 0)) == OK) {
}
- if (mHaveMetadata) {
+ if (mInitCheck == OK) {
if (mHasVideo) {
mFileMetaData->setCString(kKeyMIMEType, "video/mp4");
} else {
mFileMetaData->setCString(kKeyMIMEType, "audio/mp4");
}
- return OK;
+ mInitCheck = verifyIfStreamable();
+ } else {
+ mInitCheck = err;
}
- return err;
+ CHECK_NE(err, (status_t)NO_INIT);
+ return mInitCheck;
}
void MPEG4Extractor::setDrmFlag(bool flag) {
@@ -755,7 +758,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return err;
}
} else if (chunk_type == FOURCC('m', 'o', 'o', 'v')) {
- mHaveMetadata = true;
+ mInitCheck = OK;
if (!mIsDrm) {
return UNKNOWN_ERROR; // Return a dummy error.
@@ -2077,6 +2080,101 @@ status_t MPEG4Source::read(
}
}
+MPEG4Extractor::Track *MPEG4Extractor::findTrackByMimePrefix(
+ const char *mimePrefix) {
+ for (Track *track = mFirstTrack; track != NULL; track = track->next) {
+ const char *mime;
+ if (track->meta != NULL
+ && track->meta->findCString(kKeyMIMEType, &mime)
+ && !strncasecmp(mime, mimePrefix, strlen(mimePrefix))) {
+ return track;
+ }
+ }
+
+ return NULL;
+}
+
+status_t MPEG4Extractor::verifyIfStreamable() {
+ if (!(mDataSource->flags() & DataSource::kIsCachingDataSource)) {
+ return OK;
+ }
+
+ Track *audio = findTrackByMimePrefix("audio/");
+ Track *video = findTrackByMimePrefix("video/");
+
+ if (audio == NULL || video == NULL) {
+ return OK;
+ }
+
+ sp<SampleTable> audioSamples = audio->sampleTable;
+ sp<SampleTable> videoSamples = video->sampleTable;
+
+ off64_t maxOffsetDiff = 0;
+ int64_t maxOffsetTimeUs = -1;
+
+ for (uint32_t i = 0; i < videoSamples->countSamples(); ++i) {
+ off64_t videoOffset;
+ uint32_t videoTime;
+ bool isSync;
+ CHECK_EQ((status_t)OK, videoSamples->getMetaDataForSample(
+ i, &videoOffset, NULL, &videoTime, &isSync));
+
+ int64_t videoTimeUs = (int64_t)(videoTime * 1E6 / video->timescale);
+
+ uint32_t reqAudioTime = (videoTimeUs * audio->timescale) / 1000000;
+ uint32_t j;
+ if (audioSamples->findSampleAtTime(
+ reqAudioTime, &j, SampleTable::kFlagClosest) != OK) {
+ continue;
+ }
+
+ off64_t audioOffset;
+ uint32_t audioTime;
+ CHECK_EQ((status_t)OK, audioSamples->getMetaDataForSample(
+ j, &audioOffset, NULL, &audioTime));
+
+ int64_t audioTimeUs = (int64_t)(audioTime * 1E6 / audio->timescale);
+
+ off64_t offsetDiff = videoOffset - audioOffset;
+ if (offsetDiff < 0) {
+ offsetDiff = -offsetDiff;
+ }
+
+#if 0
+ printf("%s%d/%d videoTime %.2f secs audioTime %.2f secs "
+ "videoOffset %lld audioOffset %lld offsetDiff %lld\n",
+ isSync ? "*" : " ",
+ i,
+ j,
+ videoTimeUs / 1E6,
+ audioTimeUs / 1E6,
+ videoOffset,
+ audioOffset,
+ offsetDiff);
+#endif
+
+ if (offsetDiff > maxOffsetDiff) {
+ maxOffsetDiff = offsetDiff;
+ maxOffsetTimeUs = videoTimeUs;
+ }
+ }
+
+#if 0
+ printf("max offset diff: %lld at video time: %.2f secs\n",
+ maxOffsetDiff, maxOffsetTimeUs / 1E6);
+#endif
+
+ if (maxOffsetDiff < 1024 * 1024) {
+ return OK;
+ }
+
+ LOGE("This content is not streamable, "
+ "max offset diff: %lld at video time: %.2f secs",
+ maxOffsetDiff, maxOffsetTimeUs / 1E6);
+
+ return ERROR_UNSUPPORTED;
+}
+
static bool LegacySniffMPEG4(
const sp<DataSource> &source, String8 *mimeType, float *confidence) {
uint8_t header[8];
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index c7b99b9..7c65612 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -477,11 +477,11 @@ void NuCachedSource2::resumeFetchingIfNecessary() {
restartPrefetcherIfNecessary_l(true /* ignore low water threshold */);
}
-DecryptHandle* NuCachedSource2::DrmInitialization() {
+sp<DecryptHandle> NuCachedSource2::DrmInitialization() {
return mSource->DrmInitialization();
}
-void NuCachedSource2::getDrmInfo(DecryptHandle **handle, DrmManagerClient **client) {
+void NuCachedSource2::getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client) {
mSource->getDrmInfo(handle, client);
}
diff --git a/media/libstagefright/NuHTTPDataSource.cpp b/media/libstagefright/NuHTTPDataSource.cpp
index b24343f..73daf12 100644
--- a/media/libstagefright/NuHTTPDataSource.cpp
+++ b/media/libstagefright/NuHTTPDataSource.cpp
@@ -530,7 +530,7 @@ void NuHTTPDataSource::addBandwidthMeasurement_l(
}
}
-DecryptHandle* NuHTTPDataSource::DrmInitialization() {
+sp<DecryptHandle> NuHTTPDataSource::DrmInitialization() {
if (mDrmManagerClient == NULL) {
mDrmManagerClient = new DrmManagerClient();
}
@@ -554,8 +554,8 @@ DecryptHandle* NuHTTPDataSource::DrmInitialization() {
return mDecryptHandle;
}
-void NuHTTPDataSource::getDrmInfo(DecryptHandle **handle, DrmManagerClient **client) {
- *handle = mDecryptHandle;
+void NuHTTPDataSource::getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client) {
+ handle = mDecryptHandle;
*client = mDrmManagerClient;
}
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index ea3b801..c371cd0 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -411,6 +411,12 @@ void StagefrightMetadataRetriever::parseMetaData() {
mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp));
+ bool hasAudio = false;
+ bool hasVideo = false;
+ int32_t videoWidth = -1;
+ int32_t videoHeight = -1;
+ int32_t audioBitrate = -1;
+
// The overall duration is the duration of the longest track.
int64_t maxDurationUs = 0;
for (size_t i = 0; i < numTracks; ++i) {
@@ -422,12 +428,55 @@ void StagefrightMetadataRetriever::parseMetaData() {
maxDurationUs = durationUs;
}
}
+
+ const char *mime;
+ if (trackMeta->findCString(kKeyMIMEType, &mime)) {
+ if (!hasAudio && !strncasecmp("audio/", mime, 6)) {
+ hasAudio = true;
+
+ if (!trackMeta->findInt32(kKeyBitRate, &audioBitrate)) {
+ audioBitrate = -1;
+ }
+ } else if (!hasVideo && !strncasecmp("video/", mime, 6)) {
+ hasVideo = true;
+
+ CHECK(trackMeta->findInt32(kKeyWidth, &videoWidth));
+ CHECK(trackMeta->findInt32(kKeyHeight, &videoHeight));
+ }
+ }
}
// The duration value is a string representing the duration in ms.
sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000);
mMetaData.add(METADATA_KEY_DURATION, String8(tmp));
+ if (hasAudio) {
+ mMetaData.add(METADATA_KEY_HAS_AUDIO, String8("yes"));
+ }
+
+ if (hasVideo) {
+ mMetaData.add(METADATA_KEY_HAS_VIDEO, String8("yes"));
+
+ sprintf(tmp, "%d", videoWidth);
+ mMetaData.add(METADATA_KEY_VIDEO_WIDTH, String8(tmp));
+
+ sprintf(tmp, "%d", videoHeight);
+ mMetaData.add(METADATA_KEY_VIDEO_HEIGHT, String8(tmp));
+ }
+
+ if (numTracks == 1 && hasAudio && audioBitrate >= 0) {
+ sprintf(tmp, "%ld", audioBitrate);
+ mMetaData.add(METADATA_KEY_BITRATE, String8(tmp));
+ } else {
+ off64_t sourceSize;
+ if (mSource->getSize(&sourceSize) == OK) {
+ int64_t avgBitRate = (int64_t)(sourceSize * 8E6 / maxDurationUs);
+
+ sprintf(tmp, "%lld", avgBitRate);
+ mMetaData.add(METADATA_KEY_BITRATE, String8(tmp));
+ }
+ }
+
if (numTracks == 1) {
const char *fileMIME;
CHECK(meta->findCString(kKeyMIMEType, &fileMIME));
diff --git a/media/libstagefright/chromium_http/Android.mk b/media/libstagefright/chromium_http/Android.mk
new file mode 100644
index 0000000..80b2478
--- /dev/null
+++ b/media/libstagefright/chromium_http/Android.mk
@@ -0,0 +1,25 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ ChromiumHTTPDataSource.cpp \
+ support.cpp \
+
+LOCAL_C_INCLUDES:= \
+ $(JNI_H_INCLUDE) \
+ frameworks/base/media/libstagefright \
+ $(TOP)/frameworks/base/include/media/stagefright/openmax \
+ external/chromium \
+ external/chromium/android
+
+LOCAL_CFLAGS += -Wno-multichar
+
+ifneq ($(TARGET_SIMULATOR),true)
+LOCAL_SHARED_LIBRARIES += libstlport
+include external/stlport/libstlport.mk
+endif
+
+LOCAL_MODULE:= libstagefright_chromium_http
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
new file mode 100644
index 0000000..949a5e4
--- /dev/null
+++ b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ChromiumHTTPDataSource"
+#include <media/stagefright/foundation/ADebug.h>
+
+#include "include/ChromiumHTTPDataSource.h"
+
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/MediaErrors.h>
+
+#include "support.h"
+
+namespace android {
+
+ChromiumHTTPDataSource::ChromiumHTTPDataSource(uint32_t flags)
+ : mFlags(flags),
+ mState(DISCONNECTED),
+ mDelegate(new SfDelegate),
+ mCurrentOffset(0),
+ mIOResult(OK),
+ mContentSize(-1),
+ mNumBandwidthHistoryItems(0),
+ mTotalTransferTimeUs(0),
+ mTotalTransferBytes(0),
+ mDecryptHandle(NULL),
+ mDrmManagerClient(NULL) {
+ mDelegate->setOwner(this);
+}
+
+ChromiumHTTPDataSource::~ChromiumHTTPDataSource() {
+ disconnect();
+
+ delete mDelegate;
+ mDelegate = NULL;
+
+ if (mDrmManagerClient != NULL) {
+ delete mDrmManagerClient;
+ mDrmManagerClient = NULL;
+ }
+}
+
+status_t ChromiumHTTPDataSource::connect(
+ const char *uri,
+ const KeyedVector<String8, String8> *headers,
+ off64_t offset) {
+ Mutex::Autolock autoLock(mLock);
+
+ return connect_l(uri, headers, offset);
+}
+
+status_t ChromiumHTTPDataSource::connect_l(
+ const char *uri,
+ const KeyedVector<String8, String8> *headers,
+ off64_t offset) {
+ if (mState != DISCONNECTED) {
+ disconnect_l();
+ }
+
+ if (!(mFlags & kFlagIncognito)) {
+ LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "connect to %s @%lld", uri, offset);
+ } else {
+ LOG_PRI(ANDROID_LOG_INFO, LOG_TAG,
+ "connect to <URL suppressed> @%lld", offset);
+ }
+
+ mURI = uri;
+
+ if (headers != NULL) {
+ mHeaders = *headers;
+ } else {
+ mHeaders.clear();
+ }
+
+ mState = CONNECTING;
+ mContentSize = -1;
+ mCurrentOffset = offset;
+
+ mDelegate->initiateConnection(mURI.c_str(), &mHeaders, offset);
+
+ while (mState == CONNECTING) {
+ mCondition.wait(mLock);
+ }
+
+ return mState == CONNECTED ? OK : mIOResult;
+}
+
+void ChromiumHTTPDataSource::onConnectionEstablished(int64_t contentSize) {
+ Mutex::Autolock autoLock(mLock);
+ mState = CONNECTED;
+ mContentSize = (contentSize < 0) ? -1 : contentSize + mCurrentOffset;
+ mCondition.broadcast();
+}
+
+void ChromiumHTTPDataSource::onConnectionFailed(status_t err) {
+ Mutex::Autolock autoLock(mLock);
+ mState = DISCONNECTED;
+ mCondition.broadcast();
+
+ mURI.clear();
+
+ mIOResult = err;
+
+ clearDRMState_l();
+}
+
+void ChromiumHTTPDataSource::disconnect() {
+ Mutex::Autolock autoLock(mLock);
+ disconnect_l();
+}
+
+void ChromiumHTTPDataSource::disconnect_l() {
+ if (mState == DISCONNECTED) {
+ return;
+ }
+
+ mState = DISCONNECTING;
+ mIOResult = -EINTR;
+
+ mDelegate->initiateDisconnect();
+
+ while (mState == DISCONNECTING) {
+ mCondition.wait(mLock);
+ }
+
+ CHECK_EQ((int)mState, (int)DISCONNECTED);
+}
+
+status_t ChromiumHTTPDataSource::initCheck() const {
+ Mutex::Autolock autoLock(mLock);
+
+ return mState == CONNECTED ? OK : NO_INIT;
+}
+
+ssize_t ChromiumHTTPDataSource::readAt(off64_t offset, void *data, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mState != CONNECTED) {
+ return ERROR_NOT_CONNECTED;
+ }
+
+ if (offset != mCurrentOffset) {
+ AString tmp = mURI;
+ KeyedVector<String8, String8> tmpHeaders = mHeaders;
+
+ disconnect_l();
+
+ status_t err = connect_l(tmp.c_str(), &tmpHeaders, offset);
+
+ if (err != OK) {
+ return err;
+ }
+ }
+
+ mState = READING;
+
+ int64_t startTimeUs = ALooper::GetNowUs();
+
+ mDelegate->initiateRead(data, size);
+
+ while (mState == READING) {
+ mCondition.wait(mLock);
+ }
+
+ if (mIOResult < OK) {
+ return mIOResult;
+ }
+
+ if (mState == CONNECTED) {
+ int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
+
+ // The read operation was successful, mIOResult contains
+ // the number of bytes read.
+ addBandwidthMeasurement_l(mIOResult, delayUs);
+
+ mCurrentOffset += mIOResult;
+ return mIOResult;
+ }
+
+ return ERROR_IO;
+}
+
+void ChromiumHTTPDataSource::onReadCompleted(ssize_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ mIOResult = size;
+
+ if (mState == READING) {
+ mState = CONNECTED;
+ mCondition.broadcast();
+ }
+}
+
+status_t ChromiumHTTPDataSource::getSize(off64_t *size) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mContentSize < 0) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ *size = mContentSize;
+
+ return OK;
+}
+
+uint32_t ChromiumHTTPDataSource::flags() {
+ return kWantsPrefetching;
+}
+
+// static
+void ChromiumHTTPDataSource::InitiateRead(
+ ChromiumHTTPDataSource *me, void *data, size_t size) {
+ me->initiateRead(data, size);
+}
+
+void ChromiumHTTPDataSource::initiateRead(void *data, size_t size) {
+ mDelegate->initiateRead(data, size);
+}
+
+void ChromiumHTTPDataSource::onDisconnectComplete() {
+ Mutex::Autolock autoLock(mLock);
+ CHECK_EQ((int)mState, (int)DISCONNECTING);
+
+ mState = DISCONNECTED;
+ mURI.clear();
+
+ mCondition.broadcast();
+
+ clearDRMState_l();
+}
+
+void ChromiumHTTPDataSource::addBandwidthMeasurement_l(
+ size_t numBytes, int64_t delayUs) {
+ BandwidthEntry entry;
+ entry.mDelayUs = delayUs;
+ entry.mNumBytes = numBytes;
+ mTotalTransferTimeUs += delayUs;
+ mTotalTransferBytes += numBytes;
+
+ mBandwidthHistory.push_back(entry);
+ if (++mNumBandwidthHistoryItems > 100) {
+ BandwidthEntry *entry = &*mBandwidthHistory.begin();
+ mTotalTransferTimeUs -= entry->mDelayUs;
+ mTotalTransferBytes -= entry->mNumBytes;
+ mBandwidthHistory.erase(mBandwidthHistory.begin());
+ --mNumBandwidthHistoryItems;
+ }
+}
+
+bool ChromiumHTTPDataSource::estimateBandwidth(int32_t *bandwidth_bps) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mNumBandwidthHistoryItems < 2) {
+ return false;
+ }
+
+ *bandwidth_bps = ((double)mTotalTransferBytes * 8E6 / mTotalTransferTimeUs);
+
+ return true;
+}
+
+sp<DecryptHandle> ChromiumHTTPDataSource::DrmInitialization() {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mDrmManagerClient == NULL) {
+ mDrmManagerClient = new DrmManagerClient();
+ }
+
+ if (mDrmManagerClient == NULL) {
+ return NULL;
+ }
+
+ if (mDecryptHandle == NULL) {
+ /* Note if redirect occurs, mUri is the redirect uri instead of the
+ * original one
+ */
+ mDecryptHandle = mDrmManagerClient->openDecryptSession(
+ String8(mURI.c_str()));
+ }
+
+ if (mDecryptHandle == NULL) {
+ delete mDrmManagerClient;
+ mDrmManagerClient = NULL;
+ }
+
+ return mDecryptHandle;
+}
+
+void ChromiumHTTPDataSource::getDrmInfo(
+ sp<DecryptHandle> &handle, DrmManagerClient **client) {
+ Mutex::Autolock autoLock(mLock);
+
+ handle = mDecryptHandle;
+ *client = mDrmManagerClient;
+}
+
+String8 ChromiumHTTPDataSource::getUri() {
+ Mutex::Autolock autoLock(mLock);
+
+ return String8(mURI.c_str());
+}
+
+void ChromiumHTTPDataSource::clearDRMState_l() {
+ if (mDecryptHandle != NULL) {
+ // To release mDecryptHandle
+ CHECK(mDrmManagerClient);
+ mDrmManagerClient->closeDecryptSession(mDecryptHandle);
+ mDecryptHandle = NULL;
+ }
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp
new file mode 100644
index 0000000..7ac56e8
--- /dev/null
+++ b/media/libstagefright/chromium_http/support.cpp
@@ -0,0 +1,457 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ChromiumHTTPDataSourceSupport"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/AString.h>
+
+#include "support.h"
+
+#include "android/net/android_network_library_impl.h"
+#include "base/thread.h"
+#include "net/base/host_resolver.h"
+#include "net/base/ssl_config_service.h"
+#include "net/http/http_auth_handler_factory.h"
+#include "net/http/http_cache.h"
+#include "net/proxy/proxy_config_service_android.h"
+
+#include "include/ChromiumHTTPDataSource.h"
+
+#include <cutils/properties.h>
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+static Mutex gNetworkThreadLock;
+static base::Thread *gNetworkThread = NULL;
+static scoped_refptr<URLRequestContext> gReqContext;
+
+static void InitializeNetworkThreadIfNecessary() {
+ Mutex::Autolock autoLock(gNetworkThreadLock);
+ if (gNetworkThread == NULL) {
+ gNetworkThread = new base::Thread("network");
+ base::Thread::Options options;
+ options.message_loop_type = MessageLoop::TYPE_IO;
+ CHECK(gNetworkThread->StartWithOptions(options));
+
+ gReqContext = new SfRequestContext;
+
+ net::AndroidNetworkLibrary::RegisterSharedInstance(
+ new SfNetworkLibrary);
+ }
+}
+
+static void MY_LOGI(const char *s) {
+ LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "%s", s);
+}
+
+static void MY_LOGV(const char *s) {
+#if !defined(LOG_NDEBUG) || LOG_NDEBUG == 0
+ LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG, "%s", s);
+#endif
+}
+
+SfNetLog::SfNetLog()
+ : mNextID(1) {
+}
+
+void SfNetLog::AddEntry(
+ EventType type,
+ const base::TimeTicks &time,
+ const Source &source,
+ EventPhase phase,
+ EventParameters *params) {
+#if 0
+ MY_LOGI(StringPrintf(
+ "AddEntry time=%s type=%s source=%s phase=%s\n",
+ TickCountToString(time).c_str(),
+ EventTypeToString(type),
+ SourceTypeToString(source.type),
+ EventPhaseToString(phase)).c_str());
+#endif
+}
+
+uint32 SfNetLog::NextID() {
+ return mNextID++;
+}
+
+net::NetLog::LogLevel SfNetLog::GetLogLevel() const {
+ return LOG_ALL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+SfRequestContext::SfRequestContext() {
+ AString ua;
+ ua.append("stagefright/1.2 (Linux;Android ");
+
+#if (PROPERTY_VALUE_MAX < 8)
+#error "PROPERTY_VALUE_MAX must be at least 8"
+#endif
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.build.version.release", value, "Unknown");
+ ua.append(value);
+ ua.append(")");
+
+ mUserAgent = ua.c_str();
+
+ net_log_ = new SfNetLog;
+
+ host_resolver_ =
+ net::CreateSystemHostResolver(
+ net::HostResolver::kDefaultParallelism,
+ NULL /* resolver_proc */,
+ net_log_);
+
+ ssl_config_service_ =
+ net::SSLConfigService::CreateSystemSSLConfigService();
+
+ proxy_service_ = net::ProxyService::CreateWithoutProxyResolver(
+ new net::ProxyConfigServiceAndroid, net_log_);
+
+ http_transaction_factory_ = new net::HttpCache(
+ host_resolver_,
+ dnsrr_resolver_,
+ dns_cert_checker_.get(),
+ proxy_service_.get(),
+ ssl_config_service_.get(),
+ net::HttpAuthHandlerFactory::CreateDefault(host_resolver_),
+ network_delegate_,
+ net_log_,
+ NULL); // backend_factory
+}
+
+const std::string &SfRequestContext::GetUserAgent(const GURL &url) const {
+ return mUserAgent;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+SfNetworkLibrary::SfNetworkLibrary() {}
+
+SfNetworkLibrary::VerifyResult SfNetworkLibrary::VerifyX509CertChain(
+ const std::vector<std::string>& cert_chain,
+ const std::string& hostname,
+ const std::string& auth_type) {
+ return VERIFY_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+SfDelegate::SfDelegate()
+ : mOwner(NULL),
+ mURLRequest(NULL),
+ mReadBuffer(new net::IOBufferWithSize(8192)),
+ mNumBytesRead(0),
+ mNumBytesTotal(0),
+ mDataDestination(NULL),
+ mAtEOS(false) {
+ InitializeNetworkThreadIfNecessary();
+}
+
+SfDelegate::~SfDelegate() {
+ CHECK(mURLRequest == NULL);
+}
+
+void SfDelegate::setOwner(ChromiumHTTPDataSource *owner) {
+ mOwner = owner;
+}
+
+void SfDelegate::OnReceivedRedirect(
+ URLRequest *request, const GURL &new_url, bool *defer_redirect) {
+ MY_LOGI("OnReceivedRedirect");
+}
+
+void SfDelegate::OnAuthRequired(
+ URLRequest *request, net::AuthChallengeInfo *auth_info) {
+ MY_LOGI("OnAuthRequired");
+
+ inherited::OnAuthRequired(request, auth_info);
+}
+
+void SfDelegate::OnCertificateRequested(
+ URLRequest *request, net::SSLCertRequestInfo *cert_request_info) {
+ MY_LOGI("OnCertificateRequested");
+
+ inherited::OnCertificateRequested(request, cert_request_info);
+}
+
+void SfDelegate::OnSSLCertificateError(
+ URLRequest *request, int cert_error, net::X509Certificate *cert) {
+ fprintf(stderr, "OnSSLCertificateError cert_error=%d\n", cert_error);
+
+ inherited::OnSSLCertificateError(request, cert_error, cert);
+}
+
+void SfDelegate::OnGetCookies(URLRequest *request, bool blocked_by_policy) {
+ MY_LOGI("OnGetCookies");
+}
+
+void SfDelegate::OnSetCookie(
+ URLRequest *request,
+ const std::string &cookie_line,
+ const net::CookieOptions &options,
+ bool blocked_by_policy) {
+ MY_LOGI("OnSetCookie");
+}
+
+void SfDelegate::OnResponseStarted(URLRequest *request) {
+ if (request->status().status() != URLRequestStatus::SUCCESS) {
+ MY_LOGI(StringPrintf(
+ "Request failed with status %d and os_error %d",
+ request->status().status(),
+ request->status().os_error()).c_str());
+
+ delete mURLRequest;
+ mURLRequest = NULL;
+
+ mOwner->onConnectionFailed(ERROR_IO);
+ return;
+ } else if (mRangeRequested && request->GetResponseCode() != 206) {
+ MY_LOGI(StringPrintf(
+ "We requested a content range, but server didn't "
+ "support that. (responded with %d)",
+ request->GetResponseCode()).c_str());
+
+ delete mURLRequest;
+ mURLRequest = NULL;
+
+ mOwner->onConnectionFailed(-EPIPE);
+ return;
+ } else if ((request->GetResponseCode() / 100) != 2) {
+ MY_LOGI(StringPrintf(
+ "Server responded with http status %d",
+ request->GetResponseCode()).c_str());
+
+ delete mURLRequest;
+ mURLRequest = NULL;
+
+ mOwner->onConnectionFailed(ERROR_IO);
+ return;
+ }
+
+ MY_LOGV("OnResponseStarted");
+
+ std::string headers;
+ request->GetAllResponseHeaders(&headers);
+
+ MY_LOGV(StringPrintf("response headers: %s", headers.c_str()).c_str());
+
+ mOwner->onConnectionEstablished(request->GetExpectedContentSize());
+}
+
+void SfDelegate::OnReadCompleted(URLRequest *request, int bytes_read) {
+ if (bytes_read == -1) {
+ MY_LOGI(StringPrintf(
+ "OnReadCompleted, read failed, status %d",
+ request->status().status()).c_str());
+
+ mOwner->onReadCompleted(ERROR_IO);
+ return;
+ }
+
+ MY_LOGV(StringPrintf("OnReadCompleted, read %d bytes", bytes_read).c_str());
+
+ if (bytes_read < 0) {
+ MY_LOGI(StringPrintf(
+ "Read failed w/ status %d\n",
+ request->status().status()).c_str());
+
+ mOwner->onReadCompleted(ERROR_IO);
+ return;
+ } else if (bytes_read == 0) {
+ mAtEOS = true;
+ mOwner->onReadCompleted(mNumBytesRead);
+ return;
+ }
+
+ CHECK_GT(bytes_read, 0);
+ CHECK_LE(mNumBytesRead + bytes_read, mNumBytesTotal);
+
+ memcpy((uint8_t *)mDataDestination + mNumBytesRead,
+ mReadBuffer->data(),
+ bytes_read);
+
+ mNumBytesRead += bytes_read;
+
+ readMore(request);
+}
+
+void SfDelegate::readMore(URLRequest *request) {
+ while (mNumBytesRead < mNumBytesTotal) {
+ size_t copy = mNumBytesTotal - mNumBytesRead;
+ if (copy > mReadBuffer->size()) {
+ copy = mReadBuffer->size();
+ }
+
+ int n;
+ if (request->Read(mReadBuffer, copy, &n)) {
+ MY_LOGV(StringPrintf("Read %d bytes directly.", n).c_str());
+
+ CHECK_LE((size_t)n, copy);
+
+ memcpy((uint8_t *)mDataDestination + mNumBytesRead,
+ mReadBuffer->data(),
+ n);
+
+ mNumBytesRead += n;
+
+ if (n == 0) {
+ mAtEOS = true;
+ break;
+ }
+ } else {
+ MY_LOGV("readMore pending read");
+
+ if (request->status().status() != URLRequestStatus::IO_PENDING) {
+ MY_LOGI(StringPrintf(
+ "Direct read failed w/ status %d\n",
+ request->status().status()).c_str());
+
+ mOwner->onReadCompleted(ERROR_IO);
+ return;
+ }
+
+ return;
+ }
+ }
+
+ mOwner->onReadCompleted(mNumBytesRead);
+}
+
+void SfDelegate::initiateConnection(
+ const char *uri,
+ const KeyedVector<String8, String8> *headers,
+ off64_t offset) {
+ GURL url(uri);
+
+ MessageLoop *loop = gNetworkThread->message_loop();
+ loop->PostTask(
+ FROM_HERE,
+ NewRunnableFunction(
+ &SfDelegate::OnInitiateConnectionWrapper,
+ this,
+ url,
+ headers,
+ offset));
+
+}
+
+// static
+void SfDelegate::OnInitiateConnectionWrapper(
+ SfDelegate *me, GURL url,
+ const KeyedVector<String8, String8> *headers,
+ off64_t offset) {
+ me->onInitiateConnection(url, headers, offset);
+}
+
+void SfDelegate::onInitiateConnection(
+ const GURL &url,
+ const KeyedVector<String8, String8> *extra,
+ off64_t offset) {
+ CHECK(mURLRequest == NULL);
+
+ mURLRequest = new URLRequest(url, this);
+ mAtEOS = false;
+
+ mRangeRequested = false;
+
+ if (offset != 0 || extra != NULL) {
+ net::HttpRequestHeaders headers =
+ mURLRequest->extra_request_headers();
+
+ if (offset != 0) {
+ headers.AddHeaderFromString(
+ StringPrintf("Range: bytes=%lld-", offset).c_str());
+
+ mRangeRequested = true;
+ }
+
+ if (extra != NULL) {
+ for (size_t i = 0; i < extra->size(); ++i) {
+ AString s;
+ s.append(extra->keyAt(i).string());
+ s.append(": ");
+ s.append(extra->valueAt(i).string());
+
+ headers.AddHeaderFromString(s.c_str());
+ }
+ }
+
+ mURLRequest->SetExtraRequestHeaders(headers);
+ }
+
+ mURLRequest->set_context(gReqContext);
+
+ mURLRequest->Start();
+}
+
+void SfDelegate::initiateDisconnect() {
+ MessageLoop *loop = gNetworkThread->message_loop();
+ loop->PostTask(
+ FROM_HERE,
+ NewRunnableFunction(
+ &SfDelegate::OnInitiateDisconnectWrapper, this));
+}
+
+// static
+void SfDelegate::OnInitiateDisconnectWrapper(SfDelegate *me) {
+ me->onInitiateDisconnect();
+}
+
+void SfDelegate::onInitiateDisconnect() {
+ mURLRequest->Cancel();
+
+ delete mURLRequest;
+ mURLRequest = NULL;
+
+ mOwner->onDisconnectComplete();
+}
+
+void SfDelegate::initiateRead(void *data, size_t size) {
+ MessageLoop *loop = gNetworkThread->message_loop();
+ loop->PostTask(
+ FROM_HERE,
+ NewRunnableFunction(
+ &SfDelegate::OnInitiateReadWrapper, this, data, size));
+}
+
+// static
+void SfDelegate::OnInitiateReadWrapper(
+ SfDelegate *me, void *data, size_t size) {
+ me->onInitiateRead(data, size);
+}
+
+void SfDelegate::onInitiateRead(void *data, size_t size) {
+ CHECK(mURLRequest != NULL);
+
+ mNumBytesRead = 0;
+ mNumBytesTotal = size;
+ mDataDestination = data;
+
+ if (mAtEOS) {
+ mOwner->onReadCompleted(0);
+ return;
+ }
+
+ readMore(mURLRequest);
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/chromium_http/support.h b/media/libstagefright/chromium_http/support.h
new file mode 100644
index 0000000..634ac93
--- /dev/null
+++ b/media/libstagefright/chromium_http/support.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SUPPORT_H_
+
+#define SUPPORT_H_
+
+#include <assert.h>
+
+#include "net/base/net_log.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_context.h"
+#include "net/base/android_network_library.h"
+#include "net/base/io_buffer.h"
+
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+
+namespace android {
+
+struct SfNetLog : public net::NetLog {
+ SfNetLog();
+
+ virtual void AddEntry(
+ EventType type,
+ const base::TimeTicks &time,
+ const Source &source,
+ EventPhase phase,
+ EventParameters *params);
+
+ virtual uint32 NextID();
+ virtual LogLevel GetLogLevel() const;
+
+private:
+ uint32 mNextID;
+
+ DISALLOW_EVIL_CONSTRUCTORS(SfNetLog);
+};
+
+struct SfRequestContext : public URLRequestContext {
+ SfRequestContext();
+
+ virtual const std::string &GetUserAgent(const GURL &url) const;
+
+private:
+ std::string mUserAgent;
+
+ DISALLOW_EVIL_CONSTRUCTORS(SfRequestContext);
+};
+
+// This is required for https support, we don't really verify certificates,
+// we accept anything...
+struct SfNetworkLibrary : public net::AndroidNetworkLibrary {
+ SfNetworkLibrary();
+
+ virtual VerifyResult VerifyX509CertChain(
+ const std::vector<std::string>& cert_chain,
+ const std::string& hostname,
+ const std::string& auth_type);
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(SfNetworkLibrary);
+};
+
+struct ChromiumHTTPDataSource;
+
+struct SfDelegate : public URLRequest::Delegate {
+ SfDelegate();
+ virtual ~SfDelegate();
+
+ void initiateConnection(
+ const char *uri,
+ const KeyedVector<String8, String8> *headers,
+ off64_t offset);
+
+ void initiateDisconnect();
+ void initiateRead(void *data, size_t size);
+
+ void setOwner(ChromiumHTTPDataSource *mOwner);
+
+ virtual void OnReceivedRedirect(
+ URLRequest *request, const GURL &new_url, bool *defer_redirect);
+
+ virtual void OnAuthRequired(
+ URLRequest *request, net::AuthChallengeInfo *auth_info);
+
+ virtual void OnCertificateRequested(
+ URLRequest *request, net::SSLCertRequestInfo *cert_request_info);
+
+ virtual void OnSSLCertificateError(
+ URLRequest *request, int cert_error, net::X509Certificate *cert);
+
+ virtual void OnGetCookies(URLRequest *request, bool blocked_by_policy);
+
+ virtual void OnSetCookie(
+ URLRequest *request,
+ const std::string &cookie_line,
+ const net::CookieOptions &options,
+ bool blocked_by_policy);
+
+ virtual void OnResponseStarted(URLRequest *request);
+
+ virtual void OnReadCompleted(URLRequest *request, int bytes_read);
+
+private:
+ typedef Delegate inherited;
+
+ ChromiumHTTPDataSource *mOwner;
+
+ URLRequest *mURLRequest;
+ scoped_refptr<net::IOBufferWithSize> mReadBuffer;
+
+ size_t mNumBytesRead;
+ size_t mNumBytesTotal;
+ void *mDataDestination;
+
+ bool mRangeRequested;
+ bool mAtEOS;
+
+ void readMore(URLRequest *request);
+
+ static void OnInitiateConnectionWrapper(
+ SfDelegate *me,
+ GURL url,
+ const KeyedVector<String8, String8> *headers,
+ off64_t offset);
+
+ static void OnInitiateDisconnectWrapper(SfDelegate *me);
+
+ static void OnInitiateReadWrapper(
+ SfDelegate *me, void *data, size_t size);
+
+ void onInitiateConnection(
+ const GURL &url,
+ const KeyedVector<String8, String8> *headers,
+ off64_t offset);
+
+ void onInitiateDisconnect();
+ void onInitiateRead(void *data, size_t size);
+
+ DISALLOW_EVIL_CONSTRUCTORS(SfDelegate);
+};
+
+} // namespace android
+
+#endif // SUPPORT_H_
diff --git a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
index 59dd740..0ba42ff 100644
--- a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
+++ b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MP3Decoder"
+
#include "MP3Decoder.h"
#include "include/pvmp3decoder_api.h"
@@ -175,7 +178,12 @@ status_t MP3Decoder::read(
!= NO_DECODING_ERROR) {
LOGV("mp3 decoder returned error %d", decoderErr);
- if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR) {
+ if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR ||
+ mConfig->outputFrameSize == 0) {
+
+ if (mConfig->outputFrameSize == 0) {
+ LOGE("Output frame size is 0");
+ }
buffer->release();
buffer = NULL;
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index f0cd6a0..8e1bdf3 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -23,7 +23,7 @@
#include "LiveDataSource.h"
#include "include/M3UParser.h"
-#include "include/NuHTTPDataSource.h"
+#include "include/HTTPBase.h"
#include <cutils/properties.h>
#include <media/stagefright/foundation/hexdump.h>
@@ -45,9 +45,9 @@ LiveSession::LiveSession(uint32_t flags)
: mFlags(flags),
mDataSource(new LiveDataSource),
mHTTPDataSource(
- new NuHTTPDataSource(
+ HTTPBase::Create(
(mFlags & kFlagIncognito)
- ? NuHTTPDataSource::kFlagIncognito
+ ? HTTPBase::kFlagIncognito
: 0)),
mPrevBandwidthIndex(-1),
mLastPlaylistFetchTimeUs(-1),
@@ -625,7 +625,12 @@ status_t LiveSession::decryptBuffer(
} else {
key = new ABuffer(16);
- sp<NuHTTPDataSource> keySource = new NuHTTPDataSource;
+ sp<HTTPBase> keySource =
+ HTTPBase::Create(
+ (mFlags & kFlagIncognito)
+ ? HTTPBase::kFlagIncognito
+ : 0);
+
status_t err = keySource->connect(keyURI.c_str());
if (err == OK) {
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 4e6f75c..b26f202 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -18,7 +18,7 @@
#define AWESOME_PLAYER_H_
-#include "NuHTTPDataSource.h"
+#include "HTTPBase.h"
#include "TimedEventQueue.h"
#include <media/MediaPlayerInterface.h>
@@ -209,7 +209,7 @@ private:
MediaBuffer *mVideoBuffer;
- sp<NuHTTPDataSource> mConnectingDataSource;
+ sp<HTTPBase> mConnectingDataSource;
sp<NuCachedSource2> mCachedSource;
sp<ALooper> mLooper;
@@ -217,7 +217,7 @@ private:
sp<ARTSPController> mConnectingRTSPController;
DrmManagerClient *mDrmManagerClient;
- DecryptHandle *mDecryptHandle;
+ sp<DecryptHandle> mDecryptHandle;
status_t setDataSource_l(
const char *uri,
diff --git a/media/libstagefright/include/ChromiumHTTPDataSource.h b/media/libstagefright/include/ChromiumHTTPDataSource.h
new file mode 100644
index 0000000..af49059
--- /dev/null
+++ b/media/libstagefright/include/ChromiumHTTPDataSource.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CHROME_HTTP_DATA_SOURCE_H_
+
+#define CHROME_HTTP_DATA_SOURCE_H_
+
+#include <media/stagefright/foundation/AString.h>
+#include <utils/threads.h>
+
+#include "HTTPBase.h"
+
+namespace android {
+
+struct SfDelegate;
+
+struct ChromiumHTTPDataSource : public HTTPBase {
+ ChromiumHTTPDataSource(uint32_t flags = 0);
+
+ virtual status_t connect(
+ const char *uri,
+ const KeyedVector<String8, String8> *headers = NULL,
+ off64_t offset = 0);
+
+ virtual void disconnect();
+
+ virtual status_t initCheck() const;
+
+ virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+ virtual status_t getSize(off64_t *size);
+ virtual uint32_t flags();
+
+ virtual bool estimateBandwidth(int32_t *bandwidth_bps);
+
+ virtual sp<DecryptHandle> DrmInitialization();
+
+ virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client);
+
+ virtual String8 getUri();
+
+protected:
+ virtual ~ChromiumHTTPDataSource();
+
+private:
+ friend struct SfDelegate;
+
+ enum State {
+ DISCONNECTED,
+ CONNECTING,
+ CONNECTED,
+ READING,
+ DISCONNECTING
+ };
+
+ struct BandwidthEntry {
+ int64_t mDelayUs;
+ size_t mNumBytes;
+ };
+
+ const uint32_t mFlags;
+
+ mutable Mutex mLock;
+ Condition mCondition;
+
+ State mState;
+
+ SfDelegate *mDelegate;
+
+ AString mURI;
+ KeyedVector<String8, String8> mHeaders;
+
+ off64_t mCurrentOffset;
+
+ // Any connection error or the result of a read operation
+ // (for the lattter this is the number of bytes read, if successful).
+ ssize_t mIOResult;
+
+ int64_t mContentSize;
+
+ List<BandwidthEntry> mBandwidthHistory;
+ size_t mNumBandwidthHistoryItems;
+ int64_t mTotalTransferTimeUs;
+ size_t mTotalTransferBytes;
+
+ sp<DecryptHandle> mDecryptHandle;
+ DrmManagerClient *mDrmManagerClient;
+
+ void disconnect_l();
+
+ status_t connect_l(
+ const char *uri,
+ const KeyedVector<String8, String8> *headers,
+ off64_t offset);
+
+ static void InitiateRead(
+ ChromiumHTTPDataSource *me, void *data, size_t size);
+
+ void initiateRead(void *data, size_t size);
+
+ void onConnectionEstablished(int64_t contentSize);
+ void onConnectionFailed(status_t err);
+ void onReadCompleted(ssize_t size);
+ void onDisconnectComplete();
+
+ void addBandwidthMeasurement_l(size_t numBytes, int64_t delayUs);
+
+ void clearDRMState_l();
+
+ DISALLOW_EVIL_CONSTRUCTORS(ChromiumHTTPDataSource);
+};
+
+} // namespace android
+
+#endif // CHROME_HTTP_DATA_SOURCE_H_
diff --git a/media/libstagefright/include/DRMExtractor.h b/media/libstagefright/include/DRMExtractor.h
index 9881cc1..b4e4afb 100644
--- a/media/libstagefright/include/DRMExtractor.h
+++ b/media/libstagefright/include/DRMExtractor.h
@@ -45,7 +45,7 @@ private:
sp<DataSource> mDataSource;
sp<MediaExtractor> mOriginalExtractor;
- DecryptHandle* mDecryptHandle;
+ sp<DecryptHandle> mDecryptHandle;
DrmManagerClient* mDrmManagerClient;
DRMExtractor(const DRMExtractor &);
diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h
new file mode 100644
index 0000000..6cec390
--- /dev/null
+++ b/media/libstagefright/include/HTTPBase.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HTTP_BASE_H_
+
+#define HTTP_BASE_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/DataSource.h>
+
+namespace android {
+
+struct HTTPBase : public DataSource {
+ enum Flags {
+ // Don't log any URLs.
+ kFlagIncognito = 1
+ };
+
+ HTTPBase();
+
+ virtual status_t connect(
+ const char *uri,
+ const KeyedVector<String8, String8> *headers = NULL,
+ off64_t offset = 0) = 0;
+
+ virtual void disconnect() = 0;
+
+ // Returns true if bandwidth could successfully be estimated,
+ // false otherwise.
+ virtual bool estimateBandwidth(int32_t *bandwidth_bps) = 0;
+
+ static sp<HTTPBase> Create(uint32_t flags = 0);
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(HTTPBase);
+};
+
+} // namespace android
+
+#endif // HTTP_BASE_H_
diff --git a/media/libstagefright/include/LiveSession.h b/media/libstagefright/include/LiveSession.h
index 3fe5d4e..2b5ea0e 100644
--- a/media/libstagefright/include/LiveSession.h
+++ b/media/libstagefright/include/LiveSession.h
@@ -26,7 +26,7 @@ struct ABuffer;
struct DataSource;
struct LiveDataSource;
struct M3UParser;
-struct NuHTTPDataSource;
+struct HTTPBase;
struct LiveSession : public AHandler {
enum Flags {
@@ -75,7 +75,7 @@ private:
sp<LiveDataSource> mDataSource;
- sp<NuHTTPDataSource> mHTTPDataSource;
+ sp<HTTPBase> mHTTPDataSource;
AString mMasterURL;
Vector<BandwidthItem> mBandwidthItems;
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index 04e8a6a..d9ef208 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -57,7 +57,7 @@ private:
};
sp<DataSource> mDataSource;
- bool mHaveMetadata;
+ status_t mInitCheck;
bool mHasVideo;
Track *mFirstTrack, *mLastTrack;
@@ -90,6 +90,10 @@ private:
status_t parseTrackHeader(off64_t data_offset, off64_t data_size);
+ Track *findTrackByMimePrefix(const char *mimePrefix);
+
+ status_t verifyIfStreamable();
+
MPEG4Extractor(const MPEG4Extractor &);
MPEG4Extractor &operator=(const MPEG4Extractor &);
};
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h
index 022804c..02d5817 100644
--- a/media/libstagefright/include/NuCachedSource2.h
+++ b/media/libstagefright/include/NuCachedSource2.h
@@ -37,8 +37,8 @@ struct NuCachedSource2 : public DataSource {
virtual status_t getSize(off64_t *size);
virtual uint32_t flags();
- virtual DecryptHandle* DrmInitialization();
- virtual void getDrmInfo(DecryptHandle **handle, DrmManagerClient **client);
+ virtual sp<DecryptHandle> DrmInitialization();
+ virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client);
virtual String8 getUri();
////////////////////////////////////////////////////////////////////////////
diff --git a/media/libstagefright/include/NuHTTPDataSource.h b/media/libstagefright/include/NuHTTPDataSource.h
index 2569568..7dd5d59 100644
--- a/media/libstagefright/include/NuHTTPDataSource.h
+++ b/media/libstagefright/include/NuHTTPDataSource.h
@@ -18,28 +18,24 @@
#define NU_HTTP_DATA_SOURCE_H_
-#include <media/stagefright/DataSource.h>
#include <utils/List.h>
#include <utils/String8.h>
#include <utils/threads.h>
#include "HTTPStream.h"
+#include "include/HTTPBase.h"
namespace android {
-struct NuHTTPDataSource : public DataSource {
- enum Flags {
- // Don't log any URLs.
- kFlagIncognito = 1
- };
+struct NuHTTPDataSource : public HTTPBase {
NuHTTPDataSource(uint32_t flags = 0);
- status_t connect(
+ virtual status_t connect(
const char *uri,
const KeyedVector<String8, String8> *headers = NULL,
off64_t offset = 0);
- void disconnect();
+ virtual void disconnect();
virtual status_t initCheck() const;
@@ -49,10 +45,10 @@ struct NuHTTPDataSource : public DataSource {
// Returns true if bandwidth could successfully be estimated,
// false otherwise.
- bool estimateBandwidth(int32_t *bandwidth_bps);
+ virtual bool estimateBandwidth(int32_t *bandwidth_bps);
- virtual DecryptHandle* DrmInitialization();
- virtual void getDrmInfo(DecryptHandle **handle, DrmManagerClient **client);
+ virtual sp<DecryptHandle> DrmInitialization();
+ virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client);
virtual String8 getUri();
protected:
@@ -98,7 +94,7 @@ private:
int64_t mTotalTransferTimeUs;
size_t mTotalTransferBytes;
- DecryptHandle *mDecryptHandle;
+ sp<DecryptHandle> mDecryptHandle;
DrmManagerClient *mDrmManagerClient;
status_t connect(
diff --git a/media/tests/omxjpegdecoder/Android.mk b/media/tests/omxjpegdecoder/Android.mk
index 7802efd..81c6167 100644
--- a/media/tests/omxjpegdecoder/Android.mk
+++ b/media/tests/omxjpegdecoder/Android.mk
@@ -22,11 +22,6 @@ LOCAL_SRC_FILES := \
SkOmxPixelRef.cpp \
StreamSource.cpp
-
-# add external/skia/src/images/SkImageDecoder_libjpeg.cpp
-LOCAL_SRC_FILES += \
- ../../../../../external/skia/src/images/SkImageDecoder_libjpeg.cpp
-
LOCAL_SHARED_LIBRARIES := \
libcutils \
libskia \