MediaExtractor.cpp revision 64a2870d8515fd914638c60803db86dbd92f5b06
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 92private: 93 sp<IMemory> mMemory; 94 sp<DataSource> mSource; 95 String8 mName; 96 explicit RemoteDataSource(const sp<DataSource> &source); 97 DISALLOW_EVIL_CONSTRUCTORS(RemoteDataSource); 98}; 99 100 101sp<IDataSource> RemoteDataSource::wrap(const sp<DataSource> &source) { 102 return new RemoteDataSource(source); 103} 104RemoteDataSource::RemoteDataSource(const sp<DataSource> &source) { 105 mSource = source; 106 sp<MemoryDealer> memoryDealer = new MemoryDealer(kBufferSize, "RemoteDataSource"); 107 mMemory = memoryDealer->allocate(kBufferSize); 108 if (mMemory == NULL) { 109 ALOGE("Failed to allocate memory!"); 110 } 111 mName = String8::format("RemoteDataSource(%s)", mSource->toString().string()); 112} 113RemoteDataSource::~RemoteDataSource() { 114 close(); 115} 116sp<IMemory> RemoteDataSource::getIMemory() { 117 return mMemory; 118} 119ssize_t RemoteDataSource::readAt(off64_t offset, size_t size) { 120 ALOGV("readAt(%" PRId64 ", %zu)", offset, size); 121 return mSource->readAt(offset, mMemory->pointer(), size); 122} 123status_t RemoteDataSource::getSize(off64_t* size) { 124 return mSource->getSize(size); 125} 126void RemoteDataSource::close() { 127 mSource = NULL; 128} 129uint32_t RemoteDataSource::getFlags() { 130 return mSource->flags(); 131} 132 133String8 RemoteDataSource::toString() { 134 return mName; 135} 136 137// static 138sp<IMediaExtractor> MediaExtractor::Create( 139 const sp<DataSource> &source, const char *mime) { 140 ALOGV("MediaExtractor::Create %s", mime); 141 142 char value[PROPERTY_VALUE_MAX]; 143 if (property_get("media.stagefright.extractremote", value, NULL) 144 && (!strcmp("0", value) || !strcasecmp("false", value))) { 145 // local extractor 146 ALOGW("creating media extractor in calling process"); 147 return CreateFromService(source, mime); 148 } else { 149 // remote extractor 150 ALOGV("get service manager"); 151 sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor")); 152 153 // Check if it's WVM, since WVMExtractor needs to be created in the media server process, 154 // not the extractor process. 155 String8 mime8; 156 float confidence; 157 sp<AMessage> meta; 158 if (SniffWVM(source, &mime8, &confidence, &meta) && 159 !strcasecmp(mime8, MEDIA_MIMETYPE_CONTAINER_WVM)) { 160 return new WVMExtractor(source); 161 } 162 163 if (binder != 0) { 164 sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder)); 165 sp<IMediaExtractor> ex = mediaExService->makeExtractor(RemoteDataSource::wrap(source), mime); 166 return ex; 167 } else { 168 ALOGE("extractor service not running"); 169 return NULL; 170 } 171 } 172 return NULL; 173} 174 175sp<MediaExtractor> MediaExtractor::CreateFromService( 176 const sp<DataSource> &source, const char *mime) { 177 178 ALOGV("MediaExtractor::CreateFromService %s", mime); 179 DataSource::RegisterDefaultSniffers(); 180 181 sp<AMessage> meta; 182 183 String8 tmp; 184 if (mime == NULL) { 185 float confidence; 186 if (!source->sniff(&tmp, &confidence, &meta)) { 187 ALOGV("FAILED to autodetect media content."); 188 189 return NULL; 190 } 191 192 mime = tmp.string(); 193 ALOGV("Autodetected media content as '%s' with confidence %.2f", 194 mime, confidence); 195 } 196 197 bool isDrm = false; 198 // DRM MIME type syntax is "drm+type+original" where 199 // type is "es_based" or "container_based" and 200 // original is the content's cleartext MIME type 201 if (!strncmp(mime, "drm+", 4)) { 202 const char *originalMime = strchr(mime+4, '+'); 203 if (originalMime == NULL) { 204 // second + not found 205 return NULL; 206 } 207 ++originalMime; 208 if (!strncmp(mime, "drm+es_based+", 13)) { 209 // DRMExtractor sets container metadata kKeyIsDRM to 1 210 return new DRMExtractor(source, originalMime); 211 } else if (!strncmp(mime, "drm+container_based+", 20)) { 212 mime = originalMime; 213 isDrm = true; 214 } else { 215 return NULL; 216 } 217 } 218 219 MediaExtractor *ret = NULL; 220 if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4) 221 || !strcasecmp(mime, "audio/mp4")) { 222 ret = new MPEG4Extractor(source); 223 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) { 224 ret = new MP3Extractor(source, meta); 225 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB) 226 || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) { 227 ret = new AMRExtractor(source); 228 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) { 229 ret = new FLACExtractor(source); 230 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) { 231 ret = new WAVExtractor(source); 232 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) { 233 ret = new OggExtractor(source); 234 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) { 235 ret = new MatroskaExtractor(source); 236 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) { 237 ret = new MPEG2TSExtractor(source); 238 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM) && getuid() == AID_MEDIA) { 239 // Return now. WVExtractor should not have the DrmFlag set in the block below. 240 return new WVMExtractor(source); 241 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) { 242 ret = new AACExtractor(source, meta); 243 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) { 244 ret = new MPEG2PSExtractor(source); 245 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MIDI)) { 246 ret = new MidiExtractor(source); 247 } 248 249 if (ret != NULL) { 250 if (isDrm) { 251 ret->setDrmFlag(true); 252 } else { 253 ret->setDrmFlag(false); 254 } 255 } 256 257 return ret; 258} 259 260} // namespace android 261