blob: f4d4da630f65f5c33c01f25a2d92aaf27d6adef3 [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) {
174 CMediaTrack *wrapper = (CMediaTrack*) malloc(sizeof(CMediaTrack));
Marco Nelissen0e043b62018-11-14 11:26:05 -0800175 wrapper->data = track;
176 wrapper->free = [](void *data) -> void {
Marco Nelissena3082872018-12-19 14:36:28 -0800177 delete (MediaTrackHelper*)(data);
Marco Nelissen0e043b62018-11-14 11:26:05 -0800178 };
Marco Nelissena3082872018-12-19 14:36:28 -0800179 wrapper->start = [](void *data, CMediaBufferGroup *bufferGroup) -> media_status_t {
180 if (((MediaTrackHelper*)data)->mBufferGroup) {
Marco Nelissen0e043b62018-11-14 11:26:05 -0800181 // this shouldn't happen, but handle it anyway
Marco Nelissena3082872018-12-19 14:36:28 -0800182 delete ((MediaTrackHelper*)data)->mBufferGroup;
Marco Nelissen0e043b62018-11-14 11:26:05 -0800183 }
Marco Nelissena3082872018-12-19 14:36:28 -0800184 ((MediaTrackHelper*)data)->mBufferGroup = new MediaBufferGroupHelper(bufferGroup);
185 return ((MediaTrackHelper*)data)->start();
Marco Nelissen0e043b62018-11-14 11:26:05 -0800186 };
187 wrapper->stop = [](void *data) -> media_status_t {
Marco Nelissena3082872018-12-19 14:36:28 -0800188 return ((MediaTrackHelper*)data)->stop();
Marco Nelissen0e043b62018-11-14 11:26:05 -0800189 };
190 wrapper->getFormat = [](void *data, AMediaFormat *meta) -> media_status_t {
Marco Nelissena3082872018-12-19 14:36:28 -0800191 return ((MediaTrackHelper*)data)->getFormat(meta);
Marco Nelissen0e043b62018-11-14 11:26:05 -0800192 };
Marco Nelissena3082872018-12-19 14:36:28 -0800193 wrapper->read = [](void *data, CMediaBuffer **buffer, uint32_t options, int64_t seekPosUs)
Marco Nelissen0e043b62018-11-14 11:26:05 -0800194 -> media_status_t {
Marco Nelissena3082872018-12-19 14:36:28 -0800195 MediaTrackHelper::ReadOptions opts(options, seekPosUs);
196 MediaBufferHelper *buf = NULL;
197 media_status_t ret = ((MediaTrackHelper*)data)->read(&buf, &opts);
Marco Nelissen0e043b62018-11-14 11:26:05 -0800198 if (ret == AMEDIA_OK && buf != nullptr) {
199 *buffer = buf->mBuffer;
200 }
201 return ret;
202 };
203 wrapper->supportsNonBlockingRead = [](void *data) -> bool {
Marco Nelissena3082872018-12-19 14:36:28 -0800204 return ((MediaTrackHelper*)data)->supportsNonBlockingRead();
Marco Nelissen0e043b62018-11-14 11:26:05 -0800205 };
206 return wrapper;
207}
Marco Nelissen56f19382018-09-12 15:30:59 -0700208
209
Marco Nelissen0b164472018-05-30 12:16:56 -0700210// extractor plugins can derive from this class which looks remarkably
211// like MediaExtractor and can be easily wrapped in the required C API
212class MediaExtractorPluginHelper
213{
214public:
215 virtual ~MediaExtractorPluginHelper() {}
216 virtual size_t countTracks() = 0;
Marco Nelissen2a3363a2018-09-13 13:15:30 -0700217 virtual MediaTrackHelper *getTrack(size_t index) = 0;
Marco Nelissen0b164472018-05-30 12:16:56 -0700218
219 enum GetTrackMetaDataFlags {
220 kIncludeExtensiveMetaData = 1
221 };
Marco Nelissena3082872018-12-19 14:36:28 -0800222 virtual media_status_t getTrackMetaData(
223 AMediaFormat *meta,
Marco Nelissen0b164472018-05-30 12:16:56 -0700224 size_t index, uint32_t flags = 0) = 0;
225
226 // Return container specific meta-data. The default implementation
227 // returns an empty metadata object.
Marco Nelissena3082872018-12-19 14:36:28 -0800228 virtual media_status_t getMetaData(AMediaFormat *meta) = 0;
Marco Nelissen0b164472018-05-30 12:16:56 -0700229
230 enum Flags {
231 CAN_SEEK_BACKWARD = 1, // the "seek 10secs back button"
232 CAN_SEEK_FORWARD = 2, // the "seek 10secs forward button"
233 CAN_PAUSE = 4,
234 CAN_SEEK = 8, // the "seek bar"
235 };
236
237 // If subclasses do _not_ override this, the default is
238 // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
239 virtual uint32_t flags() const {
240 return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE;
241 };
242
Marco Nelissena3082872018-12-19 14:36:28 -0800243 virtual media_status_t setMediaCas(const uint8_t* /*casToken*/, size_t /*size*/) {
244 return AMEDIA_ERROR_INVALID_OPERATION;
Marco Nelissen0b164472018-05-30 12:16:56 -0700245 }
246
247 virtual const char * name() { return "<unspecified>"; }
248
249protected:
250 MediaExtractorPluginHelper() {}
251
252private:
253 MediaExtractorPluginHelper(const MediaExtractorPluginHelper &);
254 MediaExtractorPluginHelper &operator=(const MediaExtractorPluginHelper &);
255};
256
257inline CMediaExtractor *wrap(MediaExtractorPluginHelper *extractor) {
258 CMediaExtractor *wrapper = (CMediaExtractor*) malloc(sizeof(CMediaExtractor));
259 wrapper->data = extractor;
260 wrapper->free = [](void *data) -> void {
261 delete (MediaExtractorPluginHelper*)(data);
262 };
263 wrapper->countTracks = [](void *data) -> size_t {
264 return ((MediaExtractorPluginHelper*)data)->countTracks();
265 };
Marco Nelissen2a3363a2018-09-13 13:15:30 -0700266 wrapper->getTrack = [](void *data, size_t index) -> CMediaTrack* {
267 return wrap(((MediaExtractorPluginHelper*)data)->getTrack(index));
Marco Nelissen0b164472018-05-30 12:16:56 -0700268 };
269 wrapper->getTrackMetaData = [](
270 void *data,
Marco Nelissena3082872018-12-19 14:36:28 -0800271 AMediaFormat *meta,
272 size_t index, uint32_t flags) -> media_status_t {
Marco Nelissen0b164472018-05-30 12:16:56 -0700273 return ((MediaExtractorPluginHelper*)data)->getTrackMetaData(meta, index, flags);
274 };
275 wrapper->getMetaData = [](
276 void *data,
Marco Nelissena3082872018-12-19 14:36:28 -0800277 AMediaFormat *meta) -> media_status_t {
Marco Nelissen0b164472018-05-30 12:16:56 -0700278 return ((MediaExtractorPluginHelper*)data)->getMetaData(meta);
279 };
280 wrapper->flags = [](
281 void *data) -> uint32_t {
282 return ((MediaExtractorPluginHelper*)data)->flags();
283 };
284 wrapper->setMediaCas = [](
Marco Nelissena3082872018-12-19 14:36:28 -0800285 void *data, const uint8_t *casToken, size_t size) -> media_status_t {
Marco Nelissen0b164472018-05-30 12:16:56 -0700286 return ((MediaExtractorPluginHelper*)data)->setMediaCas(casToken, size);
287 };
288 wrapper->name = [](
289 void *data) -> const char * {
290 return ((MediaExtractorPluginHelper*)data)->name();
291 };
292 return wrapper;
293}
294
Marco Nelissencec44d02018-06-17 22:21:09 -0700295/* adds some convience methods */
296class DataSourceHelper {
297public:
298 explicit DataSourceHelper(CDataSource *csource) {
299 mSource = csource;
300 }
301
302 explicit DataSourceHelper(DataSourceHelper *source) {
303 mSource = source->mSource;
304 }
305
Marco Nelissenc2b10b32018-09-24 13:19:43 -0700306 virtual ~DataSourceHelper() {}
307
308 virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
Marco Nelissencec44d02018-06-17 22:21:09 -0700309 return mSource->readAt(mSource->handle, offset, data, size);
310 }
311
Marco Nelissenc2b10b32018-09-24 13:19:43 -0700312 virtual status_t getSize(off64_t *size) {
Marco Nelissencec44d02018-06-17 22:21:09 -0700313 return mSource->getSize(mSource->handle, size);
314 }
315
316 bool getUri(char *uriString, size_t bufferSize) {
317 return mSource->getUri(mSource->handle, uriString, bufferSize);
318 }
319
Marco Nelissenc2b10b32018-09-24 13:19:43 -0700320 virtual uint32_t flags() {
Marco Nelissencec44d02018-06-17 22:21:09 -0700321 return mSource->flags(mSource->handle);
322 }
323
324 // Convenience methods:
325 bool getUInt16(off64_t offset, uint16_t *x) {
326 *x = 0;
327
328 uint8_t byte[2];
329 if (readAt(offset, byte, 2) != 2) {
330 return false;
331 }
332
333 *x = (byte[0] << 8) | byte[1];
334
335 return true;
336 }
337
338 // 3 byte int, returned as a 32-bit int
339 bool getUInt24(off64_t offset, uint32_t *x) {
340 *x = 0;
341
342 uint8_t byte[3];
343 if (readAt(offset, byte, 3) != 3) {
344 return false;
345 }
346
347 *x = (byte[0] << 16) | (byte[1] << 8) | byte[2];
348
349 return true;
350 }
351
352 bool getUInt32(off64_t offset, uint32_t *x) {
353 *x = 0;
354
355 uint32_t tmp;
356 if (readAt(offset, &tmp, 4) != 4) {
357 return false;
358 }
359
360 *x = ntohl(tmp);
361
362 return true;
363 }
364
365 bool getUInt64(off64_t offset, uint64_t *x) {
366 *x = 0;
367
368 uint64_t tmp;
369 if (readAt(offset, &tmp, 8) != 8) {
370 return false;
371 }
372
373 *x = ((uint64_t)ntohl(tmp & 0xffffffff) << 32) | ntohl(tmp >> 32);
374
375 return true;
376 }
377
378 // read either int<N> or int<2N> into a uint<2N>_t, size is the int size in bytes.
379 bool getUInt16Var(off64_t offset, uint16_t *x, size_t size) {
380 if (size == 2) {
381 return getUInt16(offset, x);
382 }
383 if (size == 1) {
384 uint8_t tmp;
385 if (readAt(offset, &tmp, 1) == 1) {
386 *x = tmp;
387 return true;
388 }
389 }
390 return false;
391 }
392
393 bool getUInt32Var(off64_t offset, uint32_t *x, size_t size) {
394 if (size == 4) {
395 return getUInt32(offset, x);
396 }
397 if (size == 2) {
398 uint16_t tmp;
399 if (getUInt16(offset, &tmp)) {
400 *x = tmp;
401 return true;
402 }
403 }
404 return false;
405 }
406
407 bool getUInt64Var(off64_t offset, uint64_t *x, size_t size) {
408 if (size == 8) {
409 return getUInt64(offset, x);
410 }
411 if (size == 4) {
412 uint32_t tmp;
413 if (getUInt32(offset, &tmp)) {
414 *x = tmp;
415 return true;
416 }
417 }
418 return false;
419 }
420
421protected:
422 CDataSource *mSource;
423};
424
425
426
Marco Nelissen0b164472018-05-30 12:16:56 -0700427// helpers to create a media_uuid_t from a string literal
428
429// purposely not defined anywhere so that this will fail to link if
430// expressions below are not evaluated at compile time
431int invalid_uuid_string(const char *);
432
433template <typename T, size_t N>
434constexpr uint8_t _digitAt_(const T (&s)[N], const size_t n) {
435 return s[n] >= '0' && s[n] <= '9' ? s[n] - '0'
436 : s[n] >= 'a' && s[n] <= 'f' ? s[n] - 'a' + 10
437 : s[n] >= 'A' && s[n] <= 'F' ? s[n] - 'A' + 10
438 : invalid_uuid_string("uuid: bad digits");
439}
440
441template <typename T, size_t N>
442constexpr uint8_t _hexByteAt_(const T (&s)[N], size_t n) {
443 return (_digitAt_(s, n) << 4) + _digitAt_(s, n + 1);
444}
445
446constexpr bool _assertIsDash_(char c) {
447 return c == '-' ? true : invalid_uuid_string("Wrong format");
448}
449
450template <size_t N>
451constexpr media_uuid_t constUUID(const char (&s) [N]) {
452 static_assert(N == 37, "uuid: wrong length");
453 return
454 _assertIsDash_(s[8]),
455 _assertIsDash_(s[13]),
456 _assertIsDash_(s[18]),
457 _assertIsDash_(s[23]),
458 media_uuid_t {{
459 _hexByteAt_(s, 0),
460 _hexByteAt_(s, 2),
461 _hexByteAt_(s, 4),
462 _hexByteAt_(s, 6),
463 _hexByteAt_(s, 9),
464 _hexByteAt_(s, 11),
465 _hexByteAt_(s, 14),
466 _hexByteAt_(s, 16),
467 _hexByteAt_(s, 19),
468 _hexByteAt_(s, 21),
469 _hexByteAt_(s, 24),
470 _hexByteAt_(s, 26),
471 _hexByteAt_(s, 28),
472 _hexByteAt_(s, 30),
473 _hexByteAt_(s, 32),
474 _hexByteAt_(s, 34),
475 }};
476}
477// Convenience macro to create a media_uuid_t from a string literal, which should
478// be formatted as "12345678-1234-1234-1234-123456789abc", as generated by
479// e.g. https://www.uuidgenerator.net/ or the 'uuidgen' linux command.
480// Hex digits may be upper or lower case.
481//
482// The macro call is otherwise equivalent to specifying the structure directly
483// (e.g. UUID("7d613858-5837-4a38-84c5-332d1cddee27") is the same as
484// {{0x7d, 0x61, 0x38, 0x58, 0x58, 0x37, 0x4a, 0x38,
485// 0x84, 0xc5, 0x33, 0x2d, 0x1c, 0xdd, 0xee, 0x27}})
486
487#define UUID(str) []{ constexpr media_uuid_t uuid = constUUID(str); return uuid; }()
488
489} // namespace android
490
491#endif // MEDIA_EXTRACTOR_PLUGIN_HELPER_H_