MediaExtractor.cpp revision d49dbd6b625cddb82f3f7bbeac62d48ef338ef0f
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// static 121sp<IMediaExtractor> MediaExtractor::Create( 122 const sp<DataSource> &source, const char *mime) { 123 ALOGV("MediaExtractor::Create %s", mime); 124 125 if (!property_get_bool("media.stagefright.extractremote", true)) { 126 // local extractor 127 ALOGW("creating media extractor in calling process"); 128 return CreateFromService(source, mime); 129 } else { 130 // remote extractor 131 ALOGV("get service manager"); 132 sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor")); 133 134 if (binder != 0) { 135 sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder)); 136 sp<IMediaExtractor> ex = mediaExService->makeExtractor(source->asIDataSource(), mime); 137 return ex; 138 } else { 139 ALOGE("extractor service not running"); 140 return NULL; 141 } 142 } 143 return NULL; 144} 145 146sp<MediaExtractor> MediaExtractor::CreateFromService( 147 const sp<DataSource> &source, const char *mime) { 148 149 ALOGV("MediaExtractor::CreateFromService %s", mime); 150 RegisterDefaultSniffers(); 151 152 // initialize source decryption if needed 153 source->DrmInitialization(nullptr /* mime */); 154 155 sp<AMessage> meta; 156 157 String8 tmp; 158 if (mime == NULL) { 159 float confidence; 160 if (!sniff(source, &tmp, &confidence, &meta)) { 161 ALOGV("FAILED to autodetect media content."); 162 163 return NULL; 164 } 165 166 mime = tmp.string(); 167 ALOGV("Autodetected media content as '%s' with confidence %.2f", 168 mime, confidence); 169 } 170 171 MediaExtractor *ret = NULL; 172 if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4) 173 || !strcasecmp(mime, "audio/mp4")) { 174 ret = new MPEG4Extractor(source); 175 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) { 176 ret = new MP3Extractor(source, meta); 177 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB) 178 || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) { 179 ret = new AMRExtractor(source); 180 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) { 181 ret = new FLACExtractor(source); 182 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) { 183 ret = new WAVExtractor(source); 184 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) { 185 ret = new OggExtractor(source); 186 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) { 187 ret = new MatroskaExtractor(source); 188 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) { 189 ret = new MPEG2TSExtractor(source); 190 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) { 191 ret = new AACExtractor(source, meta); 192 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) { 193 ret = new MPEG2PSExtractor(source); 194 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MIDI)) { 195 ret = new MidiExtractor(source); 196 } 197 198 if (ret != NULL) { 199 // track the container format (mpeg, aac, wvm, etc) 200 if (MEDIA_LOG) { 201 if (ret->mAnalyticsItem != NULL) { 202 size_t ntracks = ret->countTracks(); 203 ret->mAnalyticsItem->setCString(kExtractorFormat, ret->name()); 204 // tracks (size_t) 205 ret->mAnalyticsItem->setInt32(kExtractorTracks, ntracks); 206 // metadata 207 sp<MetaData> pMetaData = ret->getMetaData(); 208 if (pMetaData != NULL) { 209 String8 xx = pMetaData->toString(); 210 // 'titl' -- but this verges into PII 211 // 'mime' 212 const char *mime = NULL; 213 if (pMetaData->findCString(kKeyMIMEType, &mime)) { 214 ret->mAnalyticsItem->setCString(kExtractorMime, mime); 215 } 216 // what else is interesting and not already available? 217 } 218 } 219 } 220 } 221 222 return ret; 223} 224 225Mutex MediaExtractor::gSnifferMutex; 226List<MediaExtractor::SnifferFunc> MediaExtractor::gSniffers; 227bool MediaExtractor::gSniffersRegistered = false; 228 229// static 230bool MediaExtractor::sniff( 231 const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta) { 232 *mimeType = ""; 233 *confidence = 0.0f; 234 meta->clear(); 235 236 { 237 Mutex::Autolock autoLock(gSnifferMutex); 238 if (!gSniffersRegistered) { 239 return false; 240 } 241 } 242 243 for (List<SnifferFunc>::iterator it = gSniffers.begin(); 244 it != gSniffers.end(); ++it) { 245 String8 newMimeType; 246 float newConfidence; 247 sp<AMessage> newMeta; 248 if ((*it)(source, &newMimeType, &newConfidence, &newMeta)) { 249 if (newConfidence > *confidence) { 250 *mimeType = newMimeType; 251 *confidence = newConfidence; 252 *meta = newMeta; 253 } 254 } 255 } 256 257 return *confidence > 0.0; 258} 259 260// static 261void MediaExtractor::RegisterSniffer_l(SnifferFunc func) { 262 for (List<SnifferFunc>::iterator it = gSniffers.begin(); 263 it != gSniffers.end(); ++it) { 264 if (*it == func) { 265 return; 266 } 267 } 268 269 gSniffers.push_back(func); 270} 271 272// static 273void MediaExtractor::RegisterDefaultSniffers() { 274 Mutex::Autolock autoLock(gSnifferMutex); 275 if (gSniffersRegistered) { 276 return; 277 } 278 279 RegisterSniffer_l(SniffMPEG4); 280 RegisterSniffer_l(SniffMatroska); 281 RegisterSniffer_l(SniffOgg); 282 RegisterSniffer_l(SniffWAV); 283 RegisterSniffer_l(SniffFLAC); 284 RegisterSniffer_l(SniffAMR); 285 RegisterSniffer_l(SniffMPEG2TS); 286 RegisterSniffer_l(SniffMP3); 287 RegisterSniffer_l(SniffAAC); 288 RegisterSniffer_l(SniffMPEG2PS); 289 RegisterSniffer_l(SniffMidi); 290 291 gSniffersRegistered = true; 292} 293 294 295} // namespace android 296