Home | History | Annotate | Download | only in mpeg2ts
      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 #include "AnotherPacketSource.h"
     18 
     19 #include <media/stagefright/foundation/ABuffer.h>
     20 #include <media/stagefright/foundation/ADebug.h>
     21 #include <media/stagefright/foundation/AMessage.h>
     22 #include <media/stagefright/foundation/AString.h>
     23 #include <media/stagefright/foundation/hexdump.h>
     24 #include <media/stagefright/MediaBuffer.h>
     25 #include <media/stagefright/MediaDefs.h>
     26 #include <media/stagefright/MetaData.h>
     27 #include <utils/Vector.h>
     28 
     29 namespace android {
     30 
     31 const int64_t kNearEOSMarkUs = 2000000ll; // 2 secs
     32 
     33 AnotherPacketSource::AnotherPacketSource(const sp<MetaData> &meta)
     34     : mIsAudio(false),
     35       mFormat(meta),
     36       mLastQueuedTimeUs(0),
     37       mEOSResult(OK) {
     38     const char *mime;
     39     CHECK(meta->findCString(kKeyMIMEType, &mime));
     40 
     41     if (!strncasecmp("audio/", mime, 6)) {
     42         mIsAudio = true;
     43     } else {
     44         CHECK(!strncasecmp("video/", mime, 6));
     45     }
     46 }
     47 
     48 void AnotherPacketSource::setFormat(const sp<MetaData> &meta) {
     49     CHECK(mFormat == NULL);
     50     mFormat = meta;
     51 }
     52 
     53 AnotherPacketSource::~AnotherPacketSource() {
     54 }
     55 
     56 status_t AnotherPacketSource::start(MetaData *params) {
     57     return OK;
     58 }
     59 
     60 status_t AnotherPacketSource::stop() {
     61     return OK;
     62 }
     63 
     64 sp<MetaData> AnotherPacketSource::getFormat() {
     65     return mFormat;
     66 }
     67 
     68 status_t AnotherPacketSource::dequeueAccessUnit(sp<ABuffer> *buffer) {
     69     buffer->clear();
     70 
     71     Mutex::Autolock autoLock(mLock);
     72     while (mEOSResult == OK && mBuffers.empty()) {
     73         mCondition.wait(mLock);
     74     }
     75 
     76     if (!mBuffers.empty()) {
     77         *buffer = *mBuffers.begin();
     78         mBuffers.erase(mBuffers.begin());
     79 
     80         int32_t discontinuity;
     81         if ((*buffer)->meta()->findInt32("discontinuity", &discontinuity)) {
     82             if (wasFormatChange(discontinuity)) {
     83                 mFormat.clear();
     84             }
     85 
     86             return INFO_DISCONTINUITY;
     87         }
     88 
     89         return OK;
     90     }
     91 
     92     return mEOSResult;
     93 }
     94 
     95 status_t AnotherPacketSource::read(
     96         MediaBuffer **out, const ReadOptions *) {
     97     *out = NULL;
     98 
     99     Mutex::Autolock autoLock(mLock);
    100     while (mEOSResult == OK && mBuffers.empty()) {
    101         mCondition.wait(mLock);
    102     }
    103 
    104     if (!mBuffers.empty()) {
    105         const sp<ABuffer> buffer = *mBuffers.begin();
    106         mBuffers.erase(mBuffers.begin());
    107 
    108         int32_t discontinuity;
    109         if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
    110             if (wasFormatChange(discontinuity)) {
    111                 mFormat.clear();
    112             }
    113 
    114             return INFO_DISCONTINUITY;
    115         } else {
    116             int64_t timeUs;
    117             CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
    118 
    119             MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
    120 
    121             mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
    122 
    123             *out = mediaBuffer;
    124             return OK;
    125         }
    126     }
    127 
    128     return mEOSResult;
    129 }
    130 
    131 bool AnotherPacketSource::wasFormatChange(
    132         int32_t discontinuityType) const {
    133     if (mIsAudio) {
    134         return (discontinuityType & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0;
    135     }
    136 
    137     return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0;
    138 }
    139 
    140 void AnotherPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
    141     int32_t damaged;
    142     if (buffer->meta()->findInt32("damaged", &damaged) && damaged) {
    143         // LOG(VERBOSE) << "discarding damaged AU";
    144         return;
    145     }
    146 
    147     CHECK(buffer->meta()->findInt64("timeUs", &mLastQueuedTimeUs));
    148     ALOGV("queueAccessUnit timeUs=%lld us (%.2f secs)", mLastQueuedTimeUs, mLastQueuedTimeUs / 1E6);
    149 
    150     Mutex::Autolock autoLock(mLock);
    151     mBuffers.push_back(buffer);
    152     mCondition.signal();
    153 }
    154 
    155 void AnotherPacketSource::queueDiscontinuity(
    156         ATSParser::DiscontinuityType type,
    157         const sp<AMessage> &extra) {
    158     Mutex::Autolock autoLock(mLock);
    159 
    160     // Leave only discontinuities in the queue.
    161     List<sp<ABuffer> >::iterator it = mBuffers.begin();
    162     while (it != mBuffers.end()) {
    163         sp<ABuffer> oldBuffer = *it;
    164 
    165         int32_t oldDiscontinuityType;
    166         if (!oldBuffer->meta()->findInt32(
    167                     "discontinuity", &oldDiscontinuityType)) {
    168             it = mBuffers.erase(it);
    169             continue;
    170         }
    171 
    172         ++it;
    173     }
    174 
    175     mEOSResult = OK;
    176     mLastQueuedTimeUs = 0;
    177 
    178     sp<ABuffer> buffer = new ABuffer(0);
    179     buffer->meta()->setInt32("discontinuity", static_cast<int32_t>(type));
    180     buffer->meta()->setMessage("extra", extra);
    181 
    182     mBuffers.push_back(buffer);
    183     mCondition.signal();
    184 }
    185 
    186 void AnotherPacketSource::signalEOS(status_t result) {
    187     CHECK(result != OK);
    188 
    189     Mutex::Autolock autoLock(mLock);
    190     mEOSResult = result;
    191     mCondition.signal();
    192 }
    193 
    194 bool AnotherPacketSource::hasBufferAvailable(status_t *finalResult) {
    195     Mutex::Autolock autoLock(mLock);
    196     if (!mBuffers.empty()) {
    197         return true;
    198     }
    199 
    200     *finalResult = mEOSResult;
    201     return false;
    202 }
    203 
    204 int64_t AnotherPacketSource::getBufferedDurationUs(status_t *finalResult) {
    205     Mutex::Autolock autoLock(mLock);
    206 
    207     *finalResult = mEOSResult;
    208 
    209     if (mBuffers.empty()) {
    210         return 0;
    211     }
    212 
    213     int64_t time1 = -1;
    214     int64_t time2 = -1;
    215 
    216     List<sp<ABuffer> >::iterator it = mBuffers.begin();
    217     while (it != mBuffers.end()) {
    218         const sp<ABuffer> &buffer = *it;
    219 
    220         int64_t timeUs;
    221         if (buffer->meta()->findInt64("timeUs", &timeUs)) {
    222             if (time1 < 0) {
    223                 time1 = timeUs;
    224             }
    225 
    226             time2 = timeUs;
    227         } else {
    228             // This is a discontinuity, reset everything.
    229             time1 = time2 = -1;
    230         }
    231 
    232         ++it;
    233     }
    234 
    235     return time2 - time1;
    236 }
    237 
    238 status_t AnotherPacketSource::nextBufferTime(int64_t *timeUs) {
    239     *timeUs = 0;
    240 
    241     Mutex::Autolock autoLock(mLock);
    242 
    243     if (mBuffers.empty()) {
    244         return mEOSResult != OK ? mEOSResult : -EWOULDBLOCK;
    245     }
    246 
    247     sp<ABuffer> buffer = *mBuffers.begin();
    248     CHECK(buffer->meta()->findInt64("timeUs", timeUs));
    249 
    250     return OK;
    251 }
    252 
    253 bool AnotherPacketSource::isFinished(int64_t duration) const {
    254     if (duration > 0) {
    255         int64_t diff = duration - mLastQueuedTimeUs;
    256         if (diff < kNearEOSMarkUs && diff > -kNearEOSMarkUs) {
    257             ALOGV("Detecting EOS due to near end");
    258             return true;
    259         }
    260     }
    261     return (mEOSResult != OK);
    262 }
    263 
    264 }  // namespace android
    265