Home | History | Annotate | Download | only in nuplayer
      1 /*
      2  * Copyright (C) 2010 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 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "HTTPLiveSource"
     19 #include <utils/Log.h>
     20 
     21 #include "HTTPLiveSource.h"
     22 
     23 #include "ATSParser.h"
     24 #include "AnotherPacketSource.h"
     25 #include "LiveDataSource.h"
     26 #include "LiveSession.h"
     27 
     28 #include <media/stagefright/foundation/ABuffer.h>
     29 #include <media/stagefright/foundation/ADebug.h>
     30 #include <media/stagefright/foundation/AMessage.h>
     31 #include <media/stagefright/MediaErrors.h>
     32 #include <media/stagefright/MetaData.h>
     33 
     34 namespace android {
     35 
     36 NuPlayer::HTTPLiveSource::HTTPLiveSource(
     37         const char *url,
     38         const KeyedVector<String8, String8> *headers,
     39         bool uidValid, uid_t uid)
     40     : mURL(url),
     41       mUIDValid(uidValid),
     42       mUID(uid),
     43       mFlags(0),
     44       mFinalResult(OK),
     45       mOffset(0) {
     46     if (headers) {
     47         mExtraHeaders = *headers;
     48 
     49         ssize_t index =
     50             mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
     51 
     52         if (index >= 0) {
     53             mFlags |= kFlagIncognito;
     54 
     55             mExtraHeaders.removeItemsAt(index);
     56         }
     57     }
     58 }
     59 
     60 NuPlayer::HTTPLiveSource::~HTTPLiveSource() {
     61     if (mLiveSession != NULL) {
     62         mLiveSession->disconnect();
     63         mLiveLooper->stop();
     64     }
     65 }
     66 
     67 void NuPlayer::HTTPLiveSource::start() {
     68     mLiveLooper = new ALooper;
     69     mLiveLooper->setName("http live");
     70     mLiveLooper->start();
     71 
     72     mLiveSession = new LiveSession(
     73             (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0,
     74             mUIDValid, mUID);
     75 
     76     mLiveLooper->registerHandler(mLiveSession);
     77 
     78     mLiveSession->connect(
     79             mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
     80 
     81     mTSParser = new ATSParser;
     82 }
     83 
     84 sp<MetaData> NuPlayer::HTTPLiveSource::getFormat(bool audio) {
     85     ATSParser::SourceType type =
     86         audio ? ATSParser::AUDIO : ATSParser::VIDEO;
     87 
     88     sp<AnotherPacketSource> source =
     89         static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get());
     90 
     91     if (source == NULL) {
     92         return NULL;
     93     }
     94 
     95     return source->getFormat();
     96 }
     97 
     98 status_t NuPlayer::HTTPLiveSource::feedMoreTSData() {
     99     if (mFinalResult != OK) {
    100         return mFinalResult;
    101     }
    102 
    103     sp<LiveDataSource> source =
    104         static_cast<LiveDataSource *>(mLiveSession->getDataSource().get());
    105 
    106     for (int32_t i = 0; i < 50; ++i) {
    107         char buffer[188];
    108         ssize_t n = source->readAtNonBlocking(mOffset, buffer, sizeof(buffer));
    109 
    110         if (n == -EWOULDBLOCK) {
    111             break;
    112         } else if (n < 0) {
    113             if (n != ERROR_END_OF_STREAM) {
    114                 ALOGI("input data EOS reached, error %ld", n);
    115             } else {
    116                 ALOGI("input data EOS reached.");
    117             }
    118             mTSParser->signalEOS(n);
    119             mFinalResult = n;
    120             break;
    121         } else {
    122             if (buffer[0] == 0x00) {
    123                 // XXX legacy
    124                 sp<AMessage> extra;
    125                 mTSParser->signalDiscontinuity(
    126                         buffer[1] == 0x00
    127                             ? ATSParser::DISCONTINUITY_SEEK
    128                             : ATSParser::DISCONTINUITY_FORMATCHANGE,
    129                         extra);
    130             } else {
    131                 status_t err = mTSParser->feedTSPacket(buffer, sizeof(buffer));
    132 
    133                 if (err != OK) {
    134                     ALOGE("TS Parser returned error %d", err);
    135                     mTSParser->signalEOS(err);
    136                     mFinalResult = err;
    137                     break;
    138                 }
    139             }
    140 
    141             mOffset += n;
    142         }
    143     }
    144 
    145     return OK;
    146 }
    147 
    148 status_t NuPlayer::HTTPLiveSource::dequeueAccessUnit(
    149         bool audio, sp<ABuffer> *accessUnit) {
    150     ATSParser::SourceType type =
    151         audio ? ATSParser::AUDIO : ATSParser::VIDEO;
    152 
    153     sp<AnotherPacketSource> source =
    154         static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get());
    155 
    156     if (source == NULL) {
    157         return -EWOULDBLOCK;
    158     }
    159 
    160     status_t finalResult;
    161     if (!source->hasBufferAvailable(&finalResult)) {
    162         return finalResult == OK ? -EWOULDBLOCK : finalResult;
    163     }
    164 
    165     return source->dequeueAccessUnit(accessUnit);
    166 }
    167 
    168 status_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) {
    169     return mLiveSession->getDuration(durationUs);
    170 }
    171 
    172 status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs) {
    173     // We need to make sure we're not seeking until we have seen the very first
    174     // PTS timestamp in the whole stream (from the beginning of the stream).
    175     while (!mTSParser->PTSTimeDeltaEstablished() && feedMoreTSData() == OK) {
    176         usleep(100000);
    177     }
    178 
    179     mLiveSession->seekTo(seekTimeUs);
    180 
    181     return OK;
    182 }
    183 
    184 bool NuPlayer::HTTPLiveSource::isSeekable() {
    185     return mLiveSession->isSeekable();
    186 }
    187 
    188 }  // namespace android
    189 
    190