GenericSource.cpp revision 3423bbdb05f843a64356fa24e8657f03ecbb7d65
1/*
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>
31#include "../../libstagefright/include/WVMExtractor.h"
32
33namespace android {
34
35NuPlayer::GenericSource::GenericSource(
36        const sp<AMessage> &notify,
37        const sp<IMediaHTTPService> &httpService,
38        const char *url,
39        const KeyedVector<String8, String8> *headers,
40        bool isWidevine,
41        bool uidValid,
42        uid_t uid)
43    : Source(notify),
44      mFetchSubtitleDataGeneration(0),
45      mDurationUs(0ll),
46      mAudioIsVorbis(false),
47      mIsWidevine(isWidevine),
48      mUIDValid(uidValid),
49      mUID(uid) {
50    DataSource::RegisterDefaultSniffers();
51
52    sp<DataSource> dataSource =
53        DataSource::CreateFromURI(httpService, url, headers);
54    CHECK(dataSource != NULL);
55
56    initFromDataSource(dataSource);
57}
58
59NuPlayer::GenericSource::GenericSource(
60        const sp<AMessage> &notify,
61        int fd, int64_t offset, int64_t length)
62    : Source(notify),
63      mFetchSubtitleDataGeneration(0),
64      mDurationUs(0ll),
65      mAudioIsVorbis(false),
66      mIsWidevine(false) {
67    DataSource::RegisterDefaultSniffers();
68
69    sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
70
71    initFromDataSource(dataSource);
72}
73
74void NuPlayer::GenericSource::initFromDataSource(
75        const sp<DataSource> &dataSource) {
76    sp<MediaExtractor> extractor;
77
78    if (mIsWidevine) {
79        String8 mimeType;
80        float confidence;
81        sp<AMessage> dummy;
82        bool success;
83
84        success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
85        if (!success
86                || strcasecmp(
87                    mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
88            ALOGE("unsupported widevine mime: %s", mimeType.string());
89            return;
90        }
91
92        sp<WVMExtractor> wvmExtractor = new WVMExtractor(dataSource);
93        wvmExtractor->setAdaptiveStreamingMode(true);
94        if (mUIDValid) {
95            wvmExtractor->setUID(mUID);
96        }
97        extractor = wvmExtractor;
98    } else {
99        extractor = MediaExtractor::Create(dataSource);
100    }
101
102    CHECK(extractor != NULL);
103
104    sp<MetaData> fileMeta = extractor->getMetaData();
105    if (fileMeta != NULL) {
106        int64_t duration;
107        if (fileMeta->findInt64(kKeyDuration, &duration)) {
108            mDurationUs = duration;
109        }
110    }
111
112    for (size_t i = 0; i < extractor->countTracks(); ++i) {
113        sp<MetaData> meta = extractor->getTrackMetaData(i);
114
115        const char *mime;
116        CHECK(meta->findCString(kKeyMIMEType, &mime));
117
118        sp<MediaSource> track = extractor->getTrack(i);
119
120        if (!strncasecmp(mime, "audio/", 6)) {
121            if (mAudioTrack.mSource == NULL) {
122                mAudioTrack.mIndex = i;
123                mAudioTrack.mSource = track;
124
125                if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
126                    mAudioIsVorbis = true;
127                } else {
128                    mAudioIsVorbis = false;
129                }
130            }
131        } else if (!strncasecmp(mime, "video/", 6)) {
132            if (mVideoTrack.mSource == NULL) {
133                mVideoTrack.mIndex = i;
134                mVideoTrack.mSource = track;
135            }
136        }
137
138        if (track != NULL) {
139            mSources.push(track);
140            int64_t durationUs;
141            if (meta->findInt64(kKeyDuration, &durationUs)) {
142                if (durationUs > mDurationUs) {
143                    mDurationUs = durationUs;
144                }
145            }
146        }
147    }
148}
149
150status_t NuPlayer::GenericSource::setBuffers(bool audio, Vector<MediaBuffer *> &buffers) {
151    if (mIsWidevine && !audio) {
152        return mVideoTrack.mSource->setBuffers(buffers);
153    }
154    return INVALID_OPERATION;
155}
156
157NuPlayer::GenericSource::~GenericSource() {
158}
159
160void NuPlayer::GenericSource::prepareAsync() {
161    if (mVideoTrack.mSource != NULL) {
162        sp<MetaData> meta = mVideoTrack.mSource->getFormat();
163
164        int32_t width, height;
165        CHECK(meta->findInt32(kKeyWidth, &width));
166        CHECK(meta->findInt32(kKeyHeight, &height));
167
168        notifyVideoSizeChanged(width, height);
169    }
170
171    notifyFlagsChanged(
172            (mIsWidevine ? FLAG_SECURE : 0)
173            | FLAG_CAN_PAUSE
174            | FLAG_CAN_SEEK_BACKWARD
175            | FLAG_CAN_SEEK_FORWARD
176            | FLAG_CAN_SEEK);
177
178    notifyPrepared();
179}
180
181void NuPlayer::GenericSource::start() {
182    ALOGI("start");
183
184    if (mAudioTrack.mSource != NULL) {
185        CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);
186        mAudioTrack.mPackets =
187            new AnotherPacketSource(mAudioTrack.mSource->getFormat());
188
189        readBuffer(MEDIA_TRACK_TYPE_AUDIO);
190    }
191
192    if (mVideoTrack.mSource != NULL) {
193        CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK);
194        mVideoTrack.mPackets =
195            new AnotherPacketSource(mVideoTrack.mSource->getFormat());
196
197        readBuffer(MEDIA_TRACK_TYPE_VIDEO);
198    }
199}
200
201status_t NuPlayer::GenericSource::feedMoreTSData() {
202    return OK;
203}
204
205void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
206    switch (msg->what()) {
207      case kWhatFetchSubtitleData:
208      {
209          int32_t generation;
210          CHECK(msg->findInt32("generation", &generation));
211          if (generation != mFetchSubtitleDataGeneration) {
212              // stale
213              break;
214          }
215
216          int32_t avail;
217          if (mSubtitleTrack.mPackets->hasBufferAvailable(&avail)) {
218              break;
219          }
220
221          int64_t timeUs;
222          CHECK(msg->findInt64("timeUs", &timeUs));
223
224          int64_t subTimeUs;
225          readBuffer(MEDIA_TRACK_TYPE_SUBTITLE, timeUs, &subTimeUs);
226
227          const int64_t oneSecUs = 1000000ll;
228          const int64_t delayUs = subTimeUs - timeUs - oneSecUs;
229          sp<AMessage> msg2 = new AMessage(kWhatSendSubtitleData, id());
230          msg2->setInt32("generation", generation);
231          msg2->post(delayUs < 0 ? 0 : delayUs);
232          ALOGV("kWhatFetchSubtitleData generation %d, delayUs %lld",
233                  mFetchSubtitleDataGeneration, delayUs);
234
235          break;
236      }
237
238      case kWhatSendSubtitleData:
239      {
240          int32_t generation;
241          CHECK(msg->findInt32("generation", &generation));
242          if (generation != mFetchSubtitleDataGeneration) {
243              // stale
244              break;
245          }
246
247          int64_t subTimeUs;
248          if (mSubtitleTrack.mPackets->nextBufferTime(&subTimeUs) != OK) {
249              break;
250          }
251
252          int64_t nextSubTimeUs;
253          readBuffer(MEDIA_TRACK_TYPE_SUBTITLE, -1, &nextSubTimeUs);
254
255          sp<ABuffer> buffer;
256          status_t dequeueStatus = mSubtitleTrack.mPackets->dequeueAccessUnit(&buffer);
257          if (dequeueStatus != OK) {
258              ALOGE("kWhatSendSubtitleData dequeueAccessUnit: %d", dequeueStatus);
259          } else {
260              sp<AMessage> notify = dupNotify();
261              notify->setInt32("what", kWhatSubtitleData);
262              notify->setBuffer("buffer", buffer);
263              notify->post();
264
265              const int64_t delayUs = nextSubTimeUs - subTimeUs;
266              msg->post(delayUs < 0 ? 0 : delayUs);
267          }
268
269          break;
270      }
271
272      case kWhatChangeAVSource:
273      {
274          int32_t trackIndex;
275          CHECK(msg->findInt32("trackIndex", &trackIndex));
276          const sp<MediaSource> source = mSources.itemAt(trackIndex);
277
278          Track* track;
279          const char *mime;
280          media_track_type trackType, counterpartType;
281          sp<MetaData> meta = source->getFormat();
282          meta->findCString(kKeyMIMEType, &mime);
283          if (!strncasecmp(mime, "audio/", 6)) {
284              track = &mAudioTrack;
285              trackType = MEDIA_TRACK_TYPE_AUDIO;
286              counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
287          } else {
288              CHECK(!strncasecmp(mime, "video/", 6));
289              track = &mVideoTrack;
290              trackType = MEDIA_TRACK_TYPE_VIDEO;
291              counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
292          }
293
294
295          if (track->mSource != NULL) {
296              track->mSource->stop();
297          }
298          track->mSource = source;
299          track->mSource->start();
300          track->mIndex = trackIndex;
301
302          status_t avail;
303          if (!track->mPackets->hasBufferAvailable(&avail)) {
304              // sync from other source
305              TRESPASS();
306              break;
307          }
308
309          int64_t timeUs, actualTimeUs;
310          const bool formatChange = true;
311          sp<AMessage> latestMeta = track->mPackets->getLatestMeta();
312          CHECK(latestMeta != NULL && latestMeta->findInt64("timeUs", &timeUs));
313          readBuffer(trackType, timeUs, &actualTimeUs, formatChange);
314          readBuffer(counterpartType, -1, NULL, formatChange);
315          ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs);
316
317          break;
318      }
319
320      default:
321          Source::onMessageReceived(msg);
322          break;
323    }
324}
325
326sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
327    sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
328
329    if (source == NULL) {
330        return NULL;
331    }
332
333    return source->getFormat();
334}
335
336status_t NuPlayer::GenericSource::dequeueAccessUnit(
337        bool audio, sp<ABuffer> *accessUnit) {
338    Track *track = audio ? &mAudioTrack : &mVideoTrack;
339
340    if (track->mSource == NULL) {
341        return -EWOULDBLOCK;
342    }
343
344    if (mIsWidevine && !audio) {
345        // try to read a buffer as we may not have been able to the last time
346        readBuffer(MEDIA_TRACK_TYPE_VIDEO, -1ll);
347    }
348
349    status_t finalResult;
350    if (!track->mPackets->hasBufferAvailable(&finalResult)) {
351        return (finalResult == OK ? -EWOULDBLOCK : finalResult);
352    }
353
354    status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
355
356    if (!track->mPackets->hasBufferAvailable(&finalResult)) {
357        readBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO, -1ll);
358    }
359
360    if (mSubtitleTrack.mSource == NULL) {
361        return result;
362    }
363
364    CHECK(mSubtitleTrack.mPackets != NULL);
365    if (result != OK) {
366        mSubtitleTrack.mPackets->clear();
367        mFetchSubtitleDataGeneration++;
368        return result;
369    }
370
371    int64_t timeUs;
372    status_t eosResult; // ignored
373    CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
374    if (!mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
375        sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
376        msg->setInt64("timeUs", timeUs);
377        msg->setInt32("generation", mFetchSubtitleDataGeneration);
378        msg->post();
379    }
380
381    return result;
382}
383
384status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
385    *durationUs = mDurationUs;
386    return OK;
387}
388
389size_t NuPlayer::GenericSource::getTrackCount() const {
390    return mSources.size();
391}
392
393sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
394    size_t trackCount = mSources.size();
395    if (trackIndex >= trackCount) {
396        return NULL;
397    }
398
399    sp<AMessage> format = new AMessage();
400    sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
401
402    const char *mime;
403    CHECK(meta->findCString(kKeyMIMEType, &mime));
404
405    int32_t trackType;
406    if (!strncasecmp(mime, "video/", 6)) {
407        trackType = MEDIA_TRACK_TYPE_VIDEO;
408    } else if (!strncasecmp(mime, "audio/", 6)) {
409        trackType = MEDIA_TRACK_TYPE_AUDIO;
410    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
411        trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
412    } else {
413        trackType = MEDIA_TRACK_TYPE_UNKNOWN;
414    }
415    format->setInt32("type", trackType);
416
417    const char *lang;
418    if (!meta->findCString(kKeyMediaLanguage, &lang)) {
419        lang = "und";
420    }
421    format->setString("language", lang);
422
423    if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
424        format->setString("mime", mime);
425
426        int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
427        meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
428        meta->findInt32(kKeyTrackIsDefault, &isDefault);
429        meta->findInt32(kKeyTrackIsForced, &isForced);
430
431        format->setInt32("auto", !!isAutoselect);
432        format->setInt32("default", !!isDefault);
433        format->setInt32("forced", !!isForced);
434    }
435
436    return format;
437}
438
439status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) {
440    ALOGV("selectTrack: %zu", trackIndex);
441    if (trackIndex >= mSources.size()) {
442        return BAD_INDEX;
443    }
444
445    if (!select) {
446        if (mSubtitleTrack.mSource == NULL || trackIndex != mSubtitleTrack.mIndex) {
447            return INVALID_OPERATION;
448        }
449        mSubtitleTrack.mSource->stop();
450        mSubtitleTrack.mSource = NULL;
451        mSubtitleTrack.mPackets->clear();
452        mFetchSubtitleDataGeneration++;
453        return OK;
454    }
455
456    const sp<MediaSource> source = mSources.itemAt(trackIndex);
457    sp<MetaData> meta = source->getFormat();
458    const char *mime;
459    CHECK(meta->findCString(kKeyMIMEType, &mime));
460    if (!strncasecmp(mime, "text/", 5)) {
461        if (mSubtitleTrack.mSource != NULL && mSubtitleTrack.mIndex == trackIndex) {
462            return OK;
463        }
464        mSubtitleTrack.mIndex = trackIndex;
465        if (mSubtitleTrack.mSource != NULL) {
466            mSubtitleTrack.mSource->stop();
467        }
468        mSubtitleTrack.mSource = mSources.itemAt(trackIndex);
469        mSubtitleTrack.mSource->start();
470        if (mSubtitleTrack.mPackets == NULL) {
471            mSubtitleTrack.mPackets = new AnotherPacketSource(mSubtitleTrack.mSource->getFormat());
472        } else {
473            mSubtitleTrack.mPackets->clear();
474
475        }
476        mFetchSubtitleDataGeneration++;
477        return OK;
478    } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
479        bool audio = !strncasecmp(mime, "audio/", 6);
480        Track *track = audio ? &mAudioTrack : &mVideoTrack;
481        if (track->mSource != NULL && track->mIndex == trackIndex) {
482            return OK;
483        }
484
485        sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id());
486        msg->setInt32("trackIndex", trackIndex);
487        msg->post();
488        return OK;
489    }
490
491    return INVALID_OPERATION;
492}
493
494status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
495    if (mVideoTrack.mSource != NULL) {
496        int64_t actualTimeUs;
497        readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
498
499        seekTimeUs = actualTimeUs;
500    }
501
502    if (mAudioTrack.mSource != NULL) {
503        readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
504    }
505
506    return OK;
507}
508
509sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
510        MediaBuffer* mb,
511        media_track_type trackType,
512        int64_t *actualTimeUs) {
513    bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
514    size_t outLength = mb->range_length();
515
516    if (audio && mAudioIsVorbis) {
517        outLength += sizeof(int32_t);
518    }
519
520    sp<ABuffer> ab;
521    if (mIsWidevine && !audio) {
522        // data is already provided in the buffer
523        ab = new ABuffer(NULL, mb->range_length());
524        ab->meta()->setPointer("mediaBuffer", mb);
525        mb->add_ref();
526    } else {
527        ab = new ABuffer(outLength);
528        memcpy(ab->data(),
529               (const uint8_t *)mb->data() + mb->range_offset(),
530               mb->range_length());
531    }
532
533    if (audio && mAudioIsVorbis) {
534        int32_t numPageSamples;
535        if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
536            numPageSamples = -1;
537        }
538
539        uint8_t* abEnd = ab->data() + mb->range_length();
540        memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
541    }
542
543    int64_t timeUs;
544    CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs));
545
546    sp<AMessage> meta = ab->meta();
547    meta->setInt64("timeUs", timeUs);
548
549    int64_t durationUs;
550    if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) {
551        meta->setInt64("durationUs", durationUs);
552    }
553
554    if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
555        meta->setInt32("trackIndex", mSubtitleTrack.mIndex);
556    }
557
558    if (actualTimeUs) {
559        *actualTimeUs = timeUs;
560    }
561
562    mb->release();
563    mb = NULL;
564
565    return ab;
566}
567
568void NuPlayer::GenericSource::readBuffer(
569        media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
570    Track *track;
571    switch (trackType) {
572        case MEDIA_TRACK_TYPE_VIDEO:
573            track = &mVideoTrack;
574            break;
575        case MEDIA_TRACK_TYPE_AUDIO:
576            track = &mAudioTrack;
577            break;
578        case MEDIA_TRACK_TYPE_SUBTITLE:
579            track = &mSubtitleTrack;
580            break;
581        default:
582            TRESPASS();
583    }
584
585    if (track->mSource == NULL) {
586        return;
587    }
588
589    if (actualTimeUs) {
590        *actualTimeUs = seekTimeUs;
591    }
592
593    MediaSource::ReadOptions options;
594
595    bool seeking = false;
596
597    if (seekTimeUs >= 0) {
598        options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
599        seeking = true;
600    }
601
602    if (mIsWidevine && trackType != MEDIA_TRACK_TYPE_AUDIO) {
603        options.setNonBlocking();
604    }
605
606    for (;;) {
607        MediaBuffer *mbuf;
608        status_t err = track->mSource->read(&mbuf, &options);
609
610        options.clearSeekTo();
611
612        if (err == OK) {
613            // formatChange && seeking: track whose source is changed during selection
614            // formatChange && !seeking: track whose source is not changed during selection
615            // !formatChange: normal seek
616            if ((seeking || formatChange) && trackType != MEDIA_TRACK_TYPE_SUBTITLE) {
617                ATSParser::DiscontinuityType type = formatChange
618                        ? (seeking
619                                ? ATSParser::DISCONTINUITY_FORMATCHANGE
620                                : ATSParser::DISCONTINUITY_NONE)
621                        : ATSParser::DISCONTINUITY_SEEK;
622                track->mPackets->queueDiscontinuity( type, NULL, true /* discard */);
623            }
624
625            sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs);
626            track->mPackets->queueAccessUnit(buffer);
627            break;
628        } else if (err == WOULD_BLOCK) {
629            break;
630        } else if (err == INFO_FORMAT_CHANGED) {
631#if 0
632            track->mPackets->queueDiscontinuity(
633                    ATSParser::DISCONTINUITY_FORMATCHANGE,
634                    NULL,
635                    false /* discard */);
636#endif
637        } else {
638            track->mPackets->signalEOS(err);
639            break;
640        }
641    }
642}
643
644}  // namespace android
645