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/DRMExtractor.h" 31#include "include/WVMExtractor.h" 32#include "include/FLACExtractor.h" 33#include "include/AACExtractor.h" 34#include "include/MidiExtractor.h" 35 36#include "matroska/MatroskaExtractor.h" 37 38#include <binder/IServiceManager.h> 39#include <binder/MemoryDealer.h> 40 41#include <media/stagefright/foundation/ADebug.h> 42#include <media/stagefright/foundation/AMessage.h> 43#include <media/stagefright/DataSource.h> 44#include <media/stagefright/MediaDefs.h> 45#include <media/stagefright/MediaExtractor.h> 46#include <media/stagefright/MetaData.h> 47#include <media/IMediaExtractorService.h> 48#include <cutils/properties.h> 49#include <utils/String8.h> 50#include <private/android_filesystem_config.h> 51 52 53namespace android { 54 55MediaExtractor::MediaExtractor(): 56 mIsDrm(false) { 57 if (!LOG_NDEBUG) { 58 uid_t uid = getuid(); 59 struct passwd *pw = getpwuid(uid); 60 ALOGI("extractor created in uid: %d (%s)", getuid(), pw->pw_name); 61 } 62 63} 64 65 66sp<MetaData> MediaExtractor::getMetaData() { 67 return new MetaData; 68} 69 70uint32_t MediaExtractor::flags() const { 71 return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK; 72} 73 74 75 76class RemoteDataSource : public BnDataSource { 77public: 78 enum { 79 kBufferSize = 64 * 1024, 80 }; 81 82 static sp<IDataSource> wrap(const sp<DataSource> &source); 83 virtual ~RemoteDataSource(); 84 85 virtual sp<IMemory> getIMemory(); 86 virtual ssize_t readAt(off64_t offset, size_t size); 87 virtual status_t getSize(off64_t* size); 88 virtual void close(); 89 virtual uint32_t getFlags(); 90 virtual String8 toString(); 91 virtual sp<DecryptHandle> DrmInitialization(const char *mime); 92 93private: 94 sp<IMemory> mMemory; 95 sp<DataSource> mSource; 96 String8 mName; 97 RemoteDataSource(const sp<DataSource> &source); 98 DISALLOW_EVIL_CONSTRUCTORS(RemoteDataSource); 99}; 100 101 102sp<IDataSource> RemoteDataSource::wrap(const sp<DataSource> &source) { 103 return new RemoteDataSource(source); 104} 105RemoteDataSource::RemoteDataSource(const sp<DataSource> &source) { 106 mSource = source; 107 sp<MemoryDealer> memoryDealer = new MemoryDealer(kBufferSize, "RemoteDataSource"); 108 mMemory = memoryDealer->allocate(kBufferSize); 109 if (mMemory == NULL) { 110 ALOGE("Failed to allocate memory!"); 111 } 112 mName = String8::format("RemoteDataSource(%s)", mSource->toString().string()); 113} 114RemoteDataSource::~RemoteDataSource() { 115 close(); 116} 117sp<IMemory> RemoteDataSource::getIMemory() { 118 return mMemory; 119} 120ssize_t RemoteDataSource::readAt(off64_t offset, size_t size) { 121 ALOGV("readAt(%" PRId64 ", %zu)", offset, size); 122 return mSource->readAt(offset, mMemory->pointer(), size); 123} 124status_t RemoteDataSource::getSize(off64_t* size) { 125 return mSource->getSize(size); 126} 127void RemoteDataSource::close() { 128 mSource = NULL; 129} 130uint32_t RemoteDataSource::getFlags() { 131 return mSource->flags(); 132} 133 134String8 RemoteDataSource::toString() { 135 return mName; 136} 137 138sp<DecryptHandle> RemoteDataSource::DrmInitialization(const char *mime) { 139 return mSource->DrmInitialization(mime); 140} 141 142// static 143sp<IMediaExtractor> MediaExtractor::Create( 144 const sp<DataSource> &source, const char *mime) { 145 ALOGV("MediaExtractor::Create %s", mime); 146 147 char value[PROPERTY_VALUE_MAX]; 148 if (property_get("media.stagefright.extractremote", value, NULL) 149 && (!strcmp("0", value) || !strcasecmp("false", value))) { 150 // local extractor 151 ALOGW("creating media extractor in calling process"); 152 return CreateFromService(source, mime); 153 } else { 154 // Check if it's WVM, since WVMExtractor needs to be created in the media server process, 155 // not the extractor process. 156 String8 mime8; 157 float confidence; 158 sp<AMessage> meta; 159 if (SniffWVM(source, &mime8, &confidence, &meta) && 160 !strcasecmp(mime8, MEDIA_MIMETYPE_CONTAINER_WVM)) { 161 return new WVMExtractor(source); 162 } 163 164 // Check if it's es-based DRM, since DRMExtractor needs to be created in the media server 165 // process, not the extractor process. 166 if (SniffDRM(source, &mime8, &confidence, &meta)) { 167 const char *drmMime = mime8.string(); 168 ALOGV("Detected media content as '%s' with confidence %.2f", drmMime, confidence); 169 if (!strncmp(drmMime, "drm+es_based+", 13)) { 170 // DRMExtractor sets container metadata kKeyIsDRM to 1 171 return new DRMExtractor(source, drmMime + 14); 172 } 173 } 174 175 // remote extractor 176 ALOGV("get service manager"); 177 sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor")); 178 179 if (binder != 0) { 180 sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder)); 181 sp<IMediaExtractor> ex = mediaExService->makeExtractor(RemoteDataSource::wrap(source), mime); 182 return ex; 183 } else { 184 ALOGE("extractor service not running"); 185 return NULL; 186 } 187 } 188 return NULL; 189} 190 191sp<MediaExtractor> MediaExtractor::CreateFromService( 192 const sp<DataSource> &source, const char *mime) { 193 194 ALOGV("MediaExtractor::CreateFromService %s", mime); 195 DataSource::RegisterDefaultSniffers(); 196 197 sp<AMessage> meta; 198 199 String8 tmp; 200 if (mime == NULL) { 201 float confidence; 202 if (!source->sniff(&tmp, &confidence, &meta)) { 203 ALOGV("FAILED to autodetect media content."); 204 205 return NULL; 206 } 207 208 mime = tmp.string(); 209 ALOGV("Autodetected media content as '%s' with confidence %.2f", 210 mime, confidence); 211 } 212 213 bool isDrm = false; 214 // DRM MIME type syntax is "drm+type+original" where 215 // type is "es_based" or "container_based" and 216 // original is the content's cleartext MIME type 217 if (!strncmp(mime, "drm+", 4)) { 218 const char *originalMime = strchr(mime+4, '+'); 219 if (originalMime == NULL) { 220 // second + not found 221 return NULL; 222 } 223 ++originalMime; 224 if (!strncmp(mime, "drm+es_based+", 13)) { 225 // DRMExtractor sets container metadata kKeyIsDRM to 1 226 return new DRMExtractor(source, originalMime); 227 } else if (!strncmp(mime, "drm+container_based+", 20)) { 228 mime = originalMime; 229 isDrm = true; 230 } else { 231 return NULL; 232 } 233 } 234 235 MediaExtractor *ret = NULL; 236 if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4) 237 || !strcasecmp(mime, "audio/mp4")) { 238 ret = new MPEG4Extractor(source); 239 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) { 240 ret = new MP3Extractor(source, meta); 241 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB) 242 || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) { 243 ret = new AMRExtractor(source); 244 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) { 245 ret = new FLACExtractor(source); 246 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) { 247 ret = new WAVExtractor(source); 248 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) { 249 ret = new OggExtractor(source); 250 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) { 251 ret = new MatroskaExtractor(source); 252 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) { 253 ret = new MPEG2TSExtractor(source); 254 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM) && getuid() == AID_MEDIA) { 255 // Return now. WVExtractor should not have the DrmFlag set in the block below. 256 return new WVMExtractor(source); 257 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) { 258 ret = new AACExtractor(source, meta); 259 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) { 260 ret = new MPEG2PSExtractor(source); 261 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MIDI)) { 262 ret = new MidiExtractor(source); 263 } 264 265 if (ret != NULL) { 266 if (isDrm) { 267 ret->setDrmFlag(true); 268 } else { 269 ret->setDrmFlag(false); 270 } 271 } 272 273 return ret; 274} 275 276} // namespace android 277