blob: 2acc2bf6fd4255940f917be64e15ed3d32d84cb4 [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>
23#include <vector>
24
25#include <utils/Errors.h>
26#include <utils/Log.h>
27#include <utils/RefBase.h>
28#include <media/MediaExtractorPluginApi.h>
29
30namespace android {
31
32class DataSourceBase;
33class MetaDataBase;
34struct MediaTrack;
35
Marco Nelissen2a3363a2018-09-13 13:15:30 -070036
37class MediaTrackHelper {
38public:
39 virtual ~MediaTrackHelper() {};
40 virtual status_t start(MetaDataBase *params = NULL) = 0;
41 virtual status_t stop() = 0;
42 virtual status_t getFormat(MetaDataBase& format) = 0;
43
44 class ReadOptions {
45 public:
46 enum SeekMode : int32_t {
47 SEEK_PREVIOUS_SYNC,
48 SEEK_NEXT_SYNC,
49 SEEK_CLOSEST_SYNC,
50 SEEK_CLOSEST,
51 SEEK_FRAME_INDEX,
52 };
53
54 ReadOptions(uint32_t options, int64_t seekPosUs) {
55 mOptions = options;
56 mSeekPosUs = seekPosUs;
57 }
58 bool getSeekTo(int64_t *time_us, SeekMode *mode) const {
59 if ((mOptions & CMediaTrackReadOptions::SEEK) == 0) {
60 return false;
61 }
62 *time_us = mSeekPosUs;
63 *mode = (SeekMode) (mOptions & 7);
64 return true;
65 }
66 bool getNonBlocking() const {
67 return mOptions & CMediaTrackReadOptions::NONBLOCKING;
68 }
69 private:
70 uint32_t mOptions;
71 int64_t mSeekPosUs;
72 };
73
74 virtual status_t read(
75 MediaBufferBase **buffer, const ReadOptions *options = NULL) = 0;
76 virtual bool supportsNonBlockingRead() { return false; }
77};
78
79inline CMediaTrack *wrap(MediaTrackHelper *track) {
80 CMediaTrack *wrapper = (CMediaTrack*) malloc(sizeof(CMediaTrack));
81 wrapper->data = track;
82 wrapper->free = [](void *data) -> void {
83 delete (MediaTrackHelper*)(data);
84 };
85 wrapper->start = [](void *data, MetaDataBase *params) -> status_t {
86 return ((MediaTrackHelper*)data)->start(params);
87 };
88 wrapper->stop = [](void *data) -> status_t {
89 return ((MediaTrackHelper*)data)->stop();
90 };
91 wrapper->getFormat = [](void *data, MetaDataBase &meta) -> status_t {
92 return ((MediaTrackHelper*)data)->getFormat(meta);
93 };
94 wrapper->read = [](void *data, MediaBufferBase **buffer, uint32_t options, int64_t seekPosUs)
95 -> status_t {
96 MediaTrackHelper::ReadOptions opts(options, seekPosUs);
97 return ((MediaTrackHelper*)data)->read(buffer, &opts);
98 };
99 wrapper->supportsNonBlockingRead = [](void *data) -> bool {
100 return ((MediaTrackHelper*)data)->supportsNonBlockingRead();
101 };
102 return wrapper;
103}
104
Marco Nelissen56f19382018-09-12 15:30:59 -0700105
106class MediaTrackHelperV2 {
107public:
108 virtual ~MediaTrackHelperV2() {};
109 virtual status_t start(AMediaFormat *params = NULL) = 0;
110 virtual status_t stop() = 0;
111 virtual status_t getFormat(AMediaFormat *format) = 0;
112
113 class ReadOptions {
114 public:
115 enum SeekMode : int32_t {
116 SEEK_PREVIOUS_SYNC,
117 SEEK_NEXT_SYNC,
118 SEEK_CLOSEST_SYNC,
119 SEEK_CLOSEST,
120 SEEK_FRAME_INDEX,
121 };
122
123 ReadOptions(uint32_t options, int64_t seekPosUs) {
124 mOptions = options;
125 mSeekPosUs = seekPosUs;
126 }
127 bool getSeekTo(int64_t *time_us, SeekMode *mode) const {
128 if ((mOptions & CMediaTrackReadOptions::SEEK) == 0) {
129 return false;
130 }
131 *time_us = mSeekPosUs;
132 *mode = (SeekMode) (mOptions & 7);
133 return true;
134 }
135 bool getNonBlocking() const {
136 return mOptions & CMediaTrackReadOptions::NONBLOCKING;
137 }
138 private:
139 uint32_t mOptions;
140 int64_t mSeekPosUs;
141 };
142
143 virtual status_t read(
144 MediaBufferBase **buffer, const ReadOptions *options = NULL) = 0;
145 virtual bool supportsNonBlockingRead() { return false; }
146};
147
148inline CMediaTrackV2 *wrapV2(MediaTrackHelperV2 *track) {
149 CMediaTrackV2 *wrapper = (CMediaTrackV2*) malloc(sizeof(CMediaTrackV2));
150 wrapper->data = track;
151 wrapper->free = [](void *data) -> void {
152 delete (MediaTrackHelperV2*)(data);
153 };
154 wrapper->start = [](void *data, AMediaFormat *params) -> status_t {
155 return ((MediaTrackHelperV2*)data)->start(params);
156 };
157 wrapper->stop = [](void *data) -> status_t {
158 return ((MediaTrackHelperV2*)data)->stop();
159 };
160 wrapper->getFormat = [](void *data, AMediaFormat *meta) -> status_t {
161 return ((MediaTrackHelperV2*)data)->getFormat(meta);
162 };
163 wrapper->read = [](void *data, MediaBufferBase **buffer, uint32_t options, int64_t seekPosUs)
164 -> status_t {
165 MediaTrackHelperV2::ReadOptions opts(options, seekPosUs);
166 return ((MediaTrackHelperV2*)data)->read(buffer, &opts);
167 };
168 wrapper->supportsNonBlockingRead = [](void *data) -> bool {
169 return ((MediaTrackHelperV2*)data)->supportsNonBlockingRead();
170 };
171 return wrapper;
172}
173
174
175
Marco Nelissen0b164472018-05-30 12:16:56 -0700176// extractor plugins can derive from this class which looks remarkably
177// like MediaExtractor and can be easily wrapped in the required C API
178class MediaExtractorPluginHelper
179{
180public:
181 virtual ~MediaExtractorPluginHelper() {}
182 virtual size_t countTracks() = 0;
Marco Nelissen2a3363a2018-09-13 13:15:30 -0700183 virtual MediaTrackHelper *getTrack(size_t index) = 0;
Marco Nelissen0b164472018-05-30 12:16:56 -0700184
185 enum GetTrackMetaDataFlags {
186 kIncludeExtensiveMetaData = 1
187 };
188 virtual status_t getTrackMetaData(
189 MetaDataBase& meta,
190 size_t index, uint32_t flags = 0) = 0;
191
192 // Return container specific meta-data. The default implementation
193 // returns an empty metadata object.
194 virtual status_t getMetaData(MetaDataBase& meta) = 0;
195
196 enum Flags {
197 CAN_SEEK_BACKWARD = 1, // the "seek 10secs back button"
198 CAN_SEEK_FORWARD = 2, // the "seek 10secs forward button"
199 CAN_PAUSE = 4,
200 CAN_SEEK = 8, // the "seek bar"
201 };
202
203 // If subclasses do _not_ override this, the default is
204 // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
205 virtual uint32_t flags() const {
206 return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE;
207 };
208
209 virtual status_t setMediaCas(const uint8_t* /*casToken*/, size_t /*size*/) {
210 return INVALID_OPERATION;
211 }
212
213 virtual const char * name() { return "<unspecified>"; }
214
215protected:
216 MediaExtractorPluginHelper() {}
217
218private:
219 MediaExtractorPluginHelper(const MediaExtractorPluginHelper &);
220 MediaExtractorPluginHelper &operator=(const MediaExtractorPluginHelper &);
221};
222
223inline CMediaExtractor *wrap(MediaExtractorPluginHelper *extractor) {
224 CMediaExtractor *wrapper = (CMediaExtractor*) malloc(sizeof(CMediaExtractor));
225 wrapper->data = extractor;
226 wrapper->free = [](void *data) -> void {
227 delete (MediaExtractorPluginHelper*)(data);
228 };
229 wrapper->countTracks = [](void *data) -> size_t {
230 return ((MediaExtractorPluginHelper*)data)->countTracks();
231 };
Marco Nelissen2a3363a2018-09-13 13:15:30 -0700232 wrapper->getTrack = [](void *data, size_t index) -> CMediaTrack* {
233 return wrap(((MediaExtractorPluginHelper*)data)->getTrack(index));
Marco Nelissen0b164472018-05-30 12:16:56 -0700234 };
235 wrapper->getTrackMetaData = [](
236 void *data,
237 MetaDataBase& meta,
238 size_t index, uint32_t flags) -> status_t {
239 return ((MediaExtractorPluginHelper*)data)->getTrackMetaData(meta, index, flags);
240 };
241 wrapper->getMetaData = [](
242 void *data,
243 MetaDataBase& meta) -> status_t {
244 return ((MediaExtractorPluginHelper*)data)->getMetaData(meta);
245 };
246 wrapper->flags = [](
247 void *data) -> uint32_t {
248 return ((MediaExtractorPluginHelper*)data)->flags();
249 };
250 wrapper->setMediaCas = [](
251 void *data, const uint8_t *casToken, size_t size) -> status_t {
252 return ((MediaExtractorPluginHelper*)data)->setMediaCas(casToken, size);
253 };
254 wrapper->name = [](
255 void *data) -> const char * {
256 return ((MediaExtractorPluginHelper*)data)->name();
257 };
258 return wrapper;
259}
260
Marco Nelissen56f19382018-09-12 15:30:59 -0700261class MediaExtractorPluginHelperV2
262{
263public:
264 virtual ~MediaExtractorPluginHelperV2() {}
265 virtual size_t countTracks() = 0;
266 virtual MediaTrackHelperV2 *getTrack(size_t index) = 0;
267
268 enum GetTrackMetaDataFlags {
269 kIncludeExtensiveMetaData = 1
270 };
271 virtual status_t getTrackMetaData(
272 AMediaFormat *meta,
273 size_t index, uint32_t flags = 0) = 0;
274
275 // Return container specific meta-data. The default implementation
276 // returns an empty metadata object.
277 virtual status_t getMetaData(AMediaFormat *meta) = 0;
278
279 enum Flags {
280 CAN_SEEK_BACKWARD = 1, // the "seek 10secs back button"
281 CAN_SEEK_FORWARD = 2, // the "seek 10secs forward button"
282 CAN_PAUSE = 4,
283 CAN_SEEK = 8, // the "seek bar"
284 };
285
286 // If subclasses do _not_ override this, the default is
287 // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
288 virtual uint32_t flags() const {
289 return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE;
290 };
291
292 virtual status_t setMediaCas(const uint8_t* /*casToken*/, size_t /*size*/) {
293 return INVALID_OPERATION;
294 }
295
296 virtual const char * name() { return "<unspecified>"; }
297
298protected:
299 MediaExtractorPluginHelperV2() {}
300
301private:
302 MediaExtractorPluginHelperV2(const MediaExtractorPluginHelperV2 &);
303 MediaExtractorPluginHelperV2 &operator=(const MediaExtractorPluginHelperV2 &);
304};
305
306inline CMediaExtractorV2 *wrapV2(MediaExtractorPluginHelperV2 *extractor) {
307 CMediaExtractorV2 *wrapper = (CMediaExtractorV2*) malloc(sizeof(CMediaExtractorV2));
308 wrapper->data = extractor;
309 wrapper->free = [](void *data) -> void {
310 delete (MediaExtractorPluginHelperV2*)(data);
311 };
312 wrapper->countTracks = [](void *data) -> size_t {
313 return ((MediaExtractorPluginHelperV2*)data)->countTracks();
314 };
315 wrapper->getTrack = [](void *data, size_t index) -> CMediaTrackV2* {
316 return wrapV2(((MediaExtractorPluginHelperV2*)data)->getTrack(index));
317 };
318 wrapper->getTrackMetaData = [](
319 void *data,
320 AMediaFormat *meta,
321 size_t index, uint32_t flags) -> status_t {
322 return ((MediaExtractorPluginHelperV2*)data)->getTrackMetaData(meta, index, flags);
323 };
324 wrapper->getMetaData = [](
325 void *data,
326 AMediaFormat *meta) -> status_t {
327 return ((MediaExtractorPluginHelperV2*)data)->getMetaData(meta);
328 };
329 wrapper->flags = [](
330 void *data) -> uint32_t {
331 return ((MediaExtractorPluginHelperV2*)data)->flags();
332 };
333 wrapper->setMediaCas = [](
334 void *data, const uint8_t *casToken, size_t size) -> status_t {
335 return ((MediaExtractorPluginHelperV2*)data)->setMediaCas(casToken, size);
336 };
337 wrapper->name = [](
338 void *data) -> const char * {
339 return ((MediaExtractorPluginHelperV2*)data)->name();
340 };
341 return wrapper;
342}
343
Marco Nelissencec44d02018-06-17 22:21:09 -0700344/* adds some convience methods */
345class DataSourceHelper {
346public:
347 explicit DataSourceHelper(CDataSource *csource) {
348 mSource = csource;
349 }
350
351 explicit DataSourceHelper(DataSourceHelper *source) {
352 mSource = source->mSource;
353 }
354
Marco Nelissenc2b10b32018-09-24 13:19:43 -0700355 virtual ~DataSourceHelper() {}
356
357 virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
Marco Nelissencec44d02018-06-17 22:21:09 -0700358 return mSource->readAt(mSource->handle, offset, data, size);
359 }
360
Marco Nelissenc2b10b32018-09-24 13:19:43 -0700361 virtual status_t getSize(off64_t *size) {
Marco Nelissencec44d02018-06-17 22:21:09 -0700362 return mSource->getSize(mSource->handle, size);
363 }
364
365 bool getUri(char *uriString, size_t bufferSize) {
366 return mSource->getUri(mSource->handle, uriString, bufferSize);
367 }
368
Marco Nelissenc2b10b32018-09-24 13:19:43 -0700369 virtual uint32_t flags() {
Marco Nelissencec44d02018-06-17 22:21:09 -0700370 return mSource->flags(mSource->handle);
371 }
372
373 // Convenience methods:
374 bool getUInt16(off64_t offset, uint16_t *x) {
375 *x = 0;
376
377 uint8_t byte[2];
378 if (readAt(offset, byte, 2) != 2) {
379 return false;
380 }
381
382 *x = (byte[0] << 8) | byte[1];
383
384 return true;
385 }
386
387 // 3 byte int, returned as a 32-bit int
388 bool getUInt24(off64_t offset, uint32_t *x) {
389 *x = 0;
390
391 uint8_t byte[3];
392 if (readAt(offset, byte, 3) != 3) {
393 return false;
394 }
395
396 *x = (byte[0] << 16) | (byte[1] << 8) | byte[2];
397
398 return true;
399 }
400
401 bool getUInt32(off64_t offset, uint32_t *x) {
402 *x = 0;
403
404 uint32_t tmp;
405 if (readAt(offset, &tmp, 4) != 4) {
406 return false;
407 }
408
409 *x = ntohl(tmp);
410
411 return true;
412 }
413
414 bool getUInt64(off64_t offset, uint64_t *x) {
415 *x = 0;
416
417 uint64_t tmp;
418 if (readAt(offset, &tmp, 8) != 8) {
419 return false;
420 }
421
422 *x = ((uint64_t)ntohl(tmp & 0xffffffff) << 32) | ntohl(tmp >> 32);
423
424 return true;
425 }
426
427 // read either int<N> or int<2N> into a uint<2N>_t, size is the int size in bytes.
428 bool getUInt16Var(off64_t offset, uint16_t *x, size_t size) {
429 if (size == 2) {
430 return getUInt16(offset, x);
431 }
432 if (size == 1) {
433 uint8_t tmp;
434 if (readAt(offset, &tmp, 1) == 1) {
435 *x = tmp;
436 return true;
437 }
438 }
439 return false;
440 }
441
442 bool getUInt32Var(off64_t offset, uint32_t *x, size_t size) {
443 if (size == 4) {
444 return getUInt32(offset, x);
445 }
446 if (size == 2) {
447 uint16_t tmp;
448 if (getUInt16(offset, &tmp)) {
449 *x = tmp;
450 return true;
451 }
452 }
453 return false;
454 }
455
456 bool getUInt64Var(off64_t offset, uint64_t *x, size_t size) {
457 if (size == 8) {
458 return getUInt64(offset, x);
459 }
460 if (size == 4) {
461 uint32_t tmp;
462 if (getUInt32(offset, &tmp)) {
463 *x = tmp;
464 return true;
465 }
466 }
467 return false;
468 }
469
470protected:
471 CDataSource *mSource;
472};
473
474
475
Marco Nelissen0b164472018-05-30 12:16:56 -0700476// helpers to create a media_uuid_t from a string literal
477
478// purposely not defined anywhere so that this will fail to link if
479// expressions below are not evaluated at compile time
480int invalid_uuid_string(const char *);
481
482template <typename T, size_t N>
483constexpr uint8_t _digitAt_(const T (&s)[N], const size_t n) {
484 return s[n] >= '0' && s[n] <= '9' ? s[n] - '0'
485 : s[n] >= 'a' && s[n] <= 'f' ? s[n] - 'a' + 10
486 : s[n] >= 'A' && s[n] <= 'F' ? s[n] - 'A' + 10
487 : invalid_uuid_string("uuid: bad digits");
488}
489
490template <typename T, size_t N>
491constexpr uint8_t _hexByteAt_(const T (&s)[N], size_t n) {
492 return (_digitAt_(s, n) << 4) + _digitAt_(s, n + 1);
493}
494
495constexpr bool _assertIsDash_(char c) {
496 return c == '-' ? true : invalid_uuid_string("Wrong format");
497}
498
499template <size_t N>
500constexpr media_uuid_t constUUID(const char (&s) [N]) {
501 static_assert(N == 37, "uuid: wrong length");
502 return
503 _assertIsDash_(s[8]),
504 _assertIsDash_(s[13]),
505 _assertIsDash_(s[18]),
506 _assertIsDash_(s[23]),
507 media_uuid_t {{
508 _hexByteAt_(s, 0),
509 _hexByteAt_(s, 2),
510 _hexByteAt_(s, 4),
511 _hexByteAt_(s, 6),
512 _hexByteAt_(s, 9),
513 _hexByteAt_(s, 11),
514 _hexByteAt_(s, 14),
515 _hexByteAt_(s, 16),
516 _hexByteAt_(s, 19),
517 _hexByteAt_(s, 21),
518 _hexByteAt_(s, 24),
519 _hexByteAt_(s, 26),
520 _hexByteAt_(s, 28),
521 _hexByteAt_(s, 30),
522 _hexByteAt_(s, 32),
523 _hexByteAt_(s, 34),
524 }};
525}
526// Convenience macro to create a media_uuid_t from a string literal, which should
527// be formatted as "12345678-1234-1234-1234-123456789abc", as generated by
528// e.g. https://www.uuidgenerator.net/ or the 'uuidgen' linux command.
529// Hex digits may be upper or lower case.
530//
531// The macro call is otherwise equivalent to specifying the structure directly
532// (e.g. UUID("7d613858-5837-4a38-84c5-332d1cddee27") is the same as
533// {{0x7d, 0x61, 0x38, 0x58, 0x58, 0x37, 0x4a, 0x38,
534// 0x84, 0xc5, 0x33, 0x2d, 0x1c, 0xdd, 0xee, 0x27}})
535
536#define UUID(str) []{ constexpr media_uuid_t uuid = constUUID(str); return uuid; }()
537
538} // namespace android
539
540#endif // MEDIA_EXTRACTOR_PLUGIN_HELPER_H_