blob: d75408d468c0cb85a0ef392d018431769fd0ca86 [file] [log] [blame]
Andreas Huberafed0e12011-09-20 15:39:58 -07001/*
2 * Copyright (C) 2012 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#include "GenericSource.h"
18
19#include "AnotherPacketSource.h"
20
21#include <media/stagefright/foundation/ABuffer.h>
22#include <media/stagefright/foundation/ADebug.h>
23#include <media/stagefright/foundation/AMessage.h>
24#include <media/stagefright/DataSource.h>
25#include <media/stagefright/FileSource.h>
26#include <media/stagefright/MediaBuffer.h>
27#include <media/stagefright/MediaDefs.h>
28#include <media/stagefright/MediaExtractor.h>
29#include <media/stagefright/MediaSource.h>
30#include <media/stagefright/MetaData.h>
Lajos Molnarcc227032014-07-17 15:33:06 -070031#include "../../libstagefright/include/WVMExtractor.h"
Andreas Huberafed0e12011-09-20 15:39:58 -070032
33namespace android {
34
35NuPlayer::GenericSource::GenericSource(
Andreas Huberb5f25f02013-02-05 10:14:26 -080036 const sp<AMessage> &notify,
Andreas Huber1b86fe02014-01-29 11:13:26 -080037 const sp<IMediaHTTPService> &httpService,
Andreas Huberafed0e12011-09-20 15:39:58 -070038 const char *url,
Lajos Molnarcc227032014-07-17 15:33:06 -070039 const KeyedVector<String8, String8> *headers,
40 bool isWidevine,
41 bool uidValid,
42 uid_t uid)
Andreas Huberb5f25f02013-02-05 10:14:26 -080043 : Source(notify),
44 mDurationUs(0ll),
Lajos Molnarcc227032014-07-17 15:33:06 -070045 mAudioIsVorbis(false),
46 mIsWidevine(isWidevine),
47 mUIDValid(uidValid),
48 mUID(uid) {
Andreas Huberafed0e12011-09-20 15:39:58 -070049 DataSource::RegisterDefaultSniffers();
50
51 sp<DataSource> dataSource =
Andreas Huber1b86fe02014-01-29 11:13:26 -080052 DataSource::CreateFromURI(httpService, url, headers);
Andreas Huberafed0e12011-09-20 15:39:58 -070053 CHECK(dataSource != NULL);
54
55 initFromDataSource(dataSource);
56}
57
58NuPlayer::GenericSource::GenericSource(
Andreas Huberb5f25f02013-02-05 10:14:26 -080059 const sp<AMessage> &notify,
Andreas Huberafed0e12011-09-20 15:39:58 -070060 int fd, int64_t offset, int64_t length)
Andreas Huberb5f25f02013-02-05 10:14:26 -080061 : Source(notify),
62 mDurationUs(0ll),
Andreas Huberafed0e12011-09-20 15:39:58 -070063 mAudioIsVorbis(false) {
64 DataSource::RegisterDefaultSniffers();
65
66 sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
67
68 initFromDataSource(dataSource);
69}
70
71void NuPlayer::GenericSource::initFromDataSource(
72 const sp<DataSource> &dataSource) {
Lajos Molnarcc227032014-07-17 15:33:06 -070073 sp<MediaExtractor> extractor;
74
75 if (mIsWidevine) {
76 String8 mimeType;
77 float confidence;
78 sp<AMessage> dummy;
79 bool success;
80
81 success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
82 if (!success
83 || strcasecmp(
84 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
85 ALOGE("unsupported widevine mime: %s", mimeType.string());
86 return;
87 }
88
89 sp<WVMExtractor> wvmExtractor = new WVMExtractor(dataSource);
90 wvmExtractor->setAdaptiveStreamingMode(true);
91 if (mUIDValid) {
92 wvmExtractor->setUID(mUID);
93 }
94 extractor = wvmExtractor;
95 } else {
96 extractor = MediaExtractor::Create(dataSource);
97 }
Andreas Huberafed0e12011-09-20 15:39:58 -070098
99 CHECK(extractor != NULL);
100
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700101 sp<MetaData> fileMeta = extractor->getMetaData();
102 if (fileMeta != NULL) {
103 int64_t duration;
104 if (fileMeta->findInt64(kKeyDuration, &duration)) {
105 mDurationUs = duration;
106 }
107 }
108
Andreas Huberafed0e12011-09-20 15:39:58 -0700109 for (size_t i = 0; i < extractor->countTracks(); ++i) {
110 sp<MetaData> meta = extractor->getTrackMetaData(i);
111
112 const char *mime;
113 CHECK(meta->findCString(kKeyMIMEType, &mime));
114
Robert Shihdd235722014-06-12 14:49:23 -0700115 sp<MediaSource> track = extractor->getTrack(i);
Andreas Huberafed0e12011-09-20 15:39:58 -0700116
117 if (!strncasecmp(mime, "audio/", 6)) {
118 if (mAudioTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700119 mAudioTrack.mIndex = i;
120 mAudioTrack.mSource = track;
Andreas Huberafed0e12011-09-20 15:39:58 -0700121
122 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
123 mAudioIsVorbis = true;
124 } else {
125 mAudioIsVorbis = false;
126 }
127 }
128 } else if (!strncasecmp(mime, "video/", 6)) {
129 if (mVideoTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700130 mVideoTrack.mIndex = i;
131 mVideoTrack.mSource = track;
Andreas Huberafed0e12011-09-20 15:39:58 -0700132 }
133 }
134
135 if (track != NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700136 mSources.push(track);
Andreas Huberafed0e12011-09-20 15:39:58 -0700137 int64_t durationUs;
138 if (meta->findInt64(kKeyDuration, &durationUs)) {
139 if (durationUs > mDurationUs) {
140 mDurationUs = durationUs;
141 }
142 }
143 }
144 }
145}
146
Lajos Molnarcc227032014-07-17 15:33:06 -0700147status_t NuPlayer::GenericSource::setBuffers(bool audio, Vector<MediaBuffer *> &buffers) {
148 if (mIsWidevine && !audio) {
149 return mVideoTrack.mSource->setBuffers(buffers);
150 }
151 return INVALID_OPERATION;
152}
153
Andreas Huberafed0e12011-09-20 15:39:58 -0700154NuPlayer::GenericSource::~GenericSource() {
155}
156
Andreas Huber9575c962013-02-05 13:59:56 -0800157void NuPlayer::GenericSource::prepareAsync() {
158 if (mVideoTrack.mSource != NULL) {
159 sp<MetaData> meta = mVideoTrack.mSource->getFormat();
160
161 int32_t width, height;
162 CHECK(meta->findInt32(kKeyWidth, &width));
163 CHECK(meta->findInt32(kKeyHeight, &height));
164
165 notifyVideoSizeChanged(width, height);
166 }
167
168 notifyFlagsChanged(
Lajos Molnarcc227032014-07-17 15:33:06 -0700169 (mIsWidevine ? FLAG_SECURE : 0)
170 | FLAG_CAN_PAUSE
Andreas Huber9575c962013-02-05 13:59:56 -0800171 | FLAG_CAN_SEEK_BACKWARD
172 | FLAG_CAN_SEEK_FORWARD
173 | FLAG_CAN_SEEK);
174
175 notifyPrepared();
176}
177
Andreas Huberafed0e12011-09-20 15:39:58 -0700178void NuPlayer::GenericSource::start() {
179 ALOGI("start");
180
181 if (mAudioTrack.mSource != NULL) {
182 CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);
183
184 mAudioTrack.mPackets =
185 new AnotherPacketSource(mAudioTrack.mSource->getFormat());
186
187 readBuffer(true /* audio */);
188 }
189
190 if (mVideoTrack.mSource != NULL) {
191 CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK);
192
193 mVideoTrack.mPackets =
194 new AnotherPacketSource(mVideoTrack.mSource->getFormat());
195
196 readBuffer(false /* audio */);
197 }
198}
199
200status_t NuPlayer::GenericSource::feedMoreTSData() {
201 return OK;
202}
203
Andreas Huber84066782011-08-16 09:34:26 -0700204sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
Andreas Huberafed0e12011-09-20 15:39:58 -0700205 sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
206
207 if (source == NULL) {
208 return NULL;
209 }
210
211 return source->getFormat();
212}
213
214status_t NuPlayer::GenericSource::dequeueAccessUnit(
215 bool audio, sp<ABuffer> *accessUnit) {
216 Track *track = audio ? &mAudioTrack : &mVideoTrack;
217
218 if (track->mSource == NULL) {
219 return -EWOULDBLOCK;
220 }
221
Lajos Molnarcc227032014-07-17 15:33:06 -0700222 if (mIsWidevine && !audio) {
223 // try to read a buffer as we may not have been able to the last time
224 readBuffer(audio, -1ll);
225 }
226
Andreas Huberafed0e12011-09-20 15:39:58 -0700227 status_t finalResult;
228 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
Lajos Molnarcc227032014-07-17 15:33:06 -0700229 return (finalResult == OK ? -EWOULDBLOCK : finalResult);
Andreas Huberafed0e12011-09-20 15:39:58 -0700230 }
231
232 status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
233
234 readBuffer(audio, -1ll);
235
236 return result;
237}
238
239status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
240 *durationUs = mDurationUs;
241 return OK;
242}
243
Robert Shihdd235722014-06-12 14:49:23 -0700244size_t NuPlayer::GenericSource::getTrackCount() const {
245 return mSources.size();
246}
247
248sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
249 size_t trackCount = mSources.size();
250 if (trackIndex >= trackCount) {
251 return NULL;
252 }
253
254 sp<AMessage> format = new AMessage();
255 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
256
257 const char *mime;
258 CHECK(meta->findCString(kKeyMIMEType, &mime));
259
260 int32_t trackType;
261 if (!strncasecmp(mime, "video/", 6)) {
262 trackType = MEDIA_TRACK_TYPE_VIDEO;
263 } else if (!strncasecmp(mime, "audio/", 6)) {
264 trackType = MEDIA_TRACK_TYPE_AUDIO;
265 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
266 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
267 } else {
268 trackType = MEDIA_TRACK_TYPE_UNKNOWN;
269 }
270 format->setInt32("type", trackType);
271
272 const char *lang;
273 if (!meta->findCString(kKeyMediaLanguage, &lang)) {
274 lang = "und";
275 }
276 format->setString("language", lang);
277
278 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
279 format->setString("mime", mime);
280
281 int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
282 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
283 meta->findInt32(kKeyTrackIsDefault, &isDefault);
284 meta->findInt32(kKeyTrackIsForced, &isForced);
285
286 format->setInt32("auto", !!isAutoselect);
287 format->setInt32("default", !!isDefault);
288 format->setInt32("forced", !!isForced);
289 }
290
291 return format;
292}
293
Andreas Huberafed0e12011-09-20 15:39:58 -0700294status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
295 if (mVideoTrack.mSource != NULL) {
296 int64_t actualTimeUs;
297 readBuffer(false /* audio */, seekTimeUs, &actualTimeUs);
298
299 seekTimeUs = actualTimeUs;
300 }
301
302 if (mAudioTrack.mSource != NULL) {
303 readBuffer(true /* audio */, seekTimeUs);
304 }
305
306 return OK;
307}
308
309void NuPlayer::GenericSource::readBuffer(
310 bool audio, int64_t seekTimeUs, int64_t *actualTimeUs) {
311 Track *track = audio ? &mAudioTrack : &mVideoTrack;
312 CHECK(track->mSource != NULL);
313
314 if (actualTimeUs) {
315 *actualTimeUs = seekTimeUs;
316 }
317
318 MediaSource::ReadOptions options;
319
320 bool seeking = false;
321
322 if (seekTimeUs >= 0) {
323 options.setSeekTo(seekTimeUs);
324 seeking = true;
325 }
326
Lajos Molnarcc227032014-07-17 15:33:06 -0700327 if (mIsWidevine && !audio) {
328 options.setNonBlocking();
329 }
330
Andreas Huberafed0e12011-09-20 15:39:58 -0700331 for (;;) {
332 MediaBuffer *mbuf;
333 status_t err = track->mSource->read(&mbuf, &options);
334
335 options.clearSeekTo();
336
337 if (err == OK) {
338 size_t outLength = mbuf->range_length();
339
340 if (audio && mAudioIsVorbis) {
341 outLength += sizeof(int32_t);
342 }
343
Lajos Molnarcc227032014-07-17 15:33:06 -0700344 sp<ABuffer> buffer;
345 if (mIsWidevine && !audio) {
346 // data is already provided in the buffer
347 buffer = new ABuffer(NULL, mbuf->range_length());
348 buffer->meta()->setPointer("mediaBuffer", mbuf);
349 mbuf->add_ref();
350 } else {
351 buffer = new ABuffer(outLength);
352 memcpy(buffer->data(),
353 (const uint8_t *)mbuf->data() + mbuf->range_offset(),
354 mbuf->range_length());
355 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700356
357 if (audio && mAudioIsVorbis) {
358 int32_t numPageSamples;
359 if (!mbuf->meta_data()->findInt32(
360 kKeyValidSamples, &numPageSamples)) {
361 numPageSamples = -1;
362 }
363
364 memcpy(buffer->data() + mbuf->range_length(),
365 &numPageSamples,
366 sizeof(numPageSamples));
367 }
368
369 int64_t timeUs;
370 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
371
372 buffer->meta()->setInt64("timeUs", timeUs);
373
374 if (actualTimeUs) {
375 *actualTimeUs = timeUs;
376 }
377
378 mbuf->release();
379 mbuf = NULL;
380
381 if (seeking) {
382 track->mPackets->queueDiscontinuity(
Chong Zhang632740c2014-06-26 13:03:47 -0700383 ATSParser::DISCONTINUITY_SEEK,
384 NULL,
385 true /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -0700386 }
387
388 track->mPackets->queueAccessUnit(buffer);
389 break;
Lajos Molnarcc227032014-07-17 15:33:06 -0700390 } else if (err == WOULD_BLOCK) {
391 break;
Andreas Huberafed0e12011-09-20 15:39:58 -0700392 } else if (err == INFO_FORMAT_CHANGED) {
393#if 0
394 track->mPackets->queueDiscontinuity(
Chong Zhang632740c2014-06-26 13:03:47 -0700395 ATSParser::DISCONTINUITY_FORMATCHANGE,
396 NULL,
397 false /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -0700398#endif
399 } else {
400 track->mPackets->signalEOS(err);
401 break;
402 }
403 }
404}
405
Andreas Huberafed0e12011-09-20 15:39:58 -0700406} // namespace android