blob: 961033bc941503dc4ac136354ba1601bdeadd981 [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 Nelissen0b164472018-05-30 12:16:56 -0700105// extractor plugins can derive from this class which looks remarkably
106// like MediaExtractor and can be easily wrapped in the required C API
107class MediaExtractorPluginHelper
108{
109public:
110 virtual ~MediaExtractorPluginHelper() {}
111 virtual size_t countTracks() = 0;
Marco Nelissen2a3363a2018-09-13 13:15:30 -0700112 virtual MediaTrackHelper *getTrack(size_t index) = 0;
Marco Nelissen0b164472018-05-30 12:16:56 -0700113
114 enum GetTrackMetaDataFlags {
115 kIncludeExtensiveMetaData = 1
116 };
117 virtual status_t getTrackMetaData(
118 MetaDataBase& meta,
119 size_t index, uint32_t flags = 0) = 0;
120
121 // Return container specific meta-data. The default implementation
122 // returns an empty metadata object.
123 virtual status_t getMetaData(MetaDataBase& meta) = 0;
124
125 enum Flags {
126 CAN_SEEK_BACKWARD = 1, // the "seek 10secs back button"
127 CAN_SEEK_FORWARD = 2, // the "seek 10secs forward button"
128 CAN_PAUSE = 4,
129 CAN_SEEK = 8, // the "seek bar"
130 };
131
132 // If subclasses do _not_ override this, the default is
133 // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
134 virtual uint32_t flags() const {
135 return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE;
136 };
137
138 virtual status_t setMediaCas(const uint8_t* /*casToken*/, size_t /*size*/) {
139 return INVALID_OPERATION;
140 }
141
142 virtual const char * name() { return "<unspecified>"; }
143
144protected:
145 MediaExtractorPluginHelper() {}
146
147private:
148 MediaExtractorPluginHelper(const MediaExtractorPluginHelper &);
149 MediaExtractorPluginHelper &operator=(const MediaExtractorPluginHelper &);
150};
151
152inline CMediaExtractor *wrap(MediaExtractorPluginHelper *extractor) {
153 CMediaExtractor *wrapper = (CMediaExtractor*) malloc(sizeof(CMediaExtractor));
154 wrapper->data = extractor;
155 wrapper->free = [](void *data) -> void {
156 delete (MediaExtractorPluginHelper*)(data);
157 };
158 wrapper->countTracks = [](void *data) -> size_t {
159 return ((MediaExtractorPluginHelper*)data)->countTracks();
160 };
Marco Nelissen2a3363a2018-09-13 13:15:30 -0700161 wrapper->getTrack = [](void *data, size_t index) -> CMediaTrack* {
162 return wrap(((MediaExtractorPluginHelper*)data)->getTrack(index));
Marco Nelissen0b164472018-05-30 12:16:56 -0700163 };
164 wrapper->getTrackMetaData = [](
165 void *data,
166 MetaDataBase& meta,
167 size_t index, uint32_t flags) -> status_t {
168 return ((MediaExtractorPluginHelper*)data)->getTrackMetaData(meta, index, flags);
169 };
170 wrapper->getMetaData = [](
171 void *data,
172 MetaDataBase& meta) -> status_t {
173 return ((MediaExtractorPluginHelper*)data)->getMetaData(meta);
174 };
175 wrapper->flags = [](
176 void *data) -> uint32_t {
177 return ((MediaExtractorPluginHelper*)data)->flags();
178 };
179 wrapper->setMediaCas = [](
180 void *data, const uint8_t *casToken, size_t size) -> status_t {
181 return ((MediaExtractorPluginHelper*)data)->setMediaCas(casToken, size);
182 };
183 wrapper->name = [](
184 void *data) -> const char * {
185 return ((MediaExtractorPluginHelper*)data)->name();
186 };
187 return wrapper;
188}
189
Marco Nelissencec44d02018-06-17 22:21:09 -0700190/* adds some convience methods */
191class DataSourceHelper {
192public:
193 explicit DataSourceHelper(CDataSource *csource) {
194 mSource = csource;
195 }
196
197 explicit DataSourceHelper(DataSourceHelper *source) {
198 mSource = source->mSource;
199 }
200
Marco Nelissenc2b10b32018-09-24 13:19:43 -0700201 virtual ~DataSourceHelper() {}
202
203 virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
Marco Nelissencec44d02018-06-17 22:21:09 -0700204 return mSource->readAt(mSource->handle, offset, data, size);
205 }
206
Marco Nelissenc2b10b32018-09-24 13:19:43 -0700207 virtual status_t getSize(off64_t *size) {
Marco Nelissencec44d02018-06-17 22:21:09 -0700208 return mSource->getSize(mSource->handle, size);
209 }
210
211 bool getUri(char *uriString, size_t bufferSize) {
212 return mSource->getUri(mSource->handle, uriString, bufferSize);
213 }
214
Marco Nelissenc2b10b32018-09-24 13:19:43 -0700215 virtual uint32_t flags() {
Marco Nelissencec44d02018-06-17 22:21:09 -0700216 return mSource->flags(mSource->handle);
217 }
218
219 // Convenience methods:
220 bool getUInt16(off64_t offset, uint16_t *x) {
221 *x = 0;
222
223 uint8_t byte[2];
224 if (readAt(offset, byte, 2) != 2) {
225 return false;
226 }
227
228 *x = (byte[0] << 8) | byte[1];
229
230 return true;
231 }
232
233 // 3 byte int, returned as a 32-bit int
234 bool getUInt24(off64_t offset, uint32_t *x) {
235 *x = 0;
236
237 uint8_t byte[3];
238 if (readAt(offset, byte, 3) != 3) {
239 return false;
240 }
241
242 *x = (byte[0] << 16) | (byte[1] << 8) | byte[2];
243
244 return true;
245 }
246
247 bool getUInt32(off64_t offset, uint32_t *x) {
248 *x = 0;
249
250 uint32_t tmp;
251 if (readAt(offset, &tmp, 4) != 4) {
252 return false;
253 }
254
255 *x = ntohl(tmp);
256
257 return true;
258 }
259
260 bool getUInt64(off64_t offset, uint64_t *x) {
261 *x = 0;
262
263 uint64_t tmp;
264 if (readAt(offset, &tmp, 8) != 8) {
265 return false;
266 }
267
268 *x = ((uint64_t)ntohl(tmp & 0xffffffff) << 32) | ntohl(tmp >> 32);
269
270 return true;
271 }
272
273 // read either int<N> or int<2N> into a uint<2N>_t, size is the int size in bytes.
274 bool getUInt16Var(off64_t offset, uint16_t *x, size_t size) {
275 if (size == 2) {
276 return getUInt16(offset, x);
277 }
278 if (size == 1) {
279 uint8_t tmp;
280 if (readAt(offset, &tmp, 1) == 1) {
281 *x = tmp;
282 return true;
283 }
284 }
285 return false;
286 }
287
288 bool getUInt32Var(off64_t offset, uint32_t *x, size_t size) {
289 if (size == 4) {
290 return getUInt32(offset, x);
291 }
292 if (size == 2) {
293 uint16_t tmp;
294 if (getUInt16(offset, &tmp)) {
295 *x = tmp;
296 return true;
297 }
298 }
299 return false;
300 }
301
302 bool getUInt64Var(off64_t offset, uint64_t *x, size_t size) {
303 if (size == 8) {
304 return getUInt64(offset, x);
305 }
306 if (size == 4) {
307 uint32_t tmp;
308 if (getUInt32(offset, &tmp)) {
309 *x = tmp;
310 return true;
311 }
312 }
313 return false;
314 }
315
316protected:
317 CDataSource *mSource;
318};
319
320
321
Marco Nelissen0b164472018-05-30 12:16:56 -0700322// helpers to create a media_uuid_t from a string literal
323
324// purposely not defined anywhere so that this will fail to link if
325// expressions below are not evaluated at compile time
326int invalid_uuid_string(const char *);
327
328template <typename T, size_t N>
329constexpr uint8_t _digitAt_(const T (&s)[N], const size_t n) {
330 return s[n] >= '0' && s[n] <= '9' ? s[n] - '0'
331 : s[n] >= 'a' && s[n] <= 'f' ? s[n] - 'a' + 10
332 : s[n] >= 'A' && s[n] <= 'F' ? s[n] - 'A' + 10
333 : invalid_uuid_string("uuid: bad digits");
334}
335
336template <typename T, size_t N>
337constexpr uint8_t _hexByteAt_(const T (&s)[N], size_t n) {
338 return (_digitAt_(s, n) << 4) + _digitAt_(s, n + 1);
339}
340
341constexpr bool _assertIsDash_(char c) {
342 return c == '-' ? true : invalid_uuid_string("Wrong format");
343}
344
345template <size_t N>
346constexpr media_uuid_t constUUID(const char (&s) [N]) {
347 static_assert(N == 37, "uuid: wrong length");
348 return
349 _assertIsDash_(s[8]),
350 _assertIsDash_(s[13]),
351 _assertIsDash_(s[18]),
352 _assertIsDash_(s[23]),
353 media_uuid_t {{
354 _hexByteAt_(s, 0),
355 _hexByteAt_(s, 2),
356 _hexByteAt_(s, 4),
357 _hexByteAt_(s, 6),
358 _hexByteAt_(s, 9),
359 _hexByteAt_(s, 11),
360 _hexByteAt_(s, 14),
361 _hexByteAt_(s, 16),
362 _hexByteAt_(s, 19),
363 _hexByteAt_(s, 21),
364 _hexByteAt_(s, 24),
365 _hexByteAt_(s, 26),
366 _hexByteAt_(s, 28),
367 _hexByteAt_(s, 30),
368 _hexByteAt_(s, 32),
369 _hexByteAt_(s, 34),
370 }};
371}
372// Convenience macro to create a media_uuid_t from a string literal, which should
373// be formatted as "12345678-1234-1234-1234-123456789abc", as generated by
374// e.g. https://www.uuidgenerator.net/ or the 'uuidgen' linux command.
375// Hex digits may be upper or lower case.
376//
377// The macro call is otherwise equivalent to specifying the structure directly
378// (e.g. UUID("7d613858-5837-4a38-84c5-332d1cddee27") is the same as
379// {{0x7d, 0x61, 0x38, 0x58, 0x58, 0x37, 0x4a, 0x38,
380// 0x84, 0xc5, 0x33, 0x2d, 0x1c, 0xdd, 0xee, 0x27}})
381
382#define UUID(str) []{ constexpr media_uuid_t uuid = constUUID(str); return uuid; }()
383
384} // namespace android
385
386#endif // MEDIA_EXTRACTOR_PLUGIN_HELPER_H_