diff options
Diffstat (limited to 'media')
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 \ |