MediaExtractor.cpp revision afb43f76821e6a63e17e6484289a40430ada6978
1/* 2 * Copyright (C) 2009 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//#define LOG_NDEBUG 0 18#define LOG_TAG "MediaExtractor" 19#include <utils/Log.h> 20#include <inttypes.h> 21#include <pwd.h> 22 23#include "include/AMRExtractor.h" 24#include "include/MP3Extractor.h" 25#include "include/MPEG4Extractor.h" 26#include "include/WAVExtractor.h" 27#include "include/OggExtractor.h" 28#include "include/MPEG2PSExtractor.h" 29#include "include/MPEG2TSExtractor.h" 30#include "include/FLACExtractor.h" 31#include "include/AACExtractor.h" 32#include "include/MidiExtractor.h" 33 34#include "matroska/MatroskaExtractor.h" 35 36#include <binder/IServiceManager.h> 37#include <binder/MemoryDealer.h> 38 39#include <media/MediaAnalyticsItem.h> 40#include <media/stagefright/foundation/ADebug.h> 41#include <media/stagefright/foundation/AMessage.h> 42#include <media/stagefright/DataSource.h> 43#include <media/stagefright/MediaDefs.h> 44#include <media/stagefright/MediaExtractor.h> 45#include <media/stagefright/MetaData.h> 46#include <media/IMediaExtractorService.h> 47#include <cutils/properties.h> 48#include <utils/String8.h> 49#include <private/android_filesystem_config.h> 50 51// still doing some on/off toggling here. 52#define MEDIA_LOG 1 53 54 55namespace android { 56 57// key for media statistics 58static const char *kKeyExtractor = "extractor"; 59// attrs for media statistics 60static const char *kExtractorMime = "android.media.mediaextractor.mime"; 61static const char *kExtractorTracks = "android.media.mediaextractor.ntrk"; 62static const char *kExtractorFormat = "android.media.mediaextractor.fmt"; 63 64MediaExtractor::MediaExtractor() { 65 if (!LOG_NDEBUG) { 66 uid_t uid = getuid(); 67 struct passwd *pw = getpwuid(uid); 68 ALOGI("extractor created in uid: %d (%s)", getuid(), pw->pw_name); 69 } 70 71 mAnalyticsItem = NULL; 72 if (MEDIA_LOG) { 73 mAnalyticsItem = new MediaAnalyticsItem(kKeyExtractor); 74 (void) mAnalyticsItem->generateSessionID(); 75 } 76} 77 78MediaExtractor::~MediaExtractor() { 79 80 // log the current record, provided it has some information worth recording 81 if (MEDIA_LOG) { 82 if (mAnalyticsItem != NULL) { 83 if (mAnalyticsItem->count() > 0) { 84 mAnalyticsItem->setFinalized(true); 85 mAnalyticsItem->selfrecord(); 86 } 87 } 88 } 89 if (mAnalyticsItem != NULL) { 90 delete mAnalyticsItem; 91 mAnalyticsItem = NULL; 92 } 93} 94 95sp<MetaData> MediaExtractor::getMetaData() { 96 return new MetaData; 97} 98 99status_t MediaExtractor::getMetrics(Parcel *reply) { 100 101 if (mAnalyticsItem == NULL || reply == NULL) { 102 return UNKNOWN_ERROR; 103 } 104 105 populateMetrics(); 106 mAnalyticsItem->writeToParcel(reply); 107 108 return OK; 109} 110 111void MediaExtractor::populateMetrics() { 112 ALOGV("MediaExtractor::populateMetrics"); 113 // normally overridden in subclasses 114} 115 116uint32_t MediaExtractor::flags() const { 117 return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK; 118} 119 120 121 122class RemoteDataSource : public BnDataSource { 123public: 124 enum { 125 kBufferSize = 64 * 1024, 126 }; 127 128 static sp<IDataSource> wrap(const sp<DataSource> &source); 129 virtual ~RemoteDataSource(); 130 131 virtual sp<IMemory> getIMemory(); 132 virtual ssize_t readAt(off64_t offset, size_t size); 133 virtual status_t getSize(off64_t* size); 134 virtual void close(); 135 virtual uint32_t getFlags(); 136 virtual String8 toString(); 137 virtual sp<DecryptHandle> DrmInitialization(const char *mime); 138 139private: 140 sp<IMemory> mMemory; 141 sp<DataSource> mSource; 142 String8 mName; 143 explicit RemoteDataSource(const sp<DataSource> &source); 144 DISALLOW_EVIL_CONSTRUCTORS(RemoteDataSource); 145}; 146 147 148sp<IDataSource> RemoteDataSource::wrap(const sp<DataSource> &source) { 149 return new RemoteDataSource(source); 150} 151RemoteDataSource::RemoteDataSource(const sp<DataSource> &source) { 152 mSource = source; 153 sp<MemoryDealer> memoryDealer = new MemoryDealer(kBufferSize, "RemoteDataSource"); 154 mMemory = memoryDealer->allocate(kBufferSize); 155 if (mMemory == NULL) { 156 ALOGE("Failed to allocate memory!"); 157 } 158 mName = String8::format("RemoteDataSource(%s)", mSource->toString().string()); 159} 160RemoteDataSource::~RemoteDataSource() { 161 close(); 162} 163sp<IMemory> RemoteDataSource::getIMemory() { 164 return mMemory; 165} 166ssize_t RemoteDataSource::readAt(off64_t offset, size_t size) { 167 ALOGV("readAt(%" PRId64 ", %zu)", offset, size); 168 return mSource->readAt(offset, mMemory->pointer(), size); 169} 170status_t RemoteDataSource::getSize(off64_t* size) { 171 return mSource->getSize(size); 172} 173void RemoteDataSource::close() { 174 mSource = NULL; 175} 176uint32_t RemoteDataSource::getFlags() { 177 return mSource->flags(); 178} 179 180String8 RemoteDataSource::toString() { 181 return mName; 182} 183 184sp<DecryptHandle> RemoteDataSource::DrmInitialization(const char *mime) { 185 return mSource->DrmInitialization(mime); 186} 187 188// static 189sp<IMediaExtractor> MediaExtractor::Create( 190 const sp<DataSource> &source, const char *mime) { 191 ALOGV("MediaExtractor::Create %s", mime); 192 193 if (!property_get_bool("media.stagefright.extractremote", true)) { 194 // local extractor 195 ALOGW("creating media extractor in calling process"); 196 return CreateFromService(source, mime); 197 } else { 198 // remote extractor 199 ALOGV("get service manager"); 200 sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor")); 201 202 if (binder != 0) { 203 sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder)); 204 sp<IMediaExtractor> ex = mediaExService->makeExtractor(RemoteDataSource::wrap(source), mime); 205 return ex; 206 } else { 207 ALOGE("extractor service not running"); 208 return NULL; 209 } 210 } 211 return NULL; 212} 213 214sp<MediaExtractor> MediaExtractor::CreateFromService( 215 const sp<DataSource> &source, const char *mime) { 216 217 ALOGV("MediaExtractor::CreateFromService %s", mime); 218 RegisterDefaultSniffers(); 219 220 // initialize source decryption if needed 221 source->DrmInitialization(); 222 223 sp<AMessage> meta; 224 225 String8 tmp; 226 if (mime == NULL) { 227 float confidence; 228 if (!sniff(source, &tmp, &confidence, &meta)) { 229 ALOGV("FAILED to autodetect media content."); 230 231 return NULL; 232 } 233 234 mime = tmp.string(); 235 ALOGV("Autodetected media content as '%s' with confidence %.2f", 236 mime, confidence); 237 } 238 239 MediaExtractor *ret = NULL; 240 if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4) 241 || !strcasecmp(mime, "audio/mp4")) { 242 ret = new MPEG4Extractor(source); 243 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) { 244 ret = new MP3Extractor(source, meta); 245 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB) 246 || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) { 247 ret = new AMRExtractor(source); 248 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) { 249 ret = new FLACExtractor(source); 250 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) { 251 ret = new WAVExtractor(source); 252 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) { 253 ret = new OggExtractor(source); 254 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) { 255 ret = new MatroskaExtractor(source); 256 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) { 257 ret = new MPEG2TSExtractor(source); 258 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) { 259 ret = new AACExtractor(source, meta); 260 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) { 261 ret = new MPEG2PSExtractor(source); 262 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MIDI)) { 263 ret = new MidiExtractor(source); 264 } 265 266 if (ret != NULL) { 267 // track the container format (mpeg, aac, wvm, etc) 268 if (MEDIA_LOG) { 269 if (ret->mAnalyticsItem != NULL) { 270 size_t ntracks = ret->countTracks(); 271 ret->mAnalyticsItem->setCString(kExtractorFormat, ret->name()); 272 // tracks (size_t) 273 ret->mAnalyticsItem->setInt32(kExtractorTracks, ntracks); 274 // metadata 275 sp<MetaData> pMetaData = ret->getMetaData(); 276 if (pMetaData != NULL) { 277 String8 xx = pMetaData->toString(); 278 // 'titl' -- but this verges into PII 279 // 'mime' 280 const char *mime = NULL; 281 if (pMetaData->findCString(kKeyMIMEType, &mime)) { 282 ret->mAnalyticsItem->setCString(kExtractorMime, mime); 283 } 284 // what else is interesting and not already available? 285 } 286 } 287 } 288 } 289 290 return ret; 291} 292 293Mutex MediaExtractor::gSnifferMutex; 294List<MediaExtractor::SnifferFunc> MediaExtractor::gSniffers; 295bool MediaExtractor::gSniffersRegistered = false; 296 297// static 298bool MediaExtractor::sniff( 299 const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta) { 300 *mimeType = ""; 301 *confidence = 0.0f; 302 meta->clear(); 303 304 { 305 Mutex::Autolock autoLock(gSnifferMutex); 306 if (!gSniffersRegistered) { 307 return false; 308 } 309 } 310 311 for (List<SnifferFunc>::iterator it = gSniffers.begin(); 312 it != gSniffers.end(); ++it) { 313 String8 newMimeType; 314 float newConfidence; 315 sp<AMessage> newMeta; 316 if ((*it)(source, &newMimeType, &newConfidence, &newMeta)) { 317 if (newConfidence > *confidence) { 318 *mimeType = newMimeType; 319 *confidence = newConfidence; 320 *meta = newMeta; 321 } 322 } 323 } 324 325 return *confidence > 0.0; 326} 327 328// static 329void MediaExtractor::RegisterSniffer_l(SnifferFunc func) { 330 for (List<SnifferFunc>::iterator it = gSniffers.begin(); 331 it != gSniffers.end(); ++it) { 332 if (*it == func) { 333 return; 334 } 335 } 336 337 gSniffers.push_back(func); 338} 339 340// static 341void MediaExtractor::RegisterDefaultSniffers() { 342 Mutex::Autolock autoLock(gSnifferMutex); 343 if (gSniffersRegistered) { 344 return; 345 } 346 347 RegisterSniffer_l(SniffMPEG4); 348 RegisterSniffer_l(SniffMatroska); 349 RegisterSniffer_l(SniffOgg); 350 RegisterSniffer_l(SniffWAV); 351 RegisterSniffer_l(SniffFLAC); 352 RegisterSniffer_l(SniffAMR); 353 RegisterSniffer_l(SniffMPEG2TS); 354 RegisterSniffer_l(SniffMP3); 355 RegisterSniffer_l(SniffAAC); 356 RegisterSniffer_l(SniffMPEG2PS); 357 RegisterSniffer_l(SniffMidi); 358 359 gSniffersRegistered = true; 360} 361 362 363} // namespace android 364