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