blob: 752dfab1536809b785b1c298623e80fed2c3e7ab [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),
Lajos Molnar63c0ce72014-07-31 07:13:32 -070063 mAudioIsVorbis(false),
64 mIsWidevine(false) {
Andreas Huberafed0e12011-09-20 15:39:58 -070065 DataSource::RegisterDefaultSniffers();
66
67 sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
68
69 initFromDataSource(dataSource);
70}
71
72void NuPlayer::GenericSource::initFromDataSource(
73 const sp<DataSource> &dataSource) {
Lajos Molnarcc227032014-07-17 15:33:06 -070074 sp<MediaExtractor> extractor;
75
76 if (mIsWidevine) {
77 String8 mimeType;
78 float confidence;
79 sp<AMessage> dummy;
80 bool success;
81
82 success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
83 if (!success
84 || strcasecmp(
85 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
86 ALOGE("unsupported widevine mime: %s", mimeType.string());
87 return;
88 }
89
90 sp<WVMExtractor> wvmExtractor = new WVMExtractor(dataSource);
91 wvmExtractor->setAdaptiveStreamingMode(true);
92 if (mUIDValid) {
93 wvmExtractor->setUID(mUID);
94 }
95 extractor = wvmExtractor;
96 } else {
97 extractor = MediaExtractor::Create(dataSource);
98 }
Andreas Huberafed0e12011-09-20 15:39:58 -070099
100 CHECK(extractor != NULL);
101
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700102 sp<MetaData> fileMeta = extractor->getMetaData();
103 if (fileMeta != NULL) {
104 int64_t duration;
105 if (fileMeta->findInt64(kKeyDuration, &duration)) {
106 mDurationUs = duration;
107 }
108 }
109
Andreas Huberafed0e12011-09-20 15:39:58 -0700110 for (size_t i = 0; i < extractor->countTracks(); ++i) {
111 sp<MetaData> meta = extractor->getTrackMetaData(i);
112
113 const char *mime;
114 CHECK(meta->findCString(kKeyMIMEType, &mime));
115
Robert Shihdd235722014-06-12 14:49:23 -0700116 sp<MediaSource> track = extractor->getTrack(i);
Andreas Huberafed0e12011-09-20 15:39:58 -0700117
118 if (!strncasecmp(mime, "audio/", 6)) {
119 if (mAudioTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700120 mAudioTrack.mIndex = i;
121 mAudioTrack.mSource = track;
Andreas Huberafed0e12011-09-20 15:39:58 -0700122
123 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
124 mAudioIsVorbis = true;
125 } else {
126 mAudioIsVorbis = false;
127 }
128 }
129 } else if (!strncasecmp(mime, "video/", 6)) {
130 if (mVideoTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700131 mVideoTrack.mIndex = i;
132 mVideoTrack.mSource = track;
Andreas Huberafed0e12011-09-20 15:39:58 -0700133 }
134 }
135
136 if (track != NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700137 mSources.push(track);
Andreas Huberafed0e12011-09-20 15:39:58 -0700138 int64_t durationUs;
139 if (meta->findInt64(kKeyDuration, &durationUs)) {
140 if (durationUs > mDurationUs) {
141 mDurationUs = durationUs;
142 }
143 }
144 }
145 }
146}
147
Lajos Molnarcc227032014-07-17 15:33:06 -0700148status_t NuPlayer::GenericSource::setBuffers(bool audio, Vector<MediaBuffer *> &buffers) {
149 if (mIsWidevine && !audio) {
150 return mVideoTrack.mSource->setBuffers(buffers);
151 }
152 return INVALID_OPERATION;
153}
154
Andreas Huberafed0e12011-09-20 15:39:58 -0700155NuPlayer::GenericSource::~GenericSource() {
156}
157
Andreas Huber9575c962013-02-05 13:59:56 -0800158void NuPlayer::GenericSource::prepareAsync() {
159 if (mVideoTrack.mSource != NULL) {
160 sp<MetaData> meta = mVideoTrack.mSource->getFormat();
161
162 int32_t width, height;
163 CHECK(meta->findInt32(kKeyWidth, &width));
164 CHECK(meta->findInt32(kKeyHeight, &height));
165
166 notifyVideoSizeChanged(width, height);
167 }
168
169 notifyFlagsChanged(
Lajos Molnarcc227032014-07-17 15:33:06 -0700170 (mIsWidevine ? FLAG_SECURE : 0)
171 | FLAG_CAN_PAUSE
Andreas Huber9575c962013-02-05 13:59:56 -0800172 | FLAG_CAN_SEEK_BACKWARD
173 | FLAG_CAN_SEEK_FORWARD
174 | FLAG_CAN_SEEK);
175
176 notifyPrepared();
177}
178
Andreas Huberafed0e12011-09-20 15:39:58 -0700179void NuPlayer::GenericSource::start() {
180 ALOGI("start");
181
182 if (mAudioTrack.mSource != NULL) {
Robert Shihbace25b2014-07-25 14:14:34 -0700183 CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);
Wei Jiacb48eac2014-07-30 13:40:49 -0700184
Andreas Huberafed0e12011-09-20 15:39:58 -0700185 mAudioTrack.mPackets =
186 new AnotherPacketSource(mAudioTrack.mSource->getFormat());
187
Wei Jiacb48eac2014-07-30 13:40:49 -0700188 readBuffer(true /* audio */);
Andreas Huberafed0e12011-09-20 15:39:58 -0700189 }
190
191 if (mVideoTrack.mSource != NULL) {
Robert Shihbace25b2014-07-25 14:14:34 -0700192 CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK);
Wei Jiacb48eac2014-07-30 13:40:49 -0700193
Andreas Huberafed0e12011-09-20 15:39:58 -0700194 mVideoTrack.mPackets =
195 new AnotherPacketSource(mVideoTrack.mSource->getFormat());
196
Wei Jiacb48eac2014-07-30 13:40:49 -0700197 readBuffer(false /* audio */);
Andreas Huberafed0e12011-09-20 15:39:58 -0700198 }
199}
200
201status_t NuPlayer::GenericSource::feedMoreTSData() {
202 return OK;
203}
204
Andreas Huber84066782011-08-16 09:34:26 -0700205sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
Andreas Huberafed0e12011-09-20 15:39:58 -0700206 sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
207
208 if (source == NULL) {
209 return NULL;
210 }
211
212 return source->getFormat();
213}
214
215status_t NuPlayer::GenericSource::dequeueAccessUnit(
216 bool audio, sp<ABuffer> *accessUnit) {
217 Track *track = audio ? &mAudioTrack : &mVideoTrack;
218
219 if (track->mSource == NULL) {
220 return -EWOULDBLOCK;
221 }
222
Lajos Molnarcc227032014-07-17 15:33:06 -0700223 if (mIsWidevine && !audio) {
224 // try to read a buffer as we may not have been able to the last time
Wei Jiacb48eac2014-07-30 13:40:49 -0700225 readBuffer(audio, -1ll);
Lajos Molnarcc227032014-07-17 15:33:06 -0700226 }
227
Andreas Huberafed0e12011-09-20 15:39:58 -0700228 status_t finalResult;
229 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
Lajos Molnarcc227032014-07-17 15:33:06 -0700230 return (finalResult == OK ? -EWOULDBLOCK : finalResult);
Andreas Huberafed0e12011-09-20 15:39:58 -0700231 }
232
233 status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
234
Wei Jiacb48eac2014-07-30 13:40:49 -0700235 readBuffer(audio, -1ll);
Robert Shiheb1735e2014-07-23 15:53:14 -0700236
Andreas Huberafed0e12011-09-20 15:39:58 -0700237 return result;
238}
239
240status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
241 *durationUs = mDurationUs;
242 return OK;
243}
244
Robert Shihdd235722014-06-12 14:49:23 -0700245size_t NuPlayer::GenericSource::getTrackCount() const {
246 return mSources.size();
247}
248
249sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
250 size_t trackCount = mSources.size();
251 if (trackIndex >= trackCount) {
252 return NULL;
253 }
254
255 sp<AMessage> format = new AMessage();
256 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
257
258 const char *mime;
259 CHECK(meta->findCString(kKeyMIMEType, &mime));
260
261 int32_t trackType;
262 if (!strncasecmp(mime, "video/", 6)) {
263 trackType = MEDIA_TRACK_TYPE_VIDEO;
264 } else if (!strncasecmp(mime, "audio/", 6)) {
265 trackType = MEDIA_TRACK_TYPE_AUDIO;
266 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
267 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
268 } else {
269 trackType = MEDIA_TRACK_TYPE_UNKNOWN;
270 }
271 format->setInt32("type", trackType);
272
273 const char *lang;
274 if (!meta->findCString(kKeyMediaLanguage, &lang)) {
275 lang = "und";
276 }
277 format->setString("language", lang);
278
279 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
280 format->setString("mime", mime);
281
282 int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
283 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
284 meta->findInt32(kKeyTrackIsDefault, &isDefault);
285 meta->findInt32(kKeyTrackIsForced, &isForced);
286
287 format->setInt32("auto", !!isAutoselect);
288 format->setInt32("default", !!isDefault);
289 format->setInt32("forced", !!isForced);
290 }
291
292 return format;
293}
294
Andreas Huberafed0e12011-09-20 15:39:58 -0700295status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
296 if (mVideoTrack.mSource != NULL) {
297 int64_t actualTimeUs;
Wei Jiacb48eac2014-07-30 13:40:49 -0700298 readBuffer(false /* audio */, seekTimeUs, &actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -0700299
300 seekTimeUs = actualTimeUs;
301 }
302
303 if (mAudioTrack.mSource != NULL) {
Wei Jiacb48eac2014-07-30 13:40:49 -0700304 readBuffer(true /* audio */, seekTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -0700305 }
306
307 return OK;
308}
309
310void NuPlayer::GenericSource::readBuffer(
Wei Jiacb48eac2014-07-30 13:40:49 -0700311 bool audio, int64_t seekTimeUs, int64_t *actualTimeUs) {
312 Track *track = audio ? &mAudioTrack : &mVideoTrack;
313 CHECK(track->mSource != NULL);
Andreas Huberafed0e12011-09-20 15:39:58 -0700314
315 if (actualTimeUs) {
316 *actualTimeUs = seekTimeUs;
317 }
318
319 MediaSource::ReadOptions options;
320
321 bool seeking = false;
322
323 if (seekTimeUs >= 0) {
Wei Jiacb48eac2014-07-30 13:40:49 -0700324 options.setSeekTo(seekTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -0700325 seeking = true;
326 }
327
Wei Jiacb48eac2014-07-30 13:40:49 -0700328 if (mIsWidevine && !audio) {
Lajos Molnarcc227032014-07-17 15:33:06 -0700329 options.setNonBlocking();
330 }
331
Andreas Huberafed0e12011-09-20 15:39:58 -0700332 for (;;) {
333 MediaBuffer *mbuf;
334 status_t err = track->mSource->read(&mbuf, &options);
335
336 options.clearSeekTo();
337
338 if (err == OK) {
Wei Jiacb48eac2014-07-30 13:40:49 -0700339 size_t outLength = mbuf->range_length();
340
341 if (audio && mAudioIsVorbis) {
342 outLength += sizeof(int32_t);
Andreas Huberafed0e12011-09-20 15:39:58 -0700343 }
344
Wei Jiacb48eac2014-07-30 13:40:49 -0700345 sp<ABuffer> buffer;
346 if (mIsWidevine && !audio) {
347 // data is already provided in the buffer
348 buffer = new ABuffer(NULL, mbuf->range_length());
349 buffer->meta()->setPointer("mediaBuffer", mbuf);
350 mbuf->add_ref();
351 } else {
352 buffer = new ABuffer(outLength);
353 memcpy(buffer->data(),
354 (const uint8_t *)mbuf->data() + mbuf->range_offset(),
355 mbuf->range_length());
356 }
357
358 if (audio && mAudioIsVorbis) {
359 int32_t numPageSamples;
360 if (!mbuf->meta_data()->findInt32(
361 kKeyValidSamples, &numPageSamples)) {
362 numPageSamples = -1;
363 }
364
365 memcpy(buffer->data() + mbuf->range_length(),
366 &numPageSamples,
367 sizeof(numPageSamples));
368 }
369
370 int64_t timeUs;
371 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
372
373 buffer->meta()->setInt64("timeUs", timeUs);
374
375 if (actualTimeUs) {
376 *actualTimeUs = timeUs;
377 }
378
379 mbuf->release();
380 mbuf = NULL;
381
382 if (seeking) {
383 track->mPackets->queueDiscontinuity(
384 ATSParser::DISCONTINUITY_SEEK,
385 NULL,
386 true /* discard */);
387 }
388
Andreas Huberafed0e12011-09-20 15:39:58 -0700389 track->mPackets->queueAccessUnit(buffer);
390 break;
Lajos Molnarcc227032014-07-17 15:33:06 -0700391 } else if (err == WOULD_BLOCK) {
392 break;
Andreas Huberafed0e12011-09-20 15:39:58 -0700393 } else if (err == INFO_FORMAT_CHANGED) {
394#if 0
395 track->mPackets->queueDiscontinuity(
Chong Zhang632740c2014-06-26 13:03:47 -0700396 ATSParser::DISCONTINUITY_FORMATCHANGE,
397 NULL,
398 false /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -0700399#endif
400 } else {
401 track->mPackets->signalEOS(err);
402 break;
403 }
404 }
405}
406
Andreas Huberafed0e12011-09-20 15:39:58 -0700407} // namespace android