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
53 namespace android {
54
MediaExtractor()55 MediaExtractor::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
getMetaData()66 sp<MetaData> MediaExtractor::getMetaData() {
67 return new MetaData;
68 }
69
flags() const70 uint32_t MediaExtractor::flags() const {
71 return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;
72 }
73
74
75
76 class RemoteDataSource : public BnDataSource {
77 public:
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
93 private:
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
wrap(const sp<DataSource> & source)102 sp<IDataSource> RemoteDataSource::wrap(const sp<DataSource> &source) {
103 return new RemoteDataSource(source);
104 }
RemoteDataSource(const sp<DataSource> & source)105 RemoteDataSource::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 }
~RemoteDataSource()114 RemoteDataSource::~RemoteDataSource() {
115 close();
116 }
getIMemory()117 sp<IMemory> RemoteDataSource::getIMemory() {
118 return mMemory;
119 }
readAt(off64_t offset,size_t size)120 ssize_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 }
getSize(off64_t * size)124 status_t RemoteDataSource::getSize(off64_t* size) {
125 return mSource->getSize(size);
126 }
close()127 void RemoteDataSource::close() {
128 mSource = NULL;
129 }
getFlags()130 uint32_t RemoteDataSource::getFlags() {
131 return mSource->flags();
132 }
133
toString()134 String8 RemoteDataSource::toString() {
135 return mName;
136 }
137
DrmInitialization(const char * mime)138 sp<DecryptHandle> RemoteDataSource::DrmInitialization(const char *mime) {
139 return mSource->DrmInitialization(mime);
140 }
141
142 // static
Create(const sp<DataSource> & source,const char * mime)143 sp<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
CreateFromService(const sp<DataSource> & source,const char * mime)191 sp<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