Home | History | Annotate | Download | only in media
      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