Home | History | Annotate | Download | only in nuplayer
      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 
     32 namespace android {
     33 
     34 NuPlayer::GenericSource::GenericSource(
     35         const char *url,
     36         const KeyedVector<String8, String8> *headers,
     37         bool uidValid,
     38         uid_t uid)
     39     : mDurationUs(0ll),
     40       mAudioIsVorbis(false) {
     41     DataSource::RegisterDefaultSniffers();
     42 
     43     sp<DataSource> dataSource =
     44         DataSource::CreateFromURI(url, headers);
     45     CHECK(dataSource != NULL);
     46 
     47     initFromDataSource(dataSource);
     48 }
     49 
     50 NuPlayer::GenericSource::GenericSource(
     51         int fd, int64_t offset, int64_t length)
     52     : mDurationUs(0ll),
     53       mAudioIsVorbis(false) {
     54     DataSource::RegisterDefaultSniffers();
     55 
     56     sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
     57 
     58     initFromDataSource(dataSource);
     59 }
     60 
     61 void NuPlayer::GenericSource::initFromDataSource(
     62         const sp<DataSource> &dataSource) {
     63     sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
     64 
     65     CHECK(extractor != NULL);
     66 
     67     for (size_t i = 0; i < extractor->countTracks(); ++i) {
     68         sp<MetaData> meta = extractor->getTrackMetaData(i);
     69 
     70         const char *mime;
     71         CHECK(meta->findCString(kKeyMIMEType, &mime));
     72 
     73         sp<MediaSource> track;
     74 
     75         if (!strncasecmp(mime, "audio/", 6)) {
     76             if (mAudioTrack.mSource == NULL) {
     77                 mAudioTrack.mSource = track = extractor->getTrack(i);
     78 
     79                 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
     80                     mAudioIsVorbis = true;
     81                 } else {
     82                     mAudioIsVorbis = false;
     83                 }
     84             }
     85         } else if (!strncasecmp(mime, "video/", 6)) {
     86             if (mVideoTrack.mSource == NULL) {
     87                 mVideoTrack.mSource = track = extractor->getTrack(i);
     88             }
     89         }
     90 
     91         if (track != NULL) {
     92             int64_t durationUs;
     93             if (meta->findInt64(kKeyDuration, &durationUs)) {
     94                 if (durationUs > mDurationUs) {
     95                     mDurationUs = durationUs;
     96                 }
     97             }
     98         }
     99     }
    100 }
    101 
    102 NuPlayer::GenericSource::~GenericSource() {
    103 }
    104 
    105 void NuPlayer::GenericSource::start() {
    106     ALOGI("start");
    107 
    108     if (mAudioTrack.mSource != NULL) {
    109         CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);
    110 
    111         mAudioTrack.mPackets =
    112             new AnotherPacketSource(mAudioTrack.mSource->getFormat());
    113 
    114         readBuffer(true /* audio */);
    115     }
    116 
    117     if (mVideoTrack.mSource != NULL) {
    118         CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK);
    119 
    120         mVideoTrack.mPackets =
    121             new AnotherPacketSource(mVideoTrack.mSource->getFormat());
    122 
    123         readBuffer(false /* audio */);
    124     }
    125 }
    126 
    127 status_t NuPlayer::GenericSource::feedMoreTSData() {
    128     return OK;
    129 }
    130 
    131 sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
    132     sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
    133 
    134     if (source == NULL) {
    135         return NULL;
    136     }
    137 
    138     return source->getFormat();
    139 }
    140 
    141 status_t NuPlayer::GenericSource::dequeueAccessUnit(
    142         bool audio, sp<ABuffer> *accessUnit) {
    143     Track *track = audio ? &mAudioTrack : &mVideoTrack;
    144 
    145     if (track->mSource == NULL) {
    146         return -EWOULDBLOCK;
    147     }
    148 
    149     status_t finalResult;
    150     if (!track->mPackets->hasBufferAvailable(&finalResult)) {
    151         return finalResult == OK ? -EWOULDBLOCK : finalResult;
    152     }
    153 
    154     status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
    155 
    156     readBuffer(audio, -1ll);
    157 
    158     return result;
    159 }
    160 
    161 status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
    162     *durationUs = mDurationUs;
    163     return OK;
    164 }
    165 
    166 status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
    167     if (mVideoTrack.mSource != NULL) {
    168         int64_t actualTimeUs;
    169         readBuffer(false /* audio */, seekTimeUs, &actualTimeUs);
    170 
    171         seekTimeUs = actualTimeUs;
    172     }
    173 
    174     if (mAudioTrack.mSource != NULL) {
    175         readBuffer(true /* audio */, seekTimeUs);
    176     }
    177 
    178     return OK;
    179 }
    180 
    181 void NuPlayer::GenericSource::readBuffer(
    182         bool audio, int64_t seekTimeUs, int64_t *actualTimeUs) {
    183     Track *track = audio ? &mAudioTrack : &mVideoTrack;
    184     CHECK(track->mSource != NULL);
    185 
    186     if (actualTimeUs) {
    187         *actualTimeUs = seekTimeUs;
    188     }
    189 
    190     MediaSource::ReadOptions options;
    191 
    192     bool seeking = false;
    193 
    194     if (seekTimeUs >= 0) {
    195         options.setSeekTo(seekTimeUs);
    196         seeking = true;
    197     }
    198 
    199     for (;;) {
    200         MediaBuffer *mbuf;
    201         status_t err = track->mSource->read(&mbuf, &options);
    202 
    203         options.clearSeekTo();
    204 
    205         if (err == OK) {
    206             size_t outLength = mbuf->range_length();
    207 
    208             if (audio && mAudioIsVorbis) {
    209                 outLength += sizeof(int32_t);
    210             }
    211 
    212             sp<ABuffer> buffer = new ABuffer(outLength);
    213 
    214             memcpy(buffer->data(),
    215                    (const uint8_t *)mbuf->data() + mbuf->range_offset(),
    216                    mbuf->range_length());
    217 
    218             if (audio && mAudioIsVorbis) {
    219                 int32_t numPageSamples;
    220                 if (!mbuf->meta_data()->findInt32(
    221                             kKeyValidSamples, &numPageSamples)) {
    222                     numPageSamples = -1;
    223                 }
    224 
    225                 memcpy(buffer->data() + mbuf->range_length(),
    226                        &numPageSamples,
    227                        sizeof(numPageSamples));
    228             }
    229 
    230             int64_t timeUs;
    231             CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
    232 
    233             buffer->meta()->setInt64("timeUs", timeUs);
    234 
    235             if (actualTimeUs) {
    236                 *actualTimeUs = timeUs;
    237             }
    238 
    239             mbuf->release();
    240             mbuf = NULL;
    241 
    242             if (seeking) {
    243                 track->mPackets->queueDiscontinuity(
    244                         ATSParser::DISCONTINUITY_SEEK, NULL);
    245             }
    246 
    247             track->mPackets->queueAccessUnit(buffer);
    248             break;
    249         } else if (err == INFO_FORMAT_CHANGED) {
    250 #if 0
    251             track->mPackets->queueDiscontinuity(
    252                     ATSParser::DISCONTINUITY_FORMATCHANGE, NULL);
    253 #endif
    254         } else {
    255             track->mPackets->signalEOS(err);
    256             break;
    257         }
    258     }
    259 }
    260 
    261 bool NuPlayer::GenericSource::isSeekable() {
    262     return true;
    263 }
    264 
    265 }  // namespace android
    266