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