Home | History | Annotate | Download | only in ndk
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "NdkMediaDataSource"
     19 
     20 #include "NdkMediaDataSourcePriv.h"
     21 
     22 #include <inttypes.h>
     23 #include <jni.h>
     24 #include <unistd.h>
     25 
     26 #include <android_runtime/AndroidRuntime.h>
     27 #include <android_util_Binder.h>
     28 #include <cutils/properties.h>
     29 #include <utils/Log.h>
     30 #include <utils/StrongPointer.h>
     31 #include <media/IMediaHTTPService.h>
     32 #include <media/NdkMediaError.h>
     33 #include <media/NdkMediaDataSource.h>
     34 #include <media/stagefright/DataSourceFactory.h>
     35 #include <media/stagefright/InterfaceUtils.h>
     36 #include <mediaplayer2/JavaVMHelper.h>
     37 #include <mediaplayer2/JMedia2HTTPService.h>
     38 
     39 #include "../../libstagefright/include/HTTPBase.h"
     40 #include "../../libstagefright/include/NuCachedSource2.h"
     41 #include "NdkMediaDataSourceCallbacksPriv.h"
     42 
     43 
     44 using namespace android;
     45 
     46 struct AMediaDataSource {
     47     void *userdata;
     48     AMediaDataSourceReadAt readAt;
     49     AMediaDataSourceGetSize getSize;
     50     AMediaDataSourceClose close;
     51     AMediaDataSourceGetAvailableSize getAvailableSize;
     52     sp<DataSource> mImpl;
     53     uint32_t mFlags;
     54 };
     55 
     56 NdkDataSource::NdkDataSource(AMediaDataSource *dataSource)
     57     : mDataSource(AMediaDataSource_new()) {
     58     AMediaDataSource_setReadAt(mDataSource, dataSource->readAt);
     59     AMediaDataSource_setGetSize(mDataSource, dataSource->getSize);
     60     AMediaDataSource_setClose(mDataSource, dataSource->close);
     61     AMediaDataSource_setUserdata(mDataSource, dataSource->userdata);
     62     AMediaDataSource_setGetAvailableSize(mDataSource, dataSource->getAvailableSize);
     63     mDataSource->mImpl = dataSource->mImpl;
     64     mDataSource->mFlags = dataSource->mFlags;
     65 }
     66 
     67 NdkDataSource::~NdkDataSource() {
     68     AMediaDataSource_delete(mDataSource);
     69 }
     70 
     71 status_t NdkDataSource::initCheck() const {
     72     return OK;
     73 }
     74 
     75 uint32_t NdkDataSource::flags() {
     76     return mDataSource->mFlags;
     77 }
     78 
     79 ssize_t NdkDataSource::readAt(off64_t offset, void *data, size_t size) {
     80     Mutex::Autolock l(mLock);
     81     if (mDataSource->readAt == NULL || mDataSource->userdata == NULL) {
     82         return -1;
     83     }
     84     return mDataSource->readAt(mDataSource->userdata, offset, data, size);
     85 }
     86 
     87 status_t NdkDataSource::getSize(off64_t *size) {
     88     Mutex::Autolock l(mLock);
     89     if (mDataSource->getSize == NULL || mDataSource->userdata == NULL) {
     90         return NO_INIT;
     91     }
     92     if (size != NULL) {
     93         *size = mDataSource->getSize(mDataSource->userdata);
     94     }
     95     return OK;
     96 }
     97 
     98 String8 NdkDataSource::toString() {
     99     return String8::format("NdkDataSource(pid %d, uid %d)", getpid(), getuid());
    100 }
    101 
    102 String8 NdkDataSource::getMIMEType() const {
    103     return String8("application/octet-stream");
    104 }
    105 
    106 void NdkDataSource::close() {
    107     if (mDataSource->close != NULL && mDataSource->userdata != NULL) {
    108         mDataSource->close(mDataSource->userdata);
    109     }
    110 }
    111 
    112 status_t NdkDataSource::getAvailableSize(off64_t offset, off64_t *sizeptr) {
    113     off64_t size = -1;
    114     if (mDataSource->getAvailableSize != NULL
    115             && mDataSource->userdata != NULL
    116             && sizeptr != NULL) {
    117         size = mDataSource->getAvailableSize(mDataSource->userdata, offset);
    118         *sizeptr = size;
    119     }
    120     return size >= 0 ? OK : UNKNOWN_ERROR;
    121 }
    122 
    123 static sp<MediaHTTPService> createMediaHttpServiceFromJavaObj(JNIEnv *env, jobject obj, int version) {
    124     if (obj == NULL) {
    125         return NULL;
    126     }
    127     switch (version) {
    128         case 1:
    129             return interface_cast<IMediaHTTPService>(ibinderForJavaObject(env, obj));
    130         case 2:
    131             return new JMedia2HTTPService(env, obj);
    132         default:
    133             return NULL;
    134     }
    135 }
    136 
    137 static sp<MediaHTTPService> createMediaHttpServiceTemplate(
    138         JNIEnv *env,
    139         const char *uri,
    140         const char *clazz,
    141         const char *method,
    142         const char *signature,
    143         int version) {
    144     jobject service = NULL;
    145     if (env == NULL) {
    146         ALOGE("http service must be created from Java thread");
    147         return NULL;
    148     }
    149 
    150     jclass mediahttpclass = env->FindClass(clazz);
    151     if (mediahttpclass == NULL) {
    152         ALOGE("can't find Media(2)HttpService");
    153         env->ExceptionClear();
    154         return NULL;
    155     }
    156 
    157     jmethodID mediaHttpCreateMethod = env->GetStaticMethodID(mediahttpclass, method, signature);
    158     if (mediaHttpCreateMethod == NULL) {
    159         ALOGE("can't find method");
    160         env->ExceptionClear();
    161         return NULL;
    162     }
    163 
    164     jstring juri = env->NewStringUTF(uri);
    165 
    166     service = env->CallStaticObjectMethod(mediahttpclass, mediaHttpCreateMethod, juri);
    167     env->DeleteLocalRef(juri);
    168 
    169     env->ExceptionClear();
    170     sp<MediaHTTPService> httpService = createMediaHttpServiceFromJavaObj(env, service, version);
    171     return httpService;
    172 
    173 }
    174 
    175 sp<MediaHTTPService> createMediaHttpService(const char *uri, int version) {
    176 
    177     JNIEnv *env;
    178     const char *clazz, *method, *signature;
    179 
    180     switch (version) {
    181         case 1:
    182             env = AndroidRuntime::getJNIEnv();
    183             clazz = "android/media/MediaHTTPService";
    184             method = "createHttpServiceBinderIfNecessary";
    185             signature = "(Ljava/lang/String;)Landroid/os/IBinder;";
    186             break;
    187         case 2:
    188             env = JavaVMHelper::getJNIEnv();
    189             clazz = "android/media/Media2HTTPService";
    190             method = "createHTTPService";
    191             signature = "(Ljava/lang/String;)Landroid/media/Media2HTTPService;";
    192             break;
    193         default:
    194             return NULL;
    195     }
    196 
    197     return createMediaHttpServiceTemplate(env, uri, clazz, method, signature, version);
    198 
    199 }
    200 
    201 extern "C" {
    202 
    203 EXPORT
    204 AMediaDataSource* AMediaDataSource_new() {
    205     AMediaDataSource *mSource = new AMediaDataSource();
    206     mSource->userdata = NULL;
    207     mSource->readAt = NULL;
    208     mSource->getSize = NULL;
    209     mSource->close = NULL;
    210     return mSource;
    211 }
    212 
    213 EXPORT
    214 AMediaDataSource* AMediaDataSource_newUri(
    215         const char *uri,
    216         int numheaders,
    217         const char * const *key_values) {
    218 
    219     sp<MediaHTTPService> service = createMediaHttpService(uri, /* version = */ 1);
    220     KeyedVector<String8, String8> headers;
    221     for (int i = 0; i < numheaders; ++i) {
    222         String8 key8(key_values[i * 2]);
    223         String8 value8(key_values[i * 2 + 1]);
    224         headers.add(key8, value8);
    225     }
    226 
    227     sp<DataSource> source = DataSourceFactory::CreateFromURI(service, uri, &headers);
    228     if (source == NULL) {
    229         ALOGE("AMediaDataSource_newUri source is null");
    230         return NULL;
    231     }
    232     ALOGI("AMediaDataSource_newUri source %s flags %u", source->toString().c_str(), source->flags());
    233     AMediaDataSource* aSource = convertDataSourceToAMediaDataSource(source);
    234     aSource->mImpl = source;
    235     aSource->mFlags = source->flags();
    236     return aSource;
    237 }
    238 
    239 EXPORT
    240 void AMediaDataSource_delete(AMediaDataSource *mSource) {
    241     ALOGV("dtor");
    242     if (mSource != NULL) {
    243         delete mSource;
    244     }
    245 }
    246 
    247 EXPORT
    248 void AMediaDataSource_setUserdata(AMediaDataSource *mSource, void *userdata) {
    249     mSource->userdata = userdata;
    250 }
    251 
    252 EXPORT
    253 void AMediaDataSource_setReadAt(AMediaDataSource *mSource, AMediaDataSourceReadAt readAt) {
    254     mSource->readAt = readAt;
    255 }
    256 
    257 EXPORT
    258 void AMediaDataSource_setGetSize(AMediaDataSource *mSource, AMediaDataSourceGetSize getSize) {
    259     mSource->getSize = getSize;
    260 }
    261 
    262 EXPORT
    263 void AMediaDataSource_setClose(AMediaDataSource *mSource, AMediaDataSourceClose close) {
    264     mSource->close = close;
    265 }
    266 
    267 EXPORT
    268 void AMediaDataSource_close(AMediaDataSource *mSource) {
    269     return mSource->close(mSource->userdata);
    270 }
    271 
    272 EXPORT
    273 void AMediaDataSource_setGetAvailableSize(AMediaDataSource *mSource,
    274         AMediaDataSourceGetAvailableSize getAvailableSize) {
    275     mSource->getAvailableSize = getAvailableSize;
    276 }
    277 
    278 } // extern "C"
    279 
    280