1 /*
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
21 #include <arpa/inet.h>
22 #include <stdio.h>
23 #include <map>
24
25 #include <utils/Errors.h>
26 #include <utils/Log.h>
27 #include <utils/RefBase.h>
28 #include <media/MediaExtractorPluginApi.h>
29 #include <media/NdkMediaFormat.h>
30
31 namespace android {
32
33 class DataSourceBase;
34 class MetaDataBase;
35 struct MediaTrack;
36
37
38 class MediaTrackHelper;
39
40 class MediaBufferHelper {
41 private:
42 friend CMediaTrack *wrap(MediaTrackHelper *);
43 CMediaBuffer *mBuffer;
44 public:
MediaBufferHelper(CMediaBuffer * buf)45 MediaBufferHelper(CMediaBuffer *buf) {
46 mBuffer = buf;
47 }
48
~MediaBufferHelper()49 virtual ~MediaBufferHelper() {}
50
release()51 virtual void release() {
52 mBuffer->release(mBuffer->handle);
53 }
54
data()55 virtual void* data() {
56 return mBuffer->data(mBuffer->handle);
57 }
58
size()59 virtual size_t size() {
60 return mBuffer->size(mBuffer->handle);
61 }
62
range_offset()63 virtual size_t range_offset() {
64 return mBuffer->range_offset(mBuffer->handle);
65 }
66
range_length()67 virtual size_t range_length() {
68 return mBuffer->range_length(mBuffer->handle);
69 }
70
set_range(size_t offset,size_t length)71 virtual void set_range(size_t offset, size_t length) {
72 mBuffer->set_range(mBuffer->handle, offset, length);
73 }
meta_data()74 virtual AMediaFormat *meta_data() {
75 return mBuffer->meta_data(mBuffer->handle);
76 }
77 };
78
79 class MediaBufferGroupHelper {
80 private:
81 CMediaBufferGroup *mGroup;
82 std::map<CMediaBuffer*, MediaBufferHelper*> mBufferHelpers;
83 public:
MediaBufferGroupHelper(CMediaBufferGroup * group)84 MediaBufferGroupHelper(CMediaBufferGroup *group) {
85 mGroup = group;
86 }
~MediaBufferGroupHelper()87 ~MediaBufferGroupHelper() {
88 // 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 }
add_buffer(size_t size)97 void add_buffer(size_t size) {
98 mGroup->add_buffer(mGroup->handle, size);
99 }
100 media_status_t acquire_buffer(
101 MediaBufferHelper **buffer, bool nonBlocking = false, size_t requestedSize = 0) {
102 CMediaBuffer *buf = nullptr;
103 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()) {
108 MediaBufferHelper* newHelper = new MediaBufferHelper(buf);
109 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 }
has_buffers()119 bool has_buffers() {
120 return mGroup->has_buffers(mGroup->handle);
121 }
122 };
123
124 class MediaTrackHelper {
125 public:
MediaTrackHelper()126 MediaTrackHelper() : mBufferGroup(nullptr) {
127 }
~MediaTrackHelper()128 virtual ~MediaTrackHelper() {
129 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
ReadOptions(uint32_t options,int64_t seekPosUs)145 ReadOptions(uint32_t options, int64_t seekPosUs) {
146 mOptions = options;
147 mSeekPosUs = seekPosUs;
148 }
getSeekTo(int64_t * time_us,SeekMode * mode)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 }
getNonBlocking()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(
166 MediaBufferHelper **buffer, const ReadOptions *options = NULL) = 0;
supportsNonBlockingRead()167 virtual bool supportsNonBlockingRead() { return false; }
168 protected:
169 friend CMediaTrack *wrap(MediaTrackHelper *track);
170 MediaBufferGroupHelper *mBufferGroup;
171 };
172
wrap(MediaTrackHelper * track)173 inline CMediaTrack *wrap(MediaTrackHelper *track) {
174 if (track == nullptr) {
175 return nullptr;
176 }
177 CMediaTrack *wrapper = (CMediaTrack*) malloc(sizeof(CMediaTrack));
178 wrapper->data = track;
179 wrapper->free = [](void *data) -> void {
180 delete (MediaTrackHelper*)(data);
181 };
182 wrapper->start = [](void *data, CMediaBufferGroup *bufferGroup) -> media_status_t {
183 if (((MediaTrackHelper*)data)->mBufferGroup) {
184 // this shouldn't happen, but handle it anyway
185 delete ((MediaTrackHelper*)data)->mBufferGroup;
186 }
187 ((MediaTrackHelper*)data)->mBufferGroup = new MediaBufferGroupHelper(bufferGroup);
188 return ((MediaTrackHelper*)data)->start();
189 };
190 wrapper->stop = [](void *data) -> media_status_t {
191 return ((MediaTrackHelper*)data)->stop();
192 };
193 wrapper->getFormat = [](void *data, AMediaFormat *meta) -> media_status_t {
194 return ((MediaTrackHelper*)data)->getFormat(meta);
195 };
196 wrapper->read = [](void *data, CMediaBuffer **buffer, uint32_t options, int64_t seekPosUs)
197 -> media_status_t {
198 MediaTrackHelper::ReadOptions opts(options, seekPosUs);
199 MediaBufferHelper *buf = NULL;
200 media_status_t ret = ((MediaTrackHelper*)data)->read(&buf, &opts);
201 if (ret == AMEDIA_OK && buf != nullptr) {
202 *buffer = buf->mBuffer;
203 }
204 return ret;
205 };
206 wrapper->supportsNonBlockingRead = [](void *data) -> bool {
207 return ((MediaTrackHelper*)data)->supportsNonBlockingRead();
208 };
209 return wrapper;
210 }
211
212
213 // extractor plugins can derive from this class which looks remarkably
214 // like MediaExtractor and can be easily wrapped in the required C API
215 class MediaExtractorPluginHelper
216 {
217 public:
~MediaExtractorPluginHelper()218 virtual ~MediaExtractorPluginHelper() {}
219 virtual size_t countTracks() = 0;
220 virtual MediaTrackHelper *getTrack(size_t index) = 0;
221
222 enum GetTrackMetaDataFlags {
223 kIncludeExtensiveMetaData = 1
224 };
225 virtual media_status_t getTrackMetaData(
226 AMediaFormat *meta,
227 size_t index, uint32_t flags = 0) = 0;
228
229 // Return container specific meta-data. The default implementation
230 // returns an empty metadata object.
231 virtual media_status_t getMetaData(AMediaFormat *meta) = 0;
232
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
flags()242 virtual uint32_t flags() const {
243 return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE;
244 };
245
setMediaCas(const uint8_t *,size_t)246 virtual media_status_t setMediaCas(const uint8_t* /*casToken*/, size_t /*size*/) {
247 return AMEDIA_ERROR_INVALID_OPERATION;
248 }
249
name()250 virtual const char * name() { return "<unspecified>"; }
251
252 protected:
MediaExtractorPluginHelper()253 MediaExtractorPluginHelper() {}
254
255 private:
256 MediaExtractorPluginHelper(const MediaExtractorPluginHelper &);
257 MediaExtractorPluginHelper &operator=(const MediaExtractorPluginHelper &);
258 };
259
wrap(MediaExtractorPluginHelper * extractor)260 inline 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 };
269 wrapper->getTrack = [](void *data, size_t index) -> CMediaTrack* {
270 return wrap(((MediaExtractorPluginHelper*)data)->getTrack(index));
271 };
272 wrapper->getTrackMetaData = [](
273 void *data,
274 AMediaFormat *meta,
275 size_t index, uint32_t flags) -> media_status_t {
276 return ((MediaExtractorPluginHelper*)data)->getTrackMetaData(meta, index, flags);
277 };
278 wrapper->getMetaData = [](
279 void *data,
280 AMediaFormat *meta) -> media_status_t {
281 return ((MediaExtractorPluginHelper*)data)->getMetaData(meta);
282 };
283 wrapper->flags = [](
284 void *data) -> uint32_t {
285 return ((MediaExtractorPluginHelper*)data)->flags();
286 };
287 wrapper->setMediaCas = [](
288 void *data, const uint8_t *casToken, size_t size) -> media_status_t {
289 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
298 /* adds some convience methods */
299 class DataSourceHelper {
300 public:
DataSourceHelper(CDataSource * csource)301 explicit DataSourceHelper(CDataSource *csource) {
302 mSource = csource;
303 }
304
DataSourceHelper(DataSourceHelper * source)305 explicit DataSourceHelper(DataSourceHelper *source) {
306 mSource = source->mSource;
307 }
308
~DataSourceHelper()309 virtual ~DataSourceHelper() {}
310
readAt(off64_t offset,void * data,size_t size)311 virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
312 return mSource->readAt(mSource->handle, offset, data, size);
313 }
314
getSize(off64_t * size)315 virtual status_t getSize(off64_t *size) {
316 return mSource->getSize(mSource->handle, size);
317 }
318
getUri(char * uriString,size_t bufferSize)319 bool getUri(char *uriString, size_t bufferSize) {
320 return mSource->getUri(mSource->handle, uriString, bufferSize);
321 }
322
flags()323 virtual uint32_t flags() {
324 return mSource->flags(mSource->handle);
325 }
326
327 // Convenience methods:
getUInt16(off64_t offset,uint16_t * x)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
getUInt24(off64_t offset,uint32_t * x)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
getUInt32(off64_t offset,uint32_t * x)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
getUInt64(off64_t offset,uint64_t * x)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.
getUInt16Var(off64_t offset,uint16_t * x,size_t size)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
getUInt32Var(off64_t offset,uint32_t * x,size_t size)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
getUInt64Var(off64_t offset,uint64_t * x,size_t size)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
424 protected:
425 CDataSource *mSource;
426 };
427
428
429
430 // 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
434 int invalid_uuid_string(const char *);
435
436 template <typename T, size_t N>
_digitAt_(const T (& s)[N],const size_t n)437 constexpr 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
444 template <typename T, size_t N>
_hexByteAt_(const T (& s)[N],size_t n)445 constexpr uint8_t _hexByteAt_(const T (&s)[N], size_t n) {
446 return (_digitAt_(s, n) << 4) + _digitAt_(s, n + 1);
447 }
448
_assertIsDash_(char c)449 constexpr bool _assertIsDash_(char c) {
450 return c == '-' ? true : invalid_uuid_string("Wrong format");
451 }
452
453 template <size_t N>
constUUID(const char (& s)[N])454 constexpr 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_
495