| Marco Nelissen | 0b16447 | 2018-05-30 12:16:56 -0700 | [diff] [blame] | 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 |  | 
| Marco Nelissen | cec44d0 | 2018-06-17 22:21:09 -0700 | [diff] [blame] | 21 | #include <arpa/inet.h> | 
| Marco Nelissen | 0b16447 | 2018-05-30 12:16:56 -0700 | [diff] [blame] | 22 | #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 |  | 
 | 30 | namespace android { | 
 | 31 |  | 
 | 32 | class DataSourceBase; | 
 | 33 | class MetaDataBase; | 
 | 34 | struct MediaTrack; | 
 | 35 |  | 
 | 36 | // extractor plugins can derive from this class which looks remarkably | 
 | 37 | // like MediaExtractor and can be easily wrapped in the required C API | 
 | 38 | class MediaExtractorPluginHelper | 
 | 39 | { | 
 | 40 | public: | 
 | 41 |     virtual ~MediaExtractorPluginHelper() {} | 
 | 42 |     virtual size_t countTracks() = 0; | 
 | 43 |     virtual MediaTrack *getTrack(size_t index) = 0; | 
 | 44 |  | 
 | 45 |     enum GetTrackMetaDataFlags { | 
 | 46 |         kIncludeExtensiveMetaData = 1 | 
 | 47 |     }; | 
 | 48 |     virtual status_t getTrackMetaData( | 
 | 49 |             MetaDataBase& meta, | 
 | 50 |             size_t index, uint32_t flags = 0) = 0; | 
 | 51 |  | 
 | 52 |     // Return container specific meta-data. The default implementation | 
 | 53 |     // returns an empty metadata object. | 
 | 54 |     virtual status_t getMetaData(MetaDataBase& meta) = 0; | 
 | 55 |  | 
 | 56 |     enum Flags { | 
 | 57 |         CAN_SEEK_BACKWARD  = 1,  // the "seek 10secs back button" | 
 | 58 |         CAN_SEEK_FORWARD   = 2,  // the "seek 10secs forward button" | 
 | 59 |         CAN_PAUSE          = 4, | 
 | 60 |         CAN_SEEK           = 8,  // the "seek bar" | 
 | 61 |     }; | 
 | 62 |  | 
 | 63 |     // If subclasses do _not_ override this, the default is | 
 | 64 |     // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE | 
 | 65 |     virtual uint32_t flags() const { | 
 | 66 |         return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE; | 
 | 67 |     }; | 
 | 68 |  | 
 | 69 |     virtual status_t setMediaCas(const uint8_t* /*casToken*/, size_t /*size*/) { | 
 | 70 |         return INVALID_OPERATION; | 
 | 71 |     } | 
 | 72 |  | 
 | 73 |     virtual const char * name() { return "<unspecified>"; } | 
 | 74 |  | 
 | 75 | protected: | 
 | 76 |     MediaExtractorPluginHelper() {} | 
 | 77 |  | 
 | 78 | private: | 
 | 79 |     MediaExtractorPluginHelper(const MediaExtractorPluginHelper &); | 
 | 80 |     MediaExtractorPluginHelper &operator=(const MediaExtractorPluginHelper &); | 
 | 81 | }; | 
 | 82 |  | 
 | 83 | inline CMediaExtractor *wrap(MediaExtractorPluginHelper *extractor) { | 
 | 84 |     CMediaExtractor *wrapper = (CMediaExtractor*) malloc(sizeof(CMediaExtractor)); | 
 | 85 |     wrapper->data = extractor; | 
 | 86 |     wrapper->free = [](void *data) -> void { | 
 | 87 |         delete (MediaExtractorPluginHelper*)(data); | 
 | 88 |     }; | 
 | 89 |     wrapper->countTracks = [](void *data) -> size_t { | 
 | 90 |         return ((MediaExtractorPluginHelper*)data)->countTracks(); | 
 | 91 |     }; | 
 | 92 |     wrapper->getTrack = [](void *data, size_t index) -> MediaTrack* { | 
 | 93 |         return ((MediaExtractorPluginHelper*)data)->getTrack(index); | 
 | 94 |     }; | 
 | 95 |     wrapper->getTrackMetaData = []( | 
 | 96 |             void *data, | 
 | 97 |             MetaDataBase& meta, | 
 | 98 |             size_t index, uint32_t flags) -> status_t { | 
 | 99 |         return ((MediaExtractorPluginHelper*)data)->getTrackMetaData(meta, index, flags); | 
 | 100 |     }; | 
 | 101 |     wrapper->getMetaData = []( | 
 | 102 |             void *data, | 
 | 103 |             MetaDataBase& meta) -> status_t { | 
 | 104 |         return ((MediaExtractorPluginHelper*)data)->getMetaData(meta); | 
 | 105 |     }; | 
 | 106 |     wrapper->flags = []( | 
 | 107 |             void *data) -> uint32_t { | 
 | 108 |         return ((MediaExtractorPluginHelper*)data)->flags(); | 
 | 109 |     }; | 
 | 110 |     wrapper->setMediaCas = []( | 
 | 111 |             void *data, const uint8_t *casToken, size_t size) -> status_t { | 
 | 112 |         return ((MediaExtractorPluginHelper*)data)->setMediaCas(casToken, size); | 
 | 113 |     }; | 
 | 114 |     wrapper->name = []( | 
 | 115 |             void *data) -> const char * { | 
 | 116 |         return ((MediaExtractorPluginHelper*)data)->name(); | 
 | 117 |     }; | 
 | 118 |     return wrapper; | 
 | 119 | } | 
 | 120 |  | 
| Marco Nelissen | cec44d0 | 2018-06-17 22:21:09 -0700 | [diff] [blame] | 121 | /* adds some convience methods */ | 
 | 122 | class DataSourceHelper { | 
 | 123 | public: | 
 | 124 |     explicit DataSourceHelper(CDataSource *csource) { | 
 | 125 |         mSource = csource; | 
 | 126 |     } | 
 | 127 |  | 
 | 128 |     explicit DataSourceHelper(DataSourceHelper *source) { | 
 | 129 |         mSource = source->mSource; | 
 | 130 |     } | 
 | 131 |  | 
| Marco Nelissen | c2b10b3 | 2018-09-24 13:19:43 -0700 | [diff] [blame^] | 132 |     virtual ~DataSourceHelper() {} | 
 | 133 |  | 
 | 134 |     virtual ssize_t readAt(off64_t offset, void *data, size_t size) { | 
| Marco Nelissen | cec44d0 | 2018-06-17 22:21:09 -0700 | [diff] [blame] | 135 |         return mSource->readAt(mSource->handle, offset, data, size); | 
 | 136 |     } | 
 | 137 |  | 
| Marco Nelissen | c2b10b3 | 2018-09-24 13:19:43 -0700 | [diff] [blame^] | 138 |     virtual status_t getSize(off64_t *size) { | 
| Marco Nelissen | cec44d0 | 2018-06-17 22:21:09 -0700 | [diff] [blame] | 139 |         return mSource->getSize(mSource->handle, size); | 
 | 140 |     } | 
 | 141 |  | 
 | 142 |     bool getUri(char *uriString, size_t bufferSize) { | 
 | 143 |         return mSource->getUri(mSource->handle, uriString, bufferSize); | 
 | 144 |     } | 
 | 145 |  | 
| Marco Nelissen | c2b10b3 | 2018-09-24 13:19:43 -0700 | [diff] [blame^] | 146 |     virtual uint32_t flags() { | 
| Marco Nelissen | cec44d0 | 2018-06-17 22:21:09 -0700 | [diff] [blame] | 147 |         return mSource->flags(mSource->handle); | 
 | 148 |     } | 
 | 149 |  | 
 | 150 |     // Convenience methods: | 
 | 151 |     bool getUInt16(off64_t offset, uint16_t *x) { | 
 | 152 |         *x = 0; | 
 | 153 |  | 
 | 154 |         uint8_t byte[2]; | 
 | 155 |         if (readAt(offset, byte, 2) != 2) { | 
 | 156 |             return false; | 
 | 157 |         } | 
 | 158 |  | 
 | 159 |         *x = (byte[0] << 8) | byte[1]; | 
 | 160 |  | 
 | 161 |         return true; | 
 | 162 |     } | 
 | 163 |  | 
 | 164 |     // 3 byte int, returned as a 32-bit int | 
 | 165 |     bool getUInt24(off64_t offset, uint32_t *x) { | 
 | 166 |         *x = 0; | 
 | 167 |  | 
 | 168 |         uint8_t byte[3]; | 
 | 169 |         if (readAt(offset, byte, 3) != 3) { | 
 | 170 |             return false; | 
 | 171 |         } | 
 | 172 |  | 
 | 173 |         *x = (byte[0] << 16) | (byte[1] << 8) | byte[2]; | 
 | 174 |  | 
 | 175 |         return true; | 
 | 176 |     } | 
 | 177 |  | 
 | 178 |     bool getUInt32(off64_t offset, uint32_t *x) { | 
 | 179 |         *x = 0; | 
 | 180 |  | 
 | 181 |         uint32_t tmp; | 
 | 182 |         if (readAt(offset, &tmp, 4) != 4) { | 
 | 183 |             return false; | 
 | 184 |         } | 
 | 185 |  | 
 | 186 |         *x = ntohl(tmp); | 
 | 187 |  | 
 | 188 |         return true; | 
 | 189 |     } | 
 | 190 |  | 
 | 191 |     bool getUInt64(off64_t offset, uint64_t *x) { | 
 | 192 |         *x = 0; | 
 | 193 |  | 
 | 194 |         uint64_t tmp; | 
 | 195 |         if (readAt(offset, &tmp, 8) != 8) { | 
 | 196 |             return false; | 
 | 197 |         } | 
 | 198 |  | 
 | 199 |         *x = ((uint64_t)ntohl(tmp & 0xffffffff) << 32) | ntohl(tmp >> 32); | 
 | 200 |  | 
 | 201 |         return true; | 
 | 202 |     } | 
 | 203 |  | 
 | 204 |     // read either int<N> or int<2N> into a uint<2N>_t, size is the int size in bytes. | 
 | 205 |     bool getUInt16Var(off64_t offset, uint16_t *x, size_t size) { | 
 | 206 |         if (size == 2) { | 
 | 207 |             return getUInt16(offset, x); | 
 | 208 |         } | 
 | 209 |         if (size == 1) { | 
 | 210 |             uint8_t tmp; | 
 | 211 |             if (readAt(offset, &tmp, 1) == 1) { | 
 | 212 |                 *x = tmp; | 
 | 213 |                 return true; | 
 | 214 |             } | 
 | 215 |         } | 
 | 216 |         return false; | 
 | 217 |     } | 
 | 218 |  | 
 | 219 |     bool getUInt32Var(off64_t offset, uint32_t *x, size_t size) { | 
 | 220 |         if (size == 4) { | 
 | 221 |             return getUInt32(offset, x); | 
 | 222 |         } | 
 | 223 |         if (size == 2) { | 
 | 224 |             uint16_t tmp; | 
 | 225 |             if (getUInt16(offset, &tmp)) { | 
 | 226 |                 *x = tmp; | 
 | 227 |                 return true; | 
 | 228 |             } | 
 | 229 |         } | 
 | 230 |         return false; | 
 | 231 |     } | 
 | 232 |  | 
 | 233 |     bool getUInt64Var(off64_t offset, uint64_t *x, size_t size) { | 
 | 234 |         if (size == 8) { | 
 | 235 |             return getUInt64(offset, x); | 
 | 236 |         } | 
 | 237 |         if (size == 4) { | 
 | 238 |             uint32_t tmp; | 
 | 239 |             if (getUInt32(offset, &tmp)) { | 
 | 240 |                 *x = tmp; | 
 | 241 |                 return true; | 
 | 242 |             } | 
 | 243 |         } | 
 | 244 |         return false; | 
 | 245 |     } | 
 | 246 |  | 
 | 247 | protected: | 
 | 248 |     CDataSource *mSource; | 
 | 249 | }; | 
 | 250 |  | 
 | 251 |  | 
 | 252 |  | 
| Marco Nelissen | 0b16447 | 2018-05-30 12:16:56 -0700 | [diff] [blame] | 253 | // helpers to create a media_uuid_t from a string literal | 
 | 254 |  | 
 | 255 | // purposely not defined anywhere so that this will fail to link if | 
 | 256 | // expressions below are not evaluated at compile time | 
 | 257 | int invalid_uuid_string(const char *); | 
 | 258 |  | 
 | 259 | template <typename T, size_t N> | 
 | 260 | constexpr uint8_t _digitAt_(const T (&s)[N], const size_t n) { | 
 | 261 |     return s[n] >= '0' && s[n] <= '9' ? s[n] - '0' | 
 | 262 |             : s[n] >= 'a' && s[n] <= 'f' ? s[n] - 'a' + 10 | 
 | 263 |                     : s[n] >= 'A' && s[n] <= 'F' ? s[n] - 'A' + 10 | 
 | 264 |                             : invalid_uuid_string("uuid: bad digits"); | 
 | 265 | } | 
 | 266 |  | 
 | 267 | template <typename T, size_t N> | 
 | 268 | constexpr uint8_t _hexByteAt_(const T (&s)[N], size_t n) { | 
 | 269 |     return (_digitAt_(s, n) << 4) + _digitAt_(s, n + 1); | 
 | 270 | } | 
 | 271 |  | 
 | 272 | constexpr bool _assertIsDash_(char c) { | 
 | 273 |     return c == '-' ? true : invalid_uuid_string("Wrong format"); | 
 | 274 | } | 
 | 275 |  | 
 | 276 | template <size_t N> | 
 | 277 | constexpr media_uuid_t constUUID(const char (&s) [N]) { | 
 | 278 |     static_assert(N == 37, "uuid: wrong length"); | 
 | 279 |     return | 
 | 280 |             _assertIsDash_(s[8]), | 
 | 281 |             _assertIsDash_(s[13]), | 
 | 282 |             _assertIsDash_(s[18]), | 
 | 283 |             _assertIsDash_(s[23]), | 
 | 284 |             media_uuid_t {{ | 
 | 285 |                 _hexByteAt_(s, 0), | 
 | 286 |                 _hexByteAt_(s, 2), | 
 | 287 |                 _hexByteAt_(s, 4), | 
 | 288 |                 _hexByteAt_(s, 6), | 
 | 289 |                 _hexByteAt_(s, 9), | 
 | 290 |                 _hexByteAt_(s, 11), | 
 | 291 |                 _hexByteAt_(s, 14), | 
 | 292 |                 _hexByteAt_(s, 16), | 
 | 293 |                 _hexByteAt_(s, 19), | 
 | 294 |                 _hexByteAt_(s, 21), | 
 | 295 |                 _hexByteAt_(s, 24), | 
 | 296 |                 _hexByteAt_(s, 26), | 
 | 297 |                 _hexByteAt_(s, 28), | 
 | 298 |                 _hexByteAt_(s, 30), | 
 | 299 |                 _hexByteAt_(s, 32), | 
 | 300 |                 _hexByteAt_(s, 34), | 
 | 301 |             }}; | 
 | 302 | } | 
 | 303 | // Convenience macro to create a media_uuid_t from a string literal, which should | 
 | 304 | // be formatted as "12345678-1234-1234-1234-123456789abc", as generated by | 
 | 305 | // e.g. https://www.uuidgenerator.net/ or the 'uuidgen' linux command. | 
 | 306 | // Hex digits may be upper or lower case. | 
 | 307 | // | 
 | 308 | // The macro call is otherwise equivalent to specifying the structure directly | 
 | 309 | // (e.g. UUID("7d613858-5837-4a38-84c5-332d1cddee27") is the same as | 
 | 310 | //       {{0x7d, 0x61, 0x38, 0x58, 0x58, 0x37, 0x4a, 0x38, | 
 | 311 | //         0x84, 0xc5, 0x33, 0x2d, 0x1c, 0xdd, 0xee, 0x27}}) | 
 | 312 |  | 
 | 313 | #define UUID(str) []{ constexpr media_uuid_t uuid = constUUID(str); return uuid; }() | 
 | 314 |  | 
 | 315 | }  // namespace android | 
 | 316 |  | 
 | 317 | #endif  // MEDIA_EXTRACTOR_PLUGIN_HELPER_H_ |