blob: b86f177e00d244481b8bf3d00ef3e7a88ad7839e [file] [log] [blame]
Marco Nelissen0b164472018-05-30 12:16:56 -07001/*
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#ifndef MEDIA_EXTRACTOR_PLUGIN_HELPER_H_
18
19#define MEDIA_EXTRACTOR_PLUGIN_HELPER_H_
20
Marco Nelissencec44d02018-06-17 22:21:09 -070021#include <arpa/inet.h>
Marco Nelissen0b164472018-05-30 12:16:56 -070022#include <stdio.h>
Marco Nelissen0e043b62018-11-14 11:26:05 -080023#include <map>
Marco Nelissen0b164472018-05-30 12:16:56 -070024
25#include <utils/Errors.h>
26#include <utils/Log.h>
27#include <utils/RefBase.h>
28#include <media/MediaExtractorPluginApi.h>
Marco Nelissen0e043b62018-11-14 11:26:05 -080029#include <media/NdkMediaFormat.h>
Marco Nelissen0b164472018-05-30 12:16:56 -070030
31namespace android {
32
33class DataSourceBase;
34class MetaDataBase;
35struct MediaTrack;
36
Marco Nelissen2a3363a2018-09-13 13:15:30 -070037
Marco Nelissena3082872018-12-19 14:36:28 -080038class MediaTrackHelper;
Marco Nelissen2a3363a2018-09-13 13:15:30 -070039
Marco Nelissena3082872018-12-19 14:36:28 -080040class MediaBufferHelper {
Marco Nelissen0e043b62018-11-14 11:26:05 -080041private:
Marco Nelissena3082872018-12-19 14:36:28 -080042 friend CMediaTrack *wrap(MediaTrackHelper *);
43 CMediaBuffer *mBuffer;
Marco Nelissen0e043b62018-11-14 11:26:05 -080044public:
Marco Nelissena3082872018-12-19 14:36:28 -080045 MediaBufferHelper(CMediaBuffer *buf) {
Marco Nelissen0e043b62018-11-14 11:26:05 -080046 mBuffer = buf;
47 }
48
Marco Nelissena3082872018-12-19 14:36:28 -080049 virtual ~MediaBufferHelper() {}
Marco Nelissen0e043b62018-11-14 11:26:05 -080050
Marco Nelissene92a5c72018-12-13 09:52:38 -080051 virtual void release() {
Marco Nelissen0e043b62018-11-14 11:26:05 -080052 mBuffer->release(mBuffer->handle);
53 }
54
Marco Nelissene92a5c72018-12-13 09:52:38 -080055 virtual void* data() {
Marco Nelissen0e043b62018-11-14 11:26:05 -080056 return mBuffer->data(mBuffer->handle);
57 }
58
Marco Nelissene92a5c72018-12-13 09:52:38 -080059 virtual size_t size() {
Marco Nelissen0e043b62018-11-14 11:26:05 -080060 return mBuffer->size(mBuffer->handle);
61 }
62
Marco Nelissene92a5c72018-12-13 09:52:38 -080063 virtual size_t range_offset() {
Marco Nelissen0e043b62018-11-14 11:26:05 -080064 return mBuffer->range_offset(mBuffer->handle);
65 }
66
Marco Nelissene92a5c72018-12-13 09:52:38 -080067 virtual size_t range_length() {
Marco Nelissen0e043b62018-11-14 11:26:05 -080068 return mBuffer->range_length(mBuffer->handle);
69 }
70
Marco Nelissene92a5c72018-12-13 09:52:38 -080071 virtual void set_range(size_t offset, size_t length) {
Marco Nelissen0e043b62018-11-14 11:26:05 -080072 mBuffer->set_range(mBuffer->handle, offset, length);
73 }
Marco Nelissene92a5c72018-12-13 09:52:38 -080074 virtual AMediaFormat *meta_data() {
Marco Nelissen0e043b62018-11-14 11:26:05 -080075 return mBuffer->meta_data(mBuffer->handle);
76 }
77};
78
Marco Nelissena3082872018-12-19 14:36:28 -080079class MediaBufferGroupHelper {
Marco Nelissen0e043b62018-11-14 11:26:05 -080080private:
Marco Nelissena3082872018-12-19 14:36:28 -080081 CMediaBufferGroup *mGroup;
82 std::map<CMediaBuffer*, MediaBufferHelper*> mBufferHelpers;
Marco Nelissen0e043b62018-11-14 11:26:05 -080083public:
Marco Nelissena3082872018-12-19 14:36:28 -080084 MediaBufferGroupHelper(CMediaBufferGroup *group) {
Marco Nelissen0e043b62018-11-14 11:26:05 -080085 mGroup = group;
86 }
Marco Nelissena3082872018-12-19 14:36:28 -080087 ~MediaBufferGroupHelper() {
Marco Nelissen0e043b62018-11-14 11:26:05 -080088 // delete all entries in map
89 ALOGV("buffergroup %p map has %zu entries", this, mBufferHelpers.size());
90 for (auto it = mBufferHelpers.begin(); it != mBufferHelpers.end(); ++it) {
91 delete it->second;
92 }
93 }
94 bool init(size_t buffers, size_t buffer_size, size_t growthLimit = 0) {
95 return mGroup->init(mGroup->handle, buffers, buffer_size, growthLimit);
96 }
97 void add_buffer(size_t size) {
98 mGroup->add_buffer(mGroup->handle, size);
99 }
100 media_status_t acquire_buffer(
Marco Nelissena3082872018-12-19 14:36:28 -0800101 MediaBufferHelper **buffer, bool nonBlocking = false, size_t requestedSize = 0) {
102 CMediaBuffer *buf = nullptr;
Marco Nelissen0e043b62018-11-14 11:26:05 -0800103 media_status_t ret =
104 mGroup->acquire_buffer(mGroup->handle, &buf, nonBlocking, requestedSize);
105 if (ret == AMEDIA_OK && buf != nullptr) {
106 auto helper = mBufferHelpers.find(buf);
107 if (helper == mBufferHelpers.end()) {
Marco Nelissena3082872018-12-19 14:36:28 -0800108 MediaBufferHelper* newHelper = new MediaBufferHelper(buf);
Marco Nelissen0e043b62018-11-14 11:26:05 -0800109 mBufferHelpers.insert(std::make_pair(buf, newHelper));
110 *buffer = newHelper;
111 } else {
112 *buffer = helper->second;
113 }
114 } else {
115 *buffer = nullptr;
116 }
117 return ret;
118 }
119 bool has_buffers() {
120 return mGroup->has_buffers(mGroup->handle);
121 }
122};
123
Marco Nelissena3082872018-12-19 14:36:28 -0800124class MediaTrackHelper {
Marco Nelissen0e043b62018-11-14 11:26:05 -0800125public:
Marco Nelissena3082872018-12-19 14:36:28 -0800126 MediaTrackHelper() : mBufferGroup(nullptr) {
Marco Nelissen0e043b62018-11-14 11:26:05 -0800127 }
Marco Nelissena3082872018-12-19 14:36:28 -0800128 virtual ~MediaTrackHelper() {
Marco Nelissen0e043b62018-11-14 11:26:05 -0800129 delete mBufferGroup;
130 }
131 virtual media_status_t start() = 0;
132 virtual media_status_t stop() = 0;
133 virtual media_status_t getFormat(AMediaFormat *format) = 0;
134
135 class ReadOptions {
136 public:
137 enum SeekMode : int32_t {
138 SEEK_PREVIOUS_SYNC,
139 SEEK_NEXT_SYNC,
140 SEEK_CLOSEST_SYNC,
141 SEEK_CLOSEST,
142 SEEK_FRAME_INDEX,
143 };
144
145 ReadOptions(uint32_t options, int64_t seekPosUs) {
146 mOptions = options;
147 mSeekPosUs = seekPosUs;
148 }
149 bool getSeekTo(int64_t *time_us, SeekMode *mode) const {
150 if ((mOptions & CMediaTrackReadOptions::SEEK) == 0) {
151 return false;
152 }
153 *time_us = mSeekPosUs;
154 *mode = (SeekMode) (mOptions & 7);
155 return true;
156 }
157 bool getNonBlocking() const {
158 return mOptions & CMediaTrackReadOptions::NONBLOCKING;
159 }
160 private:
161 uint32_t mOptions;
162 int64_t mSeekPosUs;
163 };
164
165 virtual media_status_t read(
Marco Nelissena3082872018-12-19 14:36:28 -0800166 MediaBufferHelper **buffer, const ReadOptions *options = NULL) = 0;
Marco Nelissen0e043b62018-11-14 11:26:05 -0800167 virtual bool supportsNonBlockingRead() { return false; }
168protected:
Marco Nelissena3082872018-12-19 14:36:28 -0800169 friend CMediaTrack *wrap(MediaTrackHelper *track);
170 MediaBufferGroupHelper *mBufferGroup;
Marco Nelissen0e043b62018-11-14 11:26:05 -0800171};
172
Marco Nelissena3082872018-12-19 14:36:28 -0800173inline CMediaTrack *wrap(MediaTrackHelper *track) {
Marco Nelissenb2a7ed22019-01-18 10:34:03 -0800174 if (track == nullptr) {
175 return nullptr;
176 }
Marco Nelissena3082872018-12-19 14:36:28 -0800177 CMediaTrack *wrapper = (CMediaTrack*) malloc(sizeof(CMediaTrack));
Marco Nelissen0e043b62018-11-14 11:26:05 -0800178 wrapper->data = track;
179 wrapper->free = [](void *data) -> void {
Marco Nelissena3082872018-12-19 14:36:28 -0800180 delete (MediaTrackHelper*)(data);
Marco Nelissen0e043b62018-11-14 11:26:05 -0800181 };
Marco Nelissena3082872018-12-19 14:36:28 -0800182 wrapper->start = [](void *data, CMediaBufferGroup *bufferGroup) -> media_status_t {
183 if (((MediaTrackHelper*)data)->mBufferGroup) {
Marco Nelissen0e043b62018-11-14 11:26:05 -0800184 // this shouldn't happen, but handle it anyway
Marco Nelissena3082872018-12-19 14:36:28 -0800185 delete ((MediaTrackHelper*)data)->mBufferGroup;
Marco Nelissen0e043b62018-11-14 11:26:05 -0800186 }
Marco Nelissena3082872018-12-19 14:36:28 -0800187 ((MediaTrackHelper*)data)->mBufferGroup = new MediaBufferGroupHelper(bufferGroup);
188 return ((MediaTrackHelper*)data)->start();
Marco Nelissen0e043b62018-11-14 11:26:05 -0800189 };
190 wrapper->stop = [](void *data) -> media_status_t {
Marco Nelissena3082872018-12-19 14:36:28 -0800191 return ((MediaTrackHelper*)data)->stop();
Marco Nelissen0e043b62018-11-14 11:26:05 -0800192 };
193 wrapper->getFormat = [](void *data, AMediaFormat *meta) -> media_status_t {
Marco Nelissena3082872018-12-19 14:36:28 -0800194 return ((MediaTrackHelper*)data)->getFormat(meta);
Marco Nelissen0e043b62018-11-14 11:26:05 -0800195 };
Marco Nelissena3082872018-12-19 14:36:28 -0800196 wrapper->read = [](void *data, CMediaBuffer **buffer, uint32_t options, int64_t seekPosUs)
Marco Nelissen0e043b62018-11-14 11:26:05 -0800197 -> media_status_t {
Marco Nelissena3082872018-12-19 14:36:28 -0800198 MediaTrackHelper::ReadOptions opts(options, seekPosUs);
199 MediaBufferHelper *buf = NULL;
200 media_status_t ret = ((MediaTrackHelper*)data)->read(&buf, &opts);
Marco Nelissen0e043b62018-11-14 11:26:05 -0800201 if (ret == AMEDIA_OK && buf != nullptr) {
202 *buffer = buf->mBuffer;
203 }
204 return ret;
205 };
206 wrapper->supportsNonBlockingRead = [](void *data) -> bool {
Marco Nelissena3082872018-12-19 14:36:28 -0800207 return ((MediaTrackHelper*)data)->supportsNonBlockingRead();
Marco Nelissen0e043b62018-11-14 11:26:05 -0800208 };
209 return wrapper;
210}
Marco Nelissen56f19382018-09-12 15:30:59 -0700211
212
Marco Nelissen0b164472018-05-30 12:16:56 -0700213// extractor plugins can derive from this class which looks remarkably
214// like MediaExtractor and can be easily wrapped in the required C API
215class MediaExtractorPluginHelper
216{
217public:
218 virtual ~MediaExtractorPluginHelper() {}
219 virtual size_t countTracks() = 0;
Marco Nelissen2a3363a2018-09-13 13:15:30 -0700220 virtual MediaTrackHelper *getTrack(size_t index) = 0;
Marco Nelissen0b164472018-05-30 12:16:56 -0700221
222 enum GetTrackMetaDataFlags {
223 kIncludeExtensiveMetaData = 1
224 };
Marco Nelissena3082872018-12-19 14:36:28 -0800225 virtual media_status_t getTrackMetaData(
226 AMediaFormat *meta,
Marco Nelissen0b164472018-05-30 12:16:56 -0700227 size_t index, uint32_t flags = 0) = 0;
228
229 // Return container specific meta-data. The default implementation
230 // returns an empty metadata object.
Marco Nelissena3082872018-12-19 14:36:28 -0800231 virtual media_status_t getMetaData(AMediaFormat *meta) = 0;
Marco Nelissen0b164472018-05-30 12:16:56 -0700232
233 enum Flags {
234 CAN_SEEK_BACKWARD = 1, // the "seek 10secs back button"
235 CAN_SEEK_FORWARD = 2, // the "seek 10secs forward button"
236 CAN_PAUSE = 4,
237 CAN_SEEK = 8, // the "seek bar"
238 };
239
240 // If subclasses do _not_ override this, the default is
241 // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
242 virtual uint32_t flags() const {
243 return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE;
244 };
245
Marco Nelissena3082872018-12-19 14:36:28 -0800246 virtual media_status_t setMediaCas(const uint8_t* /*casToken*/, size_t /*size*/) {
247 return AMEDIA_ERROR_INVALID_OPERATION;
Marco Nelissen0b164472018-05-30 12:16:56 -0700248 }
249
250 virtual const char * name() { return "<unspecified>"; }
251
252protected:
253 MediaExtractorPluginHelper() {}
254
255private:
256 MediaExtractorPluginHelper(const MediaExtractorPluginHelper &);
257 MediaExtractorPluginHelper &operator=(const MediaExtractorPluginHelper &);
258};
259
260inline CMediaExtractor *wrap(MediaExtractorPluginHelper *extractor) {
261 CMediaExtractor *wrapper = (CMediaExtractor*) malloc(sizeof(CMediaExtractor));
262 wrapper->data = extractor;
263 wrapper->free = [](void *data) -> void {
264 delete (MediaExtractorPluginHelper*)(data);
265 };
266 wrapper->countTracks = [](void *data) -> size_t {
267 return ((MediaExtractorPluginHelper*)data)->countTracks();
268 };
Marco Nelissen2a3363a2018-09-13 13:15:30 -0700269 wrapper->getTrack = [](void *data, size_t index) -> CMediaTrack* {
270 return wrap(((MediaExtractorPluginHelper*)data)->getTrack(index));
Marco Nelissen0b164472018-05-30 12:16:56 -0700271 };
272 wrapper->getTrackMetaData = [](
273 void *data,
Marco Nelissena3082872018-12-19 14:36:28 -0800274 AMediaFormat *meta,
275 size_t index, uint32_t flags) -> media_status_t {
Marco Nelissen0b164472018-05-30 12:16:56 -0700276 return ((MediaExtractorPluginHelper*)data)->getTrackMetaData(meta, index, flags);
277 };
278 wrapper->getMetaData = [](
279 void *data,
Marco Nelissena3082872018-12-19 14:36:28 -0800280 AMediaFormat *meta) -> media_status_t {
Marco Nelissen0b164472018-05-30 12:16:56 -0700281 return ((MediaExtractorPluginHelper*)data)->getMetaData(meta);
282 };
283 wrapper->flags = [](
284 void *data) -> uint32_t {
285 return ((MediaExtractorPluginHelper*)data)->flags();
286 };
287 wrapper->setMediaCas = [](
Marco Nelissena3082872018-12-19 14:36:28 -0800288 void *data, const uint8_t *casToken, size_t size) -> media_status_t {
Marco Nelissen0b164472018-05-30 12:16:56 -0700289 return ((MediaExtractorPluginHelper*)data)->setMediaCas(casToken, size);
290 };
291 wrapper->name = [](
292 void *data) -> const char * {
293 return ((MediaExtractorPluginHelper*)data)->name();
294 };
295 return wrapper;
296}
297
Marco Nelissencec44d02018-06-17 22:21:09 -0700298/* adds some convience methods */
299class DataSourceHelper {
300public:
301 explicit DataSourceHelper(CDataSource *csource) {
302 mSource = csource;
303 }
304
305 explicit DataSourceHelper(DataSourceHelper *source) {
306 mSource = source->mSource;
307 }
308
Marco Nelissenc2b10b32018-09-24 13:19:43 -0700309 virtual ~DataSourceHelper() {}
310
311 virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
Marco Nelissencec44d02018-06-17 22:21:09 -0700312 return mSource->readAt(mSource->handle, offset, data, size);
313 }
314
Marco Nelissenc2b10b32018-09-24 13:19:43 -0700315 virtual status_t getSize(off64_t *size) {
Marco Nelissencec44d02018-06-17 22:21:09 -0700316 return mSource->getSize(mSource->handle, size);
317 }
318
319 bool getUri(char *uriString, size_t bufferSize) {
320 return mSource->getUri(mSource->handle, uriString, bufferSize);
321 }
322
Marco Nelissenc2b10b32018-09-24 13:19:43 -0700323 virtual uint32_t flags() {
Marco Nelissencec44d02018-06-17 22:21:09 -0700324 return mSource->flags(mSource->handle);
325 }
326
327 // Convenience methods:
328 bool getUInt16(off64_t offset, uint16_t *x) {
329 *x = 0;
330
331 uint8_t byte[2];
332 if (readAt(offset, byte, 2) != 2) {
333 return false;
334 }
335
336 *x = (byte[0] << 8) | byte[1];
337
338 return true;
339 }
340
341 // 3 byte int, returned as a 32-bit int
342 bool getUInt24(off64_t offset, uint32_t *x) {
343 *x = 0;
344
345 uint8_t byte[3];
346 if (readAt(offset, byte, 3) != 3) {
347 return false;
348 }
349
350 *x = (byte[0] << 16) | (byte[1] << 8) | byte[2];
351
352 return true;
353 }
354
355 bool getUInt32(off64_t offset, uint32_t *x) {
356 *x = 0;
357
358 uint32_t tmp;
359 if (readAt(offset, &tmp, 4) != 4) {
360 return false;
361 }
362
363 *x = ntohl(tmp);
364
365 return true;
366 }
367
368 bool getUInt64(off64_t offset, uint64_t *x) {
369 *x = 0;
370
371 uint64_t tmp;
372 if (readAt(offset, &tmp, 8) != 8) {
373 return false;
374 }
375
376 *x = ((uint64_t)ntohl(tmp & 0xffffffff) << 32) | ntohl(tmp >> 32);
377
378 return true;
379 }
380
381 // read either int<N> or int<2N> into a uint<2N>_t, size is the int size in bytes.
382 bool getUInt16Var(off64_t offset, uint16_t *x, size_t size) {
383 if (size == 2) {
384 return getUInt16(offset, x);
385 }
386 if (size == 1) {
387 uint8_t tmp;
388 if (readAt(offset, &tmp, 1) == 1) {
389 *x = tmp;
390 return true;
391 }
392 }
393 return false;
394 }
395
396 bool getUInt32Var(off64_t offset, uint32_t *x, size_t size) {
397 if (size == 4) {
398 return getUInt32(offset, x);
399 }
400 if (size == 2) {
401 uint16_t tmp;
402 if (getUInt16(offset, &tmp)) {
403 *x = tmp;
404 return true;
405 }
406 }
407 return false;
408 }
409
410 bool getUInt64Var(off64_t offset, uint64_t *x, size_t size) {
411 if (size == 8) {
412 return getUInt64(offset, x);
413 }
414 if (size == 4) {
415 uint32_t tmp;
416 if (getUInt32(offset, &tmp)) {
417 *x = tmp;
418 return true;
419 }
420 }
421 return false;
422 }
423
424protected:
425 CDataSource *mSource;
426};
427
428
429
Marco Nelissen0b164472018-05-30 12:16:56 -0700430// helpers to create a media_uuid_t from a string literal
431
432// purposely not defined anywhere so that this will fail to link if
433// expressions below are not evaluated at compile time
434int invalid_uuid_string(const char *);
435
436template <typename T, size_t N>
437constexpr uint8_t _digitAt_(const T (&s)[N], const size_t n) {
438 return s[n] >= '0' && s[n] <= '9' ? s[n] - '0'
439 : s[n] >= 'a' && s[n] <= 'f' ? s[n] - 'a' + 10
440 : s[n] >= 'A' && s[n] <= 'F' ? s[n] - 'A' + 10
441 : invalid_uuid_string("uuid: bad digits");
442}
443
444template <typename T, size_t N>
445constexpr uint8_t _hexByteAt_(const T (&s)[N], size_t n) {
446 return (_digitAt_(s, n) << 4) + _digitAt_(s, n + 1);
447}
448
449constexpr bool _assertIsDash_(char c) {
450 return c == '-' ? true : invalid_uuid_string("Wrong format");
451}
452
453template <size_t N>
454constexpr media_uuid_t constUUID(const char (&s) [N]) {
455 static_assert(N == 37, "uuid: wrong length");
456 return
457 _assertIsDash_(s[8]),
458 _assertIsDash_(s[13]),
459 _assertIsDash_(s[18]),
460 _assertIsDash_(s[23]),
461 media_uuid_t {{
462 _hexByteAt_(s, 0),
463 _hexByteAt_(s, 2),
464 _hexByteAt_(s, 4),
465 _hexByteAt_(s, 6),
466 _hexByteAt_(s, 9),
467 _hexByteAt_(s, 11),
468 _hexByteAt_(s, 14),
469 _hexByteAt_(s, 16),
470 _hexByteAt_(s, 19),
471 _hexByteAt_(s, 21),
472 _hexByteAt_(s, 24),
473 _hexByteAt_(s, 26),
474 _hexByteAt_(s, 28),
475 _hexByteAt_(s, 30),
476 _hexByteAt_(s, 32),
477 _hexByteAt_(s, 34),
478 }};
479}
480// Convenience macro to create a media_uuid_t from a string literal, which should
481// be formatted as "12345678-1234-1234-1234-123456789abc", as generated by
482// e.g. https://www.uuidgenerator.net/ or the 'uuidgen' linux command.
483// Hex digits may be upper or lower case.
484//
485// The macro call is otherwise equivalent to specifying the structure directly
486// (e.g. UUID("7d613858-5837-4a38-84c5-332d1cddee27") is the same as
487// {{0x7d, 0x61, 0x38, 0x58, 0x58, 0x37, 0x4a, 0x38,
488// 0x84, 0xc5, 0x33, 0x2d, 0x1c, 0xdd, 0xee, 0x27}})
489
490#define UUID(str) []{ constexpr media_uuid_t uuid = constUUID(str); return uuid; }()
491
492} // namespace android
493
494#endif // MEDIA_EXTRACTOR_PLUGIN_HELPER_H_