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: 45 MediaBufferHelper(CMediaBuffer *buf) { 46 mBuffer = buf; 47 } 48 49 virtual ~MediaBufferHelper() {} 50 51 virtual void release() { 52 mBuffer->release(mBuffer->handle); 53 } 54 55 virtual void* data() { 56 return mBuffer->data(mBuffer->handle); 57 } 58 59 virtual size_t size() { 60 return mBuffer->size(mBuffer->handle); 61 } 62 63 virtual size_t range_offset() { 64 return mBuffer->range_offset(mBuffer->handle); 65 } 66 67 virtual size_t range_length() { 68 return mBuffer->range_length(mBuffer->handle); 69 } 70 71 virtual void set_range(size_t offset, size_t length) { 72 mBuffer->set_range(mBuffer->handle, offset, length); 73 } 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: 84 MediaBufferGroupHelper(CMediaBufferGroup *group) { 85 mGroup = group; 86 } 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 } 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 } 119 bool has_buffers() { 120 return mGroup->has_buffers(mGroup->handle); 121 } 122 }; 123 124 class MediaTrackHelper { 125 public: 126 MediaTrackHelper() : mBufferGroup(nullptr) { 127 } 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 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( 166 MediaBufferHelper **buffer, const ReadOptions *options = NULL) = 0; 167 virtual bool supportsNonBlockingRead() { return false; } 168 protected: 169 friend CMediaTrack *wrap(MediaTrackHelper *track); 170 MediaBufferGroupHelper *mBufferGroup; 171 }; 172 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: 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 242 virtual uint32_t flags() const { 243 return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE; 244 }; 245 246 virtual media_status_t setMediaCas(const uint8_t* /*casToken*/, size_t /*size*/) { 247 return AMEDIA_ERROR_INVALID_OPERATION; 248 } 249 250 virtual const char * name() { return "<unspecified>"; } 251 252 protected: 253 MediaExtractorPluginHelper() {} 254 255 private: 256 MediaExtractorPluginHelper(const MediaExtractorPluginHelper &); 257 MediaExtractorPluginHelper &operator=(const MediaExtractorPluginHelper &); 258 }; 259 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: 301 explicit DataSourceHelper(CDataSource *csource) { 302 mSource = csource; 303 } 304 305 explicit DataSourceHelper(DataSourceHelper *source) { 306 mSource = source->mSource; 307 } 308 309 virtual ~DataSourceHelper() {} 310 311 virtual ssize_t readAt(off64_t offset, void *data, size_t size) { 312 return mSource->readAt(mSource->handle, offset, data, size); 313 } 314 315 virtual status_t getSize(off64_t *size) { 316 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 323 virtual uint32_t flags() { 324 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 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> 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> 445 constexpr uint8_t _hexByteAt_(const T (&s)[N], size_t n) { 446 return (_digitAt_(s, n) << 4) + _digitAt_(s, n + 1); 447 } 448 449 constexpr bool _assertIsDash_(char c) { 450 return c == '-' ? true : invalid_uuid_string("Wrong format"); 451 } 452 453 template <size_t 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