blob: ea43d2ebb6a79772cab5abcb083419a49747cb8f [file] [log] [blame]
Marco Nelissen0c3be872014-05-01 10:14:44 -07001/*
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
Marco Nelissenc7a11b22014-05-30 10:13:25 -070017//#define LOG_NDEBUG 0
Marco Nelissen0c3be872014-05-01 10:14:44 -070018#define LOG_TAG "NdkMediaExtractor"
19
20
Colin Cross7e8d4ba2017-05-04 16:17:42 -070021#include <media/NdkMediaError.h>
22#include <media/NdkMediaExtractor.h>
Robert Shih0df451b2017-12-08 14:16:50 -080023#include "NdkMediaDataSourcePriv.h"
Marco Nelissen0c3be872014-05-01 10:14:44 -070024#include "NdkMediaFormatPriv.h"
25
26
Aurimas Liutikas214c8332016-02-19 14:48:23 -080027#include <inttypes.h>
Marco Nelissen0c3be872014-05-01 10:14:44 -070028#include <utils/Log.h>
29#include <utils/StrongPointer.h>
Marco Nelissen050eb322014-05-09 15:10:23 -070030#include <media/hardware/CryptoAPI.h>
Marco Nelissen0c3be872014-05-01 10:14:44 -070031#include <media/stagefright/foundation/ABuffer.h>
32#include <media/stagefright/foundation/AMessage.h>
33#include <media/stagefright/MetaData.h>
34#include <media/stagefright/NuMediaExtractor.h>
35#include <media/IMediaHTTPService.h>
36#include <android_runtime/AndroidRuntime.h>
37#include <android_util_Binder.h>
38
39#include <jni.h>
40
41using namespace android;
42
Marco Nelissene419d7c2014-05-15 14:17:25 -070043static media_status_t translate_error(status_t err) {
Marco Nelissen0c3be872014-05-01 10:14:44 -070044 if (err == OK) {
Marco Nelissene419d7c2014-05-15 14:17:25 -070045 return AMEDIA_OK;
Marco Nelissen0c3be872014-05-01 10:14:44 -070046 }
47 ALOGE("sf error code: %d", err);
Marco Nelissene419d7c2014-05-15 14:17:25 -070048 return AMEDIA_ERROR_UNKNOWN;
Marco Nelissen0c3be872014-05-01 10:14:44 -070049}
50
51struct AMediaExtractor {
52 sp<NuMediaExtractor> mImpl;
Marco Nelissen050eb322014-05-09 15:10:23 -070053 sp<ABuffer> mPsshBuf;
Marco Nelissen0c3be872014-05-01 10:14:44 -070054};
55
56extern "C" {
57
Marco Nelissen3425fd52014-05-14 11:12:46 -070058EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -070059AMediaExtractor* AMediaExtractor_new() {
60 ALOGV("ctor");
61 AMediaExtractor *mData = new AMediaExtractor();
62 mData->mImpl = new NuMediaExtractor();
63 return mData;
64}
65
Marco Nelissen3425fd52014-05-14 11:12:46 -070066EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -070067media_status_t AMediaExtractor_delete(AMediaExtractor *mData) {
Marco Nelissen0c3be872014-05-01 10:14:44 -070068 ALOGV("dtor");
69 delete mData;
Marco Nelissene419d7c2014-05-15 14:17:25 -070070 return AMEDIA_OK;
Marco Nelissen0c3be872014-05-01 10:14:44 -070071}
72
Marco Nelissen3425fd52014-05-14 11:12:46 -070073EXPORT
Glenn Kastenb187de12014-12-30 08:18:15 -080074media_status_t AMediaExtractor_setDataSourceFd(AMediaExtractor *mData, int fd, off64_t offset,
75 off64_t length) {
Aurimas Liutikas214c8332016-02-19 14:48:23 -080076 ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
Marco Nelissene419d7c2014-05-15 14:17:25 -070077 return translate_error(mData->mImpl->setDataSource(fd, offset, length));
Marco Nelissen0c3be872014-05-01 10:14:44 -070078}
79
Marco Nelissen3425fd52014-05-14 11:12:46 -070080EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -070081media_status_t AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) {
Marco Nelissen0c3be872014-05-01 10:14:44 -070082 ALOGV("setDataSource(%s)", location);
83 // TODO: add header support
84
85 JNIEnv *env = AndroidRuntime::getJNIEnv();
86 jobject service = NULL;
87 if (env == NULL) {
88 ALOGE("setDataSource(path) must be called from Java thread");
Marco Nelissene419d7c2014-05-15 14:17:25 -070089 return AMEDIA_ERROR_UNSUPPORTED;
Marco Nelissen0c3be872014-05-01 10:14:44 -070090 }
91
92 jclass mediahttpclass = env->FindClass("android/media/MediaHTTPService");
93 if (mediahttpclass == NULL) {
94 ALOGE("can't find MediaHttpService");
95 env->ExceptionClear();
Marco Nelissene419d7c2014-05-15 14:17:25 -070096 return AMEDIA_ERROR_UNSUPPORTED;
Marco Nelissen0c3be872014-05-01 10:14:44 -070097 }
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();
Marco Nelissene419d7c2014-05-15 14:17:25 -0700104 return AMEDIA_ERROR_UNSUPPORTED;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700105 }
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
Marco Nelissene419d7c2014-05-15 14:17:25 -0700118 status_t err = mData->mImpl->setDataSource(httpService, location, NULL);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700119 env->ExceptionClear();
Marco Nelissene419d7c2014-05-15 14:17:25 -0700120 return translate_error(err);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700121}
122
Marco Nelissen3425fd52014-05-14 11:12:46 -0700123EXPORT
Robert Shih0df451b2017-12-08 14:16:50 -0800124media_status_t AMediaExtractor_setDataSourceCustom(AMediaExtractor* mData, AMediaDataSource *src) {
125 return translate_error(mData->mImpl->setDataSource(new NdkDataSource(src)));
126}
127
128EXPORT
Robert Shih30e3c7d2018-01-21 17:06:12 -0800129AMediaFormat* AMediaExtractor_getFileFormat(AMediaExtractor *mData) {
130 sp<AMessage> format;
131 mData->mImpl->getFileFormat(&format);
132 return AMediaFormat_fromMsg(&format);
133}
134
135EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700136size_t AMediaExtractor_getTrackCount(AMediaExtractor *mData) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700137 return mData->mImpl->countTracks();
138}
139
Marco Nelissen3425fd52014-05-14 11:12:46 -0700140EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700141AMediaFormat* AMediaExtractor_getTrackFormat(AMediaExtractor *mData, size_t idx) {
142 sp<AMessage> format;
143 mData->mImpl->getTrackFormat(idx, &format);
144 return AMediaFormat_fromMsg(&format);
145}
146
Marco Nelissen3425fd52014-05-14 11:12:46 -0700147EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700148media_status_t AMediaExtractor_selectTrack(AMediaExtractor *mData, size_t idx) {
Mark Salyzyn98f28cd2014-06-18 16:32:50 -0700149 ALOGV("selectTrack(%zu)", idx);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700150 return translate_error(mData->mImpl->selectTrack(idx));
151}
152
Marco Nelissen3425fd52014-05-14 11:12:46 -0700153EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700154media_status_t AMediaExtractor_unselectTrack(AMediaExtractor *mData, size_t idx) {
Mark Salyzyn98f28cd2014-06-18 16:32:50 -0700155 ALOGV("unselectTrack(%zu)", idx);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700156 return translate_error(mData->mImpl->unselectTrack(idx));
157}
158
Marco Nelissen3425fd52014-05-14 11:12:46 -0700159EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700160bool AMediaExtractor_advance(AMediaExtractor *mData) {
161 //ALOGV("advance");
Robert Shih70452262016-09-16 16:43:49 -0700162 status_t err = mData->mImpl->advance();
163 if (err == ERROR_END_OF_STREAM) {
164 return false;
165 } else if (err != OK) {
166 ALOGE("sf error code: %d", err);
167 return false;
168 }
169 return true;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700170}
171
Marco Nelissen3425fd52014-05-14 11:12:46 -0700172EXPORT
Marco Nelissen79e2b622014-05-16 08:07:28 -0700173media_status_t AMediaExtractor_seekTo(AMediaExtractor *ex, int64_t seekPosUs, SeekMode mode) {
174 android::MediaSource::ReadOptions::SeekMode sfmode;
175 if (mode == AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC) {
176 sfmode = android::MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC;
177 } else if (mode == AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC) {
178 sfmode = android::MediaSource::ReadOptions::SEEK_CLOSEST_SYNC;
179 } else {
180 sfmode = android::MediaSource::ReadOptions::SEEK_NEXT_SYNC;
181 }
182
183 return translate_error(ex->mImpl->seekTo(seekPosUs, sfmode));
184}
185
186EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700187ssize_t AMediaExtractor_readSampleData(AMediaExtractor *mData, uint8_t *buffer, size_t capacity) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700188 //ALOGV("readSampleData");
189 sp<ABuffer> tmp = new ABuffer(buffer, capacity);
190 if (mData->mImpl->readSampleData(tmp) == OK) {
191 return tmp->size();
192 }
193 return -1;
194}
195
Marco Nelissen3425fd52014-05-14 11:12:46 -0700196EXPORT
Robert Shih30e3c7d2018-01-21 17:06:12 -0800197ssize_t AMediaExtractor_getSampleSize(AMediaExtractor *mData) {
198 size_t sampleSize;
199 status_t err = mData->mImpl->getSampleSize(&sampleSize);
200 if (err != OK) {
201 return -1;
202 }
203 return sampleSize;
204}
205
206EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700207uint32_t AMediaExtractor_getSampleFlags(AMediaExtractor *mData) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700208 int sampleFlags = 0;
209 sp<MetaData> meta;
210 status_t err = mData->mImpl->getSampleMeta(&meta);
211 if (err != OK) {
212 return -1;
213 }
214 int32_t val;
215 if (meta->findInt32(kKeyIsSyncFrame, &val) && val != 0) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700216 sampleFlags |= AMEDIAEXTRACTOR_SAMPLE_FLAG_SYNC;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700217 }
218
219 uint32_t type;
220 const void *data;
221 size_t size;
222 if (meta->findData(kKeyEncryptedSizes, &type, &data, &size)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700223 sampleFlags |= AMEDIAEXTRACTOR_SAMPLE_FLAG_ENCRYPTED;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700224 }
225 return sampleFlags;
226}
227
Marco Nelissen3425fd52014-05-14 11:12:46 -0700228EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700229int AMediaExtractor_getSampleTrackIndex(AMediaExtractor *mData) {
230 size_t idx;
231 if (mData->mImpl->getSampleTrackIndex(&idx) != OK) {
232 return -1;
233 }
234 return idx;
235}
236
Marco Nelissen3425fd52014-05-14 11:12:46 -0700237EXPORT
Marco Nelisseneb4860c2014-05-29 08:04:34 -0700238int64_t AMediaExtractor_getSampleTime(AMediaExtractor *mData) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700239 int64_t time;
240 if (mData->mImpl->getSampleTime(&time) != OK) {
241 return -1;
242 }
243 return time;
244}
245
Marco Nelissen3425fd52014-05-14 11:12:46 -0700246EXPORT
Marco Nelissen050eb322014-05-09 15:10:23 -0700247PsshInfo* AMediaExtractor_getPsshInfo(AMediaExtractor *ex) {
248
249 if (ex->mPsshBuf != NULL) {
250 return (PsshInfo*) ex->mPsshBuf->data();
251 }
252
253 sp<AMessage> format;
254 ex->mImpl->getFileFormat(&format);
255 sp<ABuffer> buffer;
256 if(!format->findBuffer("pssh", &buffer)) {
257 return NULL;
258 }
259
260 // the format of the buffer is 1 or more of:
261 // {
262 // 16 byte uuid
263 // 4 byte data length N
264 // N bytes of data
265 // }
266
267 // Determine the number of entries in the source data.
268 // Since we got the data from stagefright, we trust it is valid and properly formatted.
269 const uint8_t* data = buffer->data();
270 size_t len = buffer->size();
271 size_t numentries = 0;
272 while (len > 0) {
273 numentries++;
274
Marco Nelissen346bb512015-04-09 14:32:45 -0700275 if (len < 16) {
276 ALOGE("invalid PSSH data");
277 return NULL;
278 }
Marco Nelissen050eb322014-05-09 15:10:23 -0700279 // skip uuid
280 data += 16;
281 len -= 16;
282
283 // get data length
Marco Nelissen346bb512015-04-09 14:32:45 -0700284 if (len < 4) {
285 ALOGE("invalid PSSH data");
286 return NULL;
287 }
Marco Nelissen050eb322014-05-09 15:10:23 -0700288 uint32_t datalen = *((uint32_t*)data);
289 data += 4;
290 len -= 4;
291
Marco Nelissen346bb512015-04-09 14:32:45 -0700292 if (len < datalen) {
293 ALOGE("invalid PSSH data");
294 return NULL;
295 }
Marco Nelissen050eb322014-05-09 15:10:23 -0700296 // skip the data
297 data += datalen;
298 len -= datalen;
299 }
300
Marco Nelissen58344bc2014-10-23 11:36:38 -0700301 // there are <numentries> in the source buffer, we need
302 // (source buffer size) - (sizeof(uint32_t) * numentries) + sizeof(size_t)
303 // + ((sizeof(void*) + sizeof(size_t)) * numentries) bytes for the PsshInfo structure
304 // Or in other words, the data lengths in the source structure are replaced by size_t
305 // (which may be the same size or larger, for 64 bit), and in addition there is an
306 // extra pointer for each entry, and an extra size_t for the entire PsshInfo.
307 size_t newsize = buffer->size() - (sizeof(uint32_t) * numentries) + sizeof(size_t)
308 + ((sizeof(void*) + sizeof(size_t)) * numentries);
Marco Nelissen346bb512015-04-09 14:32:45 -0700309 if (newsize <= buffer->size()) {
310 ALOGE("invalid PSSH data");
311 return NULL;
312 }
Marco Nelissen050eb322014-05-09 15:10:23 -0700313 ex->mPsshBuf = new ABuffer(newsize);
314 ex->mPsshBuf->setRange(0, newsize);
315
316 // copy data
317 const uint8_t* src = buffer->data();
318 uint8_t* dst = ex->mPsshBuf->data();
Marco Nelissen58344bc2014-10-23 11:36:38 -0700319 uint8_t* dstdata = dst + sizeof(size_t) + numentries * sizeof(PsshEntry);
320 *((size_t*)dst) = numentries;
321 dst += sizeof(size_t);
Marco Nelissen050eb322014-05-09 15:10:23 -0700322 for (size_t i = 0; i < numentries; i++) {
323 // copy uuid
324 memcpy(dst, src, 16);
325 src += 16;
326 dst += 16;
327
328 // get/copy data length
329 uint32_t datalen = *((uint32_t*)src);
Marco Nelissen58344bc2014-10-23 11:36:38 -0700330 *((size_t*)dst) = datalen;
331 src += sizeof(uint32_t);
332 dst += sizeof(size_t);
Marco Nelissen050eb322014-05-09 15:10:23 -0700333
334 // the next entry in the destination is a pointer to the actual data, which we store
335 // after the array of PsshEntry
Marco Nelissen58344bc2014-10-23 11:36:38 -0700336 *((void**)dst) = dstdata;
337 dst += sizeof(void*);
Marco Nelissen050eb322014-05-09 15:10:23 -0700338
339 // copy the actual data
340 memcpy(dstdata, src, datalen);
341 dstdata += datalen;
342 src += datalen;
343 }
344
345 return (PsshInfo*) ex->mPsshBuf->data();
346}
347
Marco Nelissen3425fd52014-05-14 11:12:46 -0700348EXPORT
Marco Nelissen050eb322014-05-09 15:10:23 -0700349AMediaCodecCryptoInfo *AMediaExtractor_getSampleCryptoInfo(AMediaExtractor *ex) {
350 sp<MetaData> meta;
351 if(ex->mImpl->getSampleMeta(&meta) != 0) {
352 return NULL;
353 }
354
355 uint32_t type;
356 const void *crypteddata;
357 size_t cryptedsize;
358 if (!meta->findData(kKeyEncryptedSizes, &type, &crypteddata, &cryptedsize)) {
359 return NULL;
360 }
361 size_t numSubSamples = cryptedsize / sizeof(size_t);
362
363 const void *cleardata;
364 size_t clearsize;
365 if (meta->findData(kKeyPlainSizes, &type, &cleardata, &clearsize)) {
366 if (clearsize != cryptedsize) {
367 // The two must be of the same length.
368 return NULL;
369 }
370 }
371
372 const void *key;
373 size_t keysize;
Edwin Wongb2fb3c92016-08-29 14:57:47 -0700374 if (meta->findData(kKeyCryptoKey, &type, &key, &keysize)) {
Marco Nelissen050eb322014-05-09 15:10:23 -0700375 if (keysize != 16) {
Edwin Wongb2fb3c92016-08-29 14:57:47 -0700376 // Keys must be 16 bytes in length.
Marco Nelissen050eb322014-05-09 15:10:23 -0700377 return NULL;
378 }
379 }
380
381 const void *iv;
382 size_t ivsize;
383 if (meta->findData(kKeyCryptoIV, &type, &iv, &ivsize)) {
384 if (ivsize != 16) {
385 // IVs must be 16 bytes in length.
386 return NULL;
387 }
388 }
389
390 int32_t mode;
391 if (!meta->findInt32(kKeyCryptoMode, &mode)) {
392 mode = CryptoPlugin::kMode_AES_CTR;
393 }
394
395 return AMediaCodecCryptoInfo_new(
396 numSubSamples,
397 (uint8_t*) key,
398 (uint8_t*) iv,
Marco Nelissen79e2b622014-05-16 08:07:28 -0700399 (cryptoinfo_mode_t) mode,
Marco Nelissen050eb322014-05-09 15:10:23 -0700400 (size_t*) cleardata,
401 (size_t*) crypteddata);
402}
403
Robert Shih30e3c7d2018-01-21 17:06:12 -0800404EXPORT
405int64_t AMediaExtractor_getCachedDuration(AMediaExtractor *ex) {
406 bool eos;
407 int64_t durationUs;
408 if (ex->mImpl->getCachedDuration(&durationUs, &eos)) {
409 return durationUs;
410 }
411 return -1;
412}
Marco Nelissen0c3be872014-05-01 10:14:44 -0700413
414} // extern "C"
415