NdkMediaExtractor.cpp revision 3425fd5a55dd31e261d2f2a9590c762d6d0a6b79
1/* 2 * Copyright (C) 2014 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 "NdkMediaExtractor" 19 20 21#include "NdkMediaError.h" 22#include "NdkMediaExtractor.h" 23#include "NdkMediaFormatPriv.h" 24 25 26#include <utils/Log.h> 27#include <utils/StrongPointer.h> 28#include <media/hardware/CryptoAPI.h> 29#include <media/stagefright/foundation/ABuffer.h> 30#include <media/stagefright/foundation/AMessage.h> 31#include <media/stagefright/MetaData.h> 32#include <media/stagefright/NuMediaExtractor.h> 33#include <media/IMediaHTTPService.h> 34#include <android_runtime/AndroidRuntime.h> 35#include <android_util_Binder.h> 36 37#include <jni.h> 38 39using namespace android; 40 41static int translate_error(status_t err) { 42 if (err == OK) { 43 return OK; 44 } 45 ALOGE("sf error code: %d", err); 46 return AMEDIAERROR_GENERIC; 47} 48 49struct AMediaExtractor { 50 sp<NuMediaExtractor> mImpl; 51 sp<ABuffer> mPsshBuf; 52 53}; 54 55extern "C" { 56 57EXPORT 58AMediaExtractor* AMediaExtractor_new() { 59 ALOGV("ctor"); 60 AMediaExtractor *mData = new AMediaExtractor(); 61 mData->mImpl = new NuMediaExtractor(); 62 return mData; 63} 64 65EXPORT 66int AMediaExtractor_delete(AMediaExtractor *mData) { 67 ALOGV("dtor"); 68 delete mData; 69 return OK; 70} 71 72EXPORT 73int AMediaExtractor_setDataSourceFd(AMediaExtractor *mData, int fd, off64_t offset, off64_t length) { 74 ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length); 75 mData->mImpl->setDataSource(fd, offset, length); 76 return 0; 77} 78 79EXPORT 80int AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) { 81 ALOGV("setDataSource(%s)", location); 82 // TODO: add header support 83 84 JNIEnv *env = AndroidRuntime::getJNIEnv(); 85 jobject service = NULL; 86 if (env == NULL) { 87 ALOGE("setDataSource(path) must be called from Java thread"); 88 env->ExceptionClear(); 89 return AMEDIAERROR_UNSUPPORTED; 90 } 91 92 jclass mediahttpclass = env->FindClass("android/media/MediaHTTPService"); 93 if (mediahttpclass == NULL) { 94 ALOGE("can't find MediaHttpService"); 95 env->ExceptionClear(); 96 return AMEDIAERROR_UNSUPPORTED; 97 } 98 99 jmethodID mediaHttpCreateMethod = env->GetStaticMethodID(mediahttpclass, 100 "createHttpServiceBinderIfNecessary", "(Ljava/lang/String;)Landroid/os/IBinder;"); 101 if (mediaHttpCreateMethod == NULL) { 102 ALOGE("can't find method"); 103 env->ExceptionClear(); 104 return AMEDIAERROR_UNSUPPORTED; 105 } 106 107 jstring jloc = env->NewStringUTF(location); 108 109 service = env->CallStaticObjectMethod(mediahttpclass, mediaHttpCreateMethod, jloc); 110 env->DeleteLocalRef(jloc); 111 112 sp<IMediaHTTPService> httpService; 113 if (service != NULL) { 114 sp<IBinder> binder = ibinderForJavaObject(env, service); 115 httpService = interface_cast<IMediaHTTPService>(binder); 116 } 117 118 mData->mImpl->setDataSource(httpService, location, NULL); 119 env->ExceptionClear(); 120 return OK; 121} 122 123EXPORT 124int AMediaExtractor_getTrackCount(AMediaExtractor *mData) { 125 return mData->mImpl->countTracks(); 126} 127 128EXPORT 129AMediaFormat* AMediaExtractor_getTrackFormat(AMediaExtractor *mData, size_t idx) { 130 sp<AMessage> format; 131 mData->mImpl->getTrackFormat(idx, &format); 132 return AMediaFormat_fromMsg(&format); 133} 134 135EXPORT 136int AMediaExtractor_selectTrack(AMediaExtractor *mData, size_t idx) { 137 ALOGV("selectTrack(%z)", idx); 138 return translate_error(mData->mImpl->selectTrack(idx)); 139} 140 141EXPORT 142int AMediaExtractor_unselectTrack(AMediaExtractor *mData, size_t idx) { 143 ALOGV("unselectTrack(%z)", idx); 144 return translate_error(mData->mImpl->unselectTrack(idx)); 145} 146 147EXPORT 148bool AMediaExtractor_advance(AMediaExtractor *mData) { 149 //ALOGV("advance"); 150 return mData->mImpl->advance(); 151} 152 153EXPORT 154int AMediaExtractor_readSampleData(AMediaExtractor *mData, uint8_t *buffer, size_t capacity) { 155 //ALOGV("readSampleData"); 156 sp<ABuffer> tmp = new ABuffer(buffer, capacity); 157 if (mData->mImpl->readSampleData(tmp) == OK) { 158 return tmp->size(); 159 } 160 return -1; 161} 162 163EXPORT 164int AMediaExtractor_getSampleFlags(AMediaExtractor *mData) { 165 int sampleFlags = 0; 166 sp<MetaData> meta; 167 status_t err = mData->mImpl->getSampleMeta(&meta); 168 if (err != OK) { 169 return -1; 170 } 171 int32_t val; 172 if (meta->findInt32(kKeyIsSyncFrame, &val) && val != 0) { 173 sampleFlags |= NuMediaExtractor::SAMPLE_FLAG_SYNC; 174 } 175 176 uint32_t type; 177 const void *data; 178 size_t size; 179 if (meta->findData(kKeyEncryptedSizes, &type, &data, &size)) { 180 sampleFlags |= NuMediaExtractor::SAMPLE_FLAG_ENCRYPTED; 181 } 182 return sampleFlags; 183} 184 185EXPORT 186int AMediaExtractor_getSampleTrackIndex(AMediaExtractor *mData) { 187 size_t idx; 188 if (mData->mImpl->getSampleTrackIndex(&idx) != OK) { 189 return -1; 190 } 191 return idx; 192} 193 194EXPORT 195int64_t AMediaExtractor_getSampletime(AMediaExtractor *mData) { 196 int64_t time; 197 if (mData->mImpl->getSampleTime(&time) != OK) { 198 return -1; 199 } 200 return time; 201} 202 203EXPORT 204PsshInfo* AMediaExtractor_getPsshInfo(AMediaExtractor *ex) { 205 206 if (ex->mPsshBuf != NULL) { 207 return (PsshInfo*) ex->mPsshBuf->data(); 208 } 209 210 sp<AMessage> format; 211 ex->mImpl->getFileFormat(&format); 212 sp<ABuffer> buffer; 213 if(!format->findBuffer("pssh", &buffer)) { 214 return NULL; 215 } 216 217 // the format of the buffer is 1 or more of: 218 // { 219 // 16 byte uuid 220 // 4 byte data length N 221 // N bytes of data 222 // } 223 224 // Determine the number of entries in the source data. 225 // Since we got the data from stagefright, we trust it is valid and properly formatted. 226 const uint8_t* data = buffer->data(); 227 size_t len = buffer->size(); 228 size_t numentries = 0; 229 while (len > 0) { 230 numentries++; 231 232 // skip uuid 233 data += 16; 234 len -= 16; 235 236 // get data length 237 uint32_t datalen = *((uint32_t*)data); 238 data += 4; 239 len -= 4; 240 241 // skip the data 242 data += datalen; 243 len -= datalen; 244 } 245 246 // there are <numentries> in the buffer, we need 247 // (source buffer size) + 4 + (4 * numentries) bytes for the PsshInfo structure 248 size_t newsize = buffer->size() + 4 + (4 * numentries); 249 ex->mPsshBuf = new ABuffer(newsize); 250 ex->mPsshBuf->setRange(0, newsize); 251 252 // copy data 253 const uint8_t* src = buffer->data(); 254 uint8_t* dst = ex->mPsshBuf->data(); 255 uint8_t* dstdata = dst + 4 + numentries * sizeof(PsshEntry); 256 *((uint32_t*)dst) = numentries; 257 dst += 4; 258 for (size_t i = 0; i < numentries; i++) { 259 // copy uuid 260 memcpy(dst, src, 16); 261 src += 16; 262 dst += 16; 263 264 // get/copy data length 265 uint32_t datalen = *((uint32_t*)src); 266 memcpy(dst, src, 4); 267 src += 4; 268 dst += 4; 269 270 // the next entry in the destination is a pointer to the actual data, which we store 271 // after the array of PsshEntry 272 memcpy(dst, &dstdata, sizeof(dstdata)); 273 dst += 4; 274 275 // copy the actual data 276 memcpy(dstdata, src, datalen); 277 dstdata += datalen; 278 src += datalen; 279 } 280 281 return (PsshInfo*) ex->mPsshBuf->data(); 282} 283 284EXPORT 285AMediaCodecCryptoInfo *AMediaExtractor_getSampleCryptoInfo(AMediaExtractor *ex) { 286 sp<MetaData> meta; 287 if(ex->mImpl->getSampleMeta(&meta) != 0) { 288 return NULL; 289 } 290 291 uint32_t type; 292 const void *crypteddata; 293 size_t cryptedsize; 294 if (!meta->findData(kKeyEncryptedSizes, &type, &crypteddata, &cryptedsize)) { 295 return NULL; 296 } 297 size_t numSubSamples = cryptedsize / sizeof(size_t); 298 299 const void *cleardata; 300 size_t clearsize; 301 if (meta->findData(kKeyPlainSizes, &type, &cleardata, &clearsize)) { 302 if (clearsize != cryptedsize) { 303 // The two must be of the same length. 304 return NULL; 305 } 306 } 307 308 const void *key; 309 size_t keysize; 310 if (meta->findData(kKeyCryptoIV, &type, &key, &keysize)) { 311 if (keysize != 16) { 312 // IVs must be 16 bytes in length. 313 return NULL; 314 } 315 } 316 317 const void *iv; 318 size_t ivsize; 319 if (meta->findData(kKeyCryptoIV, &type, &iv, &ivsize)) { 320 if (ivsize != 16) { 321 // IVs must be 16 bytes in length. 322 return NULL; 323 } 324 } 325 326 int32_t mode; 327 if (!meta->findInt32(kKeyCryptoMode, &mode)) { 328 mode = CryptoPlugin::kMode_AES_CTR; 329 } 330 331 return AMediaCodecCryptoInfo_new( 332 numSubSamples, 333 (uint8_t*) key, 334 (uint8_t*) iv, 335 mode, 336 (size_t*) cleardata, 337 (size_t*) crypteddata); 338} 339 340 341} // extern "C" 342 343