MediaExtractor.cpp revision 9a1a9537456e41cb8450f84a735c3d005a22ffe2
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 // remote extractor 155 ALOGV("get service manager"); 156 sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor")); 157 158 // Check if it's WVM, since WVMExtractor needs to be created in the media server process, 159 // not the extractor process. 160 String8 mime8; 161 float confidence; 162 sp<AMessage> meta; 163 if (SniffWVM(source, &mime8, &confidence, &meta) && 164 !strcasecmp(mime8, MEDIA_MIMETYPE_CONTAINER_WVM)) { 165 return new WVMExtractor(source); 166 } 167 168 if (binder != 0) { 169 sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder)); 170 sp<IMediaExtractor> ex = mediaExService->makeExtractor(RemoteDataSource::wrap(source), mime); 171 return ex; 172 } else { 173 ALOGE("extractor service not running"); 174 return NULL; 175 } 176 } 177 return NULL; 178} 179 180sp<MediaExtractor> MediaExtractor::CreateFromService( 181 const sp<DataSource> &source, const char *mime) { 182 183 ALOGV("MediaExtractor::CreateFromService %s", mime); 184 DataSource::RegisterDefaultSniffers(); 185 186 sp<AMessage> meta; 187 188 String8 tmp; 189 if (mime == NULL) { 190 float confidence; 191 if (!source->sniff(&tmp, &confidence, &meta)) { 192 ALOGV("FAILED to autodetect media content."); 193 194 return NULL; 195 } 196 197 mime = tmp.string(); 198 ALOGV("Autodetected media content as '%s' with confidence %.2f", 199 mime, confidence); 200 } 201 202 bool isDrm = false; 203 // DRM MIME type syntax is "drm+type+original" where 204 // type is "es_based" or "container_based" and 205 // original is the content's cleartext MIME type 206 if (!strncmp(mime, "drm+", 4)) { 207 const char *originalMime = strchr(mime+4, '+'); 208 if (originalMime == NULL) { 209 // second + not found 210 return NULL; 211 } 212 ++originalMime; 213 if (!strncmp(mime, "drm+es_based+", 13)) { 214 // DRMExtractor sets container metadata kKeyIsDRM to 1 215 return new DRMExtractor(source, originalMime); 216 } else if (!strncmp(mime, "drm+container_based+", 20)) { 217 mime = originalMime; 218 isDrm = true; 219 } else { 220 return NULL; 221 } 222 } 223 224 MediaExtractor *ret = NULL; 225 if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4) 226 || !strcasecmp(mime, "audio/mp4")) { 227 ret = new MPEG4Extractor(source); 228 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) { 229 ret = new MP3Extractor(source, meta); 230 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB) 231 || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) { 232 ret = new AMRExtractor(source); 233 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) { 234 ret = new FLACExtractor(source); 235 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) { 236 ret = new WAVExtractor(source); 237 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) { 238 ret = new OggExtractor(source); 239 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) { 240 ret = new MatroskaExtractor(source); 241 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) { 242 ret = new MPEG2TSExtractor(source); 243 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM) && getuid() == AID_MEDIA) { 244 // Return now. WVExtractor should not have the DrmFlag set in the block below. 245 return new WVMExtractor(source); 246 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) { 247 ret = new AACExtractor(source, meta); 248 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) { 249 ret = new MPEG2PSExtractor(source); 250 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MIDI)) { 251 ret = new MidiExtractor(source); 252 } 253 254 if (ret != NULL) { 255 if (isDrm) { 256 ret->setDrmFlag(true); 257 } else { 258 ret->setDrmFlag(false); 259 } 260 } 261 262 return ret; 263} 264 265} // namespace android 266