blob: 0b09f5849394cce6db4046a46dc930e853ceb135 [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),
Robert Shih05312bc2014-07-16 15:47:09 -070044 mFetchSubtitleDataGeneration(0),
Robert Shiheb1735e2014-07-23 15:53:14 -070045 mFetchTimedTextDataGeneration(0),
Andreas Huberb5f25f02013-02-05 10:14:26 -080046 mDurationUs(0ll),
Lajos Molnarcc227032014-07-17 15:33:06 -070047 mAudioIsVorbis(false),
48 mIsWidevine(isWidevine),
49 mUIDValid(uidValid),
50 mUID(uid) {
Andreas Huberafed0e12011-09-20 15:39:58 -070051 DataSource::RegisterDefaultSniffers();
52
53 sp<DataSource> dataSource =
Andreas Huber1b86fe02014-01-29 11:13:26 -080054 DataSource::CreateFromURI(httpService, url, headers);
Andreas Huberafed0e12011-09-20 15:39:58 -070055 CHECK(dataSource != NULL);
56
57 initFromDataSource(dataSource);
58}
59
60NuPlayer::GenericSource::GenericSource(
Andreas Huberb5f25f02013-02-05 10:14:26 -080061 const sp<AMessage> &notify,
Andreas Huberafed0e12011-09-20 15:39:58 -070062 int fd, int64_t offset, int64_t length)
Andreas Huberb5f25f02013-02-05 10:14:26 -080063 : Source(notify),
Robert Shih05312bc2014-07-16 15:47:09 -070064 mFetchSubtitleDataGeneration(0),
Robert Shiheb1735e2014-07-23 15:53:14 -070065 mFetchTimedTextDataGeneration(0),
Andreas Huberb5f25f02013-02-05 10:14:26 -080066 mDurationUs(0ll),
Andreas Huberafed0e12011-09-20 15:39:58 -070067 mAudioIsVorbis(false) {
68 DataSource::RegisterDefaultSniffers();
69
70 sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
71
72 initFromDataSource(dataSource);
73}
74
75void NuPlayer::GenericSource::initFromDataSource(
76 const sp<DataSource> &dataSource) {
Lajos Molnarcc227032014-07-17 15:33:06 -070077 sp<MediaExtractor> extractor;
78
79 if (mIsWidevine) {
80 String8 mimeType;
81 float confidence;
82 sp<AMessage> dummy;
83 bool success;
84
85 success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
86 if (!success
87 || strcasecmp(
88 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
89 ALOGE("unsupported widevine mime: %s", mimeType.string());
90 return;
91 }
92
93 sp<WVMExtractor> wvmExtractor = new WVMExtractor(dataSource);
94 wvmExtractor->setAdaptiveStreamingMode(true);
95 if (mUIDValid) {
96 wvmExtractor->setUID(mUID);
97 }
98 extractor = wvmExtractor;
99 } else {
100 extractor = MediaExtractor::Create(dataSource);
101 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700102
103 CHECK(extractor != NULL);
104
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700105 sp<MetaData> fileMeta = extractor->getMetaData();
106 if (fileMeta != NULL) {
107 int64_t duration;
108 if (fileMeta->findInt64(kKeyDuration, &duration)) {
109 mDurationUs = duration;
110 }
111 }
112
Andreas Huberafed0e12011-09-20 15:39:58 -0700113 for (size_t i = 0; i < extractor->countTracks(); ++i) {
114 sp<MetaData> meta = extractor->getTrackMetaData(i);
115
116 const char *mime;
117 CHECK(meta->findCString(kKeyMIMEType, &mime));
118
Robert Shihdd235722014-06-12 14:49:23 -0700119 sp<MediaSource> track = extractor->getTrack(i);
Andreas Huberafed0e12011-09-20 15:39:58 -0700120
121 if (!strncasecmp(mime, "audio/", 6)) {
122 if (mAudioTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700123 mAudioTrack.mIndex = i;
124 mAudioTrack.mSource = track;
Andreas Huberafed0e12011-09-20 15:39:58 -0700125
126 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
127 mAudioIsVorbis = true;
128 } else {
129 mAudioIsVorbis = false;
130 }
131 }
132 } else if (!strncasecmp(mime, "video/", 6)) {
133 if (mVideoTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700134 mVideoTrack.mIndex = i;
135 mVideoTrack.mSource = track;
Andreas Huberafed0e12011-09-20 15:39:58 -0700136 }
137 }
138
139 if (track != NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700140 mSources.push(track);
Andreas Huberafed0e12011-09-20 15:39:58 -0700141 int64_t durationUs;
142 if (meta->findInt64(kKeyDuration, &durationUs)) {
143 if (durationUs > mDurationUs) {
144 mDurationUs = durationUs;
145 }
146 }
147 }
148 }
149}
150
Lajos Molnarcc227032014-07-17 15:33:06 -0700151status_t NuPlayer::GenericSource::setBuffers(bool audio, Vector<MediaBuffer *> &buffers) {
152 if (mIsWidevine && !audio) {
153 return mVideoTrack.mSource->setBuffers(buffers);
154 }
155 return INVALID_OPERATION;
156}
157
Andreas Huberafed0e12011-09-20 15:39:58 -0700158NuPlayer::GenericSource::~GenericSource() {
159}
160
Andreas Huber9575c962013-02-05 13:59:56 -0800161void NuPlayer::GenericSource::prepareAsync() {
162 if (mVideoTrack.mSource != NULL) {
163 sp<MetaData> meta = mVideoTrack.mSource->getFormat();
164
165 int32_t width, height;
166 CHECK(meta->findInt32(kKeyWidth, &width));
167 CHECK(meta->findInt32(kKeyHeight, &height));
168
169 notifyVideoSizeChanged(width, height);
170 }
171
172 notifyFlagsChanged(
Lajos Molnarcc227032014-07-17 15:33:06 -0700173 (mIsWidevine ? FLAG_SECURE : 0)
174 | FLAG_CAN_PAUSE
Andreas Huber9575c962013-02-05 13:59:56 -0800175 | FLAG_CAN_SEEK_BACKWARD
176 | FLAG_CAN_SEEK_FORWARD
177 | FLAG_CAN_SEEK);
178
179 notifyPrepared();
180}
181
Andreas Huberafed0e12011-09-20 15:39:58 -0700182void NuPlayer::GenericSource::start() {
183 ALOGI("start");
184
185 if (mAudioTrack.mSource != NULL) {
Robert Shihbace25b2014-07-25 14:14:34 -0700186 CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);
Andreas Huberafed0e12011-09-20 15:39:58 -0700187 mAudioTrack.mPackets =
188 new AnotherPacketSource(mAudioTrack.mSource->getFormat());
189
Robert Shih05312bc2014-07-16 15:47:09 -0700190 readBuffer(MEDIA_TRACK_TYPE_AUDIO);
Andreas Huberafed0e12011-09-20 15:39:58 -0700191 }
192
193 if (mVideoTrack.mSource != NULL) {
Robert Shihbace25b2014-07-25 14:14:34 -0700194 CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK);
Andreas Huberafed0e12011-09-20 15:39:58 -0700195 mVideoTrack.mPackets =
196 new AnotherPacketSource(mVideoTrack.mSource->getFormat());
197
Robert Shih05312bc2014-07-16 15:47:09 -0700198 readBuffer(MEDIA_TRACK_TYPE_VIDEO);
Andreas Huberafed0e12011-09-20 15:39:58 -0700199 }
200}
201
202status_t NuPlayer::GenericSource::feedMoreTSData() {
203 return OK;
204}
205
Robert Shih05312bc2014-07-16 15:47:09 -0700206void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
207 switch (msg->what()) {
208 case kWhatFetchSubtitleData:
209 {
Robert Shiheb1735e2014-07-23 15:53:14 -0700210 fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
211 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
212 break;
213 }
Robert Shih05312bc2014-07-16 15:47:09 -0700214
Robert Shiheb1735e2014-07-23 15:53:14 -0700215 case kWhatFetchTimedTextData:
216 {
217 fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
218 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
Robert Shih05312bc2014-07-16 15:47:09 -0700219 break;
220 }
221
222 case kWhatSendSubtitleData:
223 {
Robert Shiheb1735e2014-07-23 15:53:14 -0700224 sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
225 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
226 break;
227 }
Robert Shih05312bc2014-07-16 15:47:09 -0700228
Robert Shiheb1735e2014-07-23 15:53:14 -0700229 case kWhatSendTimedTextData:
230 {
231 sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
232 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
Robert Shih05312bc2014-07-16 15:47:09 -0700233 break;
234 }
235
236 case kWhatChangeAVSource:
237 {
238 int32_t trackIndex;
239 CHECK(msg->findInt32("trackIndex", &trackIndex));
240 const sp<MediaSource> source = mSources.itemAt(trackIndex);
241
242 Track* track;
243 const char *mime;
244 media_track_type trackType, counterpartType;
245 sp<MetaData> meta = source->getFormat();
246 meta->findCString(kKeyMIMEType, &mime);
247 if (!strncasecmp(mime, "audio/", 6)) {
248 track = &mAudioTrack;
249 trackType = MEDIA_TRACK_TYPE_AUDIO;
250 counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
251 } else {
252 CHECK(!strncasecmp(mime, "video/", 6));
253 track = &mVideoTrack;
254 trackType = MEDIA_TRACK_TYPE_VIDEO;
255 counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
256 }
257
258
Robert Shihbace25b2014-07-25 14:14:34 -0700259 if (track->mSource != NULL) {
260 track->mSource->stop();
261 }
Robert Shih05312bc2014-07-16 15:47:09 -0700262 track->mSource = source;
Robert Shihbace25b2014-07-25 14:14:34 -0700263 track->mSource->start();
Robert Shih05312bc2014-07-16 15:47:09 -0700264 track->mIndex = trackIndex;
265
266 status_t avail;
267 if (!track->mPackets->hasBufferAvailable(&avail)) {
268 // sync from other source
269 TRESPASS();
270 break;
271 }
272
273 int64_t timeUs, actualTimeUs;
274 const bool formatChange = true;
275 sp<AMessage> latestMeta = track->mPackets->getLatestMeta();
276 CHECK(latestMeta != NULL && latestMeta->findInt64("timeUs", &timeUs));
277 readBuffer(trackType, timeUs, &actualTimeUs, formatChange);
278 readBuffer(counterpartType, -1, NULL, formatChange);
279 ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs);
280
281 break;
282 }
283
284 default:
285 Source::onMessageReceived(msg);
286 break;
287 }
288}
289
Robert Shiheb1735e2014-07-23 15:53:14 -0700290void NuPlayer::GenericSource::fetchTextData(
291 uint32_t sendWhat,
292 media_track_type type,
293 int32_t curGen,
294 sp<AnotherPacketSource> packets,
295 sp<AMessage> msg) {
296 int32_t msgGeneration;
297 CHECK(msg->findInt32("generation", &msgGeneration));
298 if (msgGeneration != curGen) {
299 // stale
300 return;
301 }
302
303 int32_t avail;
304 if (packets->hasBufferAvailable(&avail)) {
305 return;
306 }
307
308 int64_t timeUs;
309 CHECK(msg->findInt64("timeUs", &timeUs));
310
311 int64_t subTimeUs;
312 readBuffer(type, timeUs, &subTimeUs);
313
314 int64_t delayUs = subTimeUs - timeUs;
315 if (msg->what() == kWhatFetchSubtitleData) {
316 const int64_t oneSecUs = 1000000ll;
317 delayUs -= oneSecUs;
318 }
319 sp<AMessage> msg2 = new AMessage(sendWhat, id());
320 msg2->setInt32("generation", msgGeneration);
321 msg2->post(delayUs < 0 ? 0 : delayUs);
322}
323
324void NuPlayer::GenericSource::sendTextData(
325 uint32_t what,
326 media_track_type type,
327 int32_t curGen,
328 sp<AnotherPacketSource> packets,
329 sp<AMessage> msg) {
330 int32_t msgGeneration;
331 CHECK(msg->findInt32("generation", &msgGeneration));
332 if (msgGeneration != curGen) {
333 // stale
334 return;
335 }
336
337 int64_t subTimeUs;
338 if (packets->nextBufferTime(&subTimeUs) != OK) {
339 return;
340 }
341
342 int64_t nextSubTimeUs;
343 readBuffer(type, -1, &nextSubTimeUs);
344
345 sp<ABuffer> buffer;
346 status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
347 if (dequeueStatus == OK) {
348 sp<AMessage> notify = dupNotify();
349 notify->setInt32("what", what);
350 notify->setBuffer("buffer", buffer);
351 notify->post();
352
353 const int64_t delayUs = nextSubTimeUs - subTimeUs;
354 msg->post(delayUs < 0 ? 0 : delayUs);
355 }
356}
357
Andreas Huber84066782011-08-16 09:34:26 -0700358sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
Andreas Huberafed0e12011-09-20 15:39:58 -0700359 sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
360
361 if (source == NULL) {
362 return NULL;
363 }
364
365 return source->getFormat();
366}
367
368status_t NuPlayer::GenericSource::dequeueAccessUnit(
369 bool audio, sp<ABuffer> *accessUnit) {
370 Track *track = audio ? &mAudioTrack : &mVideoTrack;
371
372 if (track->mSource == NULL) {
373 return -EWOULDBLOCK;
374 }
375
Lajos Molnarcc227032014-07-17 15:33:06 -0700376 if (mIsWidevine && !audio) {
377 // try to read a buffer as we may not have been able to the last time
Robert Shih05312bc2014-07-16 15:47:09 -0700378 readBuffer(MEDIA_TRACK_TYPE_AUDIO, -1ll);
Lajos Molnarcc227032014-07-17 15:33:06 -0700379 }
380
Andreas Huberafed0e12011-09-20 15:39:58 -0700381 status_t finalResult;
382 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
Lajos Molnarcc227032014-07-17 15:33:06 -0700383 return (finalResult == OK ? -EWOULDBLOCK : finalResult);
Andreas Huberafed0e12011-09-20 15:39:58 -0700384 }
385
386 status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
387
Robert Shih05312bc2014-07-16 15:47:09 -0700388 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
389 readBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO, -1ll);
390 }
391
Robert Shiheb1735e2014-07-23 15:53:14 -0700392 if (mSubtitleTrack.mSource == NULL && mTimedTextTrack.mSource == NULL) {
Robert Shih05312bc2014-07-16 15:47:09 -0700393 return result;
394 }
395
Robert Shiheb1735e2014-07-23 15:53:14 -0700396 if (mSubtitleTrack.mSource != NULL) {
397 CHECK(mSubtitleTrack.mPackets != NULL);
398 }
399 if (mTimedTextTrack.mSource != NULL) {
400 CHECK(mTimedTextTrack.mPackets != NULL);
401 }
402
Robert Shih05312bc2014-07-16 15:47:09 -0700403 if (result != OK) {
Robert Shiheb1735e2014-07-23 15:53:14 -0700404 if (mSubtitleTrack.mSource != NULL) {
405 mSubtitleTrack.mPackets->clear();
406 mFetchSubtitleDataGeneration++;
407 }
408 if (mTimedTextTrack.mSource != NULL) {
409 mTimedTextTrack.mPackets->clear();
410 mFetchTimedTextDataGeneration++;
411 }
Robert Shih05312bc2014-07-16 15:47:09 -0700412 return result;
413 }
414
415 int64_t timeUs;
416 status_t eosResult; // ignored
417 CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
Robert Shiheb1735e2014-07-23 15:53:14 -0700418
419 if (mSubtitleTrack.mSource != NULL
420 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
Robert Shih05312bc2014-07-16 15:47:09 -0700421 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
422 msg->setInt64("timeUs", timeUs);
423 msg->setInt32("generation", mFetchSubtitleDataGeneration);
424 msg->post();
425 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700426
Robert Shiheb1735e2014-07-23 15:53:14 -0700427 if (mTimedTextTrack.mSource != NULL
428 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
429 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
430 msg->setInt64("timeUs", timeUs);
431 msg->setInt32("generation", mFetchTimedTextDataGeneration);
432 msg->post();
433 }
434
Andreas Huberafed0e12011-09-20 15:39:58 -0700435 return result;
436}
437
438status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
439 *durationUs = mDurationUs;
440 return OK;
441}
442
Robert Shihdd235722014-06-12 14:49:23 -0700443size_t NuPlayer::GenericSource::getTrackCount() const {
444 return mSources.size();
445}
446
447sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
448 size_t trackCount = mSources.size();
449 if (trackIndex >= trackCount) {
450 return NULL;
451 }
452
453 sp<AMessage> format = new AMessage();
454 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
455
456 const char *mime;
457 CHECK(meta->findCString(kKeyMIMEType, &mime));
458
459 int32_t trackType;
460 if (!strncasecmp(mime, "video/", 6)) {
461 trackType = MEDIA_TRACK_TYPE_VIDEO;
462 } else if (!strncasecmp(mime, "audio/", 6)) {
463 trackType = MEDIA_TRACK_TYPE_AUDIO;
464 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
465 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
466 } else {
467 trackType = MEDIA_TRACK_TYPE_UNKNOWN;
468 }
469 format->setInt32("type", trackType);
470
471 const char *lang;
472 if (!meta->findCString(kKeyMediaLanguage, &lang)) {
473 lang = "und";
474 }
475 format->setString("language", lang);
476
477 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
478 format->setString("mime", mime);
479
480 int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
481 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
482 meta->findInt32(kKeyTrackIsDefault, &isDefault);
483 meta->findInt32(kKeyTrackIsForced, &isForced);
484
485 format->setInt32("auto", !!isAutoselect);
486 format->setInt32("default", !!isDefault);
487 format->setInt32("forced", !!isForced);
488 }
489
490 return format;
491}
492
Robert Shiheb1735e2014-07-23 15:53:14 -0700493ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
494 const Track *track = NULL;
495 switch (type) {
496 case MEDIA_TRACK_TYPE_VIDEO:
497 track = &mVideoTrack;
498 break;
499 case MEDIA_TRACK_TYPE_AUDIO:
500 track = &mAudioTrack;
501 break;
502 case MEDIA_TRACK_TYPE_TIMEDTEXT:
503 track = &mTimedTextTrack;
504 break;
505 case MEDIA_TRACK_TYPE_SUBTITLE:
506 track = &mSubtitleTrack;
507 break;
508 default:
509 break;
510 }
511
512 if (track != NULL && track->mSource != NULL) {
513 return track->mIndex;
514 }
515
516 return -1;
517}
518
Robert Shih05312bc2014-07-16 15:47:09 -0700519status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) {
Robert Shiheb1735e2014-07-23 15:53:14 -0700520 ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
Robert Shih05312bc2014-07-16 15:47:09 -0700521 if (trackIndex >= mSources.size()) {
522 return BAD_INDEX;
523 }
524
525 if (!select) {
Robert Shiheb1735e2014-07-23 15:53:14 -0700526 Track* track = NULL;
527 if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) {
528 track = &mSubtitleTrack;
529 mFetchSubtitleDataGeneration++;
530 } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) {
531 track = &mTimedTextTrack;
532 mFetchTimedTextDataGeneration++;
533 }
534 if (track == NULL) {
Robert Shih05312bc2014-07-16 15:47:09 -0700535 return INVALID_OPERATION;
536 }
Robert Shihbace25b2014-07-25 14:14:34 -0700537 track->mSource->stop();
Robert Shiheb1735e2014-07-23 15:53:14 -0700538 track->mSource = NULL;
539 track->mPackets->clear();
Robert Shih05312bc2014-07-16 15:47:09 -0700540 return OK;
541 }
542
543 const sp<MediaSource> source = mSources.itemAt(trackIndex);
544 sp<MetaData> meta = source->getFormat();
545 const char *mime;
546 CHECK(meta->findCString(kKeyMIMEType, &mime));
547 if (!strncasecmp(mime, "text/", 5)) {
Robert Shiheb1735e2014-07-23 15:53:14 -0700548 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
549 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
550 if (track->mSource != NULL && track->mIndex == trackIndex) {
Robert Shih05312bc2014-07-16 15:47:09 -0700551 return OK;
552 }
Robert Shiheb1735e2014-07-23 15:53:14 -0700553 track->mIndex = trackIndex;
Robert Shihbace25b2014-07-25 14:14:34 -0700554 if (track->mSource != NULL) {
555 track->mSource->stop();
556 }
Robert Shiheb1735e2014-07-23 15:53:14 -0700557 track->mSource = mSources.itemAt(trackIndex);
Robert Shihbace25b2014-07-25 14:14:34 -0700558 track->mSource->start();
Robert Shiheb1735e2014-07-23 15:53:14 -0700559 if (track->mPackets == NULL) {
560 track->mPackets = new AnotherPacketSource(track->mSource->getFormat());
Robert Shih05312bc2014-07-16 15:47:09 -0700561 } else {
Robert Shiheb1735e2014-07-23 15:53:14 -0700562 track->mPackets->clear();
563 track->mPackets->setFormat(track->mSource->getFormat());
Robert Shih05312bc2014-07-16 15:47:09 -0700564
565 }
Robert Shiheb1735e2014-07-23 15:53:14 -0700566
567 if (isSubtitle) {
568 mFetchSubtitleDataGeneration++;
569 } else {
570 mFetchTimedTextDataGeneration++;
571 }
572
Robert Shih05312bc2014-07-16 15:47:09 -0700573 return OK;
574 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
575 bool audio = !strncasecmp(mime, "audio/", 6);
576 Track *track = audio ? &mAudioTrack : &mVideoTrack;
577 if (track->mSource != NULL && track->mIndex == trackIndex) {
578 return OK;
579 }
580
581 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id());
582 msg->setInt32("trackIndex", trackIndex);
583 msg->post();
584 return OK;
585 }
586
587 return INVALID_OPERATION;
588}
589
Andreas Huberafed0e12011-09-20 15:39:58 -0700590status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
591 if (mVideoTrack.mSource != NULL) {
592 int64_t actualTimeUs;
Robert Shih05312bc2014-07-16 15:47:09 -0700593 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -0700594
595 seekTimeUs = actualTimeUs;
596 }
597
598 if (mAudioTrack.mSource != NULL) {
Robert Shih05312bc2014-07-16 15:47:09 -0700599 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -0700600 }
601
602 return OK;
603}
604
Robert Shih05312bc2014-07-16 15:47:09 -0700605sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
606 MediaBuffer* mb,
607 media_track_type trackType,
608 int64_t *actualTimeUs) {
609 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
610 size_t outLength = mb->range_length();
611
612 if (audio && mAudioIsVorbis) {
613 outLength += sizeof(int32_t);
614 }
615
616 sp<ABuffer> ab;
617 if (mIsWidevine && !audio) {
618 // data is already provided in the buffer
619 ab = new ABuffer(NULL, mb->range_length());
620 ab->meta()->setPointer("mediaBuffer", mb);
621 mb->add_ref();
622 } else {
623 ab = new ABuffer(outLength);
624 memcpy(ab->data(),
625 (const uint8_t *)mb->data() + mb->range_offset(),
626 mb->range_length());
627 }
628
629 if (audio && mAudioIsVorbis) {
630 int32_t numPageSamples;
631 if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
632 numPageSamples = -1;
633 }
634
635 uint8_t* abEnd = ab->data() + mb->range_length();
636 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
637 }
638
Robert Shiheb1735e2014-07-23 15:53:14 -0700639 sp<AMessage> meta = ab->meta();
640
Robert Shih05312bc2014-07-16 15:47:09 -0700641 int64_t timeUs;
642 CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs));
Robert Shih05312bc2014-07-16 15:47:09 -0700643 meta->setInt64("timeUs", timeUs);
644
Robert Shiheb1735e2014-07-23 15:53:14 -0700645 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
646 const char *mime;
647 CHECK(mTimedTextTrack.mSource != NULL
648 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime));
649 meta->setString("mime", mime);
650 }
651
Robert Shih05312bc2014-07-16 15:47:09 -0700652 int64_t durationUs;
653 if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) {
654 meta->setInt64("durationUs", durationUs);
655 }
656
657 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
658 meta->setInt32("trackIndex", mSubtitleTrack.mIndex);
659 }
660
661 if (actualTimeUs) {
662 *actualTimeUs = timeUs;
663 }
664
665 mb->release();
666 mb = NULL;
667
668 return ab;
669}
670
Andreas Huberafed0e12011-09-20 15:39:58 -0700671void NuPlayer::GenericSource::readBuffer(
Robert Shih05312bc2014-07-16 15:47:09 -0700672 media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
673 Track *track;
674 switch (trackType) {
675 case MEDIA_TRACK_TYPE_VIDEO:
676 track = &mVideoTrack;
677 break;
678 case MEDIA_TRACK_TYPE_AUDIO:
679 track = &mAudioTrack;
680 break;
681 case MEDIA_TRACK_TYPE_SUBTITLE:
682 track = &mSubtitleTrack;
683 break;
Robert Shiheb1735e2014-07-23 15:53:14 -0700684 case MEDIA_TRACK_TYPE_TIMEDTEXT:
685 track = &mTimedTextTrack;
686 break;
Robert Shih05312bc2014-07-16 15:47:09 -0700687 default:
688 TRESPASS();
689 }
690
691 if (track->mSource == NULL) {
692 return;
693 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700694
695 if (actualTimeUs) {
696 *actualTimeUs = seekTimeUs;
697 }
698
699 MediaSource::ReadOptions options;
700
701 bool seeking = false;
702
703 if (seekTimeUs >= 0) {
Robert Shih05312bc2014-07-16 15:47:09 -0700704 options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
Andreas Huberafed0e12011-09-20 15:39:58 -0700705 seeking = true;
706 }
707
Robert Shih05312bc2014-07-16 15:47:09 -0700708 if (mIsWidevine && trackType != MEDIA_TRACK_TYPE_AUDIO) {
Lajos Molnarcc227032014-07-17 15:33:06 -0700709 options.setNonBlocking();
710 }
711
Andreas Huberafed0e12011-09-20 15:39:58 -0700712 for (;;) {
713 MediaBuffer *mbuf;
714 status_t err = track->mSource->read(&mbuf, &options);
715
716 options.clearSeekTo();
717
718 if (err == OK) {
Robert Shih05312bc2014-07-16 15:47:09 -0700719 // formatChange && seeking: track whose source is changed during selection
720 // formatChange && !seeking: track whose source is not changed during selection
721 // !formatChange: normal seek
Robert Shiheb1735e2014-07-23 15:53:14 -0700722 if ((seeking || formatChange)
723 && (trackType == MEDIA_TRACK_TYPE_AUDIO
724 || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
Robert Shih05312bc2014-07-16 15:47:09 -0700725 ATSParser::DiscontinuityType type = formatChange
726 ? (seeking
727 ? ATSParser::DISCONTINUITY_FORMATCHANGE
728 : ATSParser::DISCONTINUITY_NONE)
729 : ATSParser::DISCONTINUITY_SEEK;
730 track->mPackets->queueDiscontinuity( type, NULL, true /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -0700731 }
732
Robert Shih05312bc2014-07-16 15:47:09 -0700733 sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -0700734 track->mPackets->queueAccessUnit(buffer);
735 break;
Lajos Molnarcc227032014-07-17 15:33:06 -0700736 } else if (err == WOULD_BLOCK) {
737 break;
Andreas Huberafed0e12011-09-20 15:39:58 -0700738 } else if (err == INFO_FORMAT_CHANGED) {
739#if 0
740 track->mPackets->queueDiscontinuity(
Chong Zhang632740c2014-06-26 13:03:47 -0700741 ATSParser::DISCONTINUITY_FORMATCHANGE,
742 NULL,
743 false /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -0700744#endif
745 } else {
746 track->mPackets->signalEOS(err);
747 break;
748 }
749 }
750}
751
Andreas Huberafed0e12011-09-20 15:39:58 -0700752} // namespace android