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