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