Home | History | Annotate | Download | only in nuplayer
      1 /*
      2  * Copyright (C) 2014 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 "NuPlayerDecoderPassThrough"
     19 #include <utils/Log.h>
     20 #include <inttypes.h>
     21 
     22 #include "NuPlayerDecoderPassThrough.h"
     23 
     24 #include "NuPlayerRenderer.h"
     25 #include "NuPlayerSource.h"
     26 
     27 #include <media/ICrypto.h>
     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 
     33 #include "ATSParser.h"
     34 
     35 namespace android {
     36 
     37 // TODO optimize buffer size for power consumption
     38 // The offload read buffer size is 32 KB but 24 KB uses less power.
     39 static const size_t kAggregateBufferSizeBytes = 24 * 1024;
     40 static const size_t kMaxCachedBytes = 200000;
     41 
     42 NuPlayer::DecoderPassThrough::DecoderPassThrough(
     43         const sp<AMessage> &notify,
     44         const sp<Source> &source,
     45         const sp<Renderer> &renderer)
     46     : DecoderBase(notify),
     47       mSource(source),
     48       mRenderer(renderer),
     49       mSkipRenderingUntilMediaTimeUs(-1ll),
     50       mPaused(false),
     51       mReachedEOS(true),
     52       mPendingAudioErr(OK),
     53       mPendingBuffersToDrain(0),
     54       mCachedBytes(0),
     55       mComponentName("pass through decoder") {
     56     ALOGW_IF(renderer == NULL, "expect a non-NULL renderer");
     57 }
     58 
     59 NuPlayer::DecoderPassThrough::~DecoderPassThrough() {
     60 }
     61 
     62 void NuPlayer::DecoderPassThrough::onConfigure(const sp<AMessage> &format) {
     63     ALOGV("[%s] onConfigure", mComponentName.c_str());
     64     mCachedBytes = 0;
     65     mPendingBuffersToDrain = 0;
     66     mReachedEOS = false;
     67     ++mBufferGeneration;
     68 
     69     onRequestInputBuffers();
     70 
     71     int32_t hasVideo = 0;
     72     format->findInt32("has-video", &hasVideo);
     73 
     74     // The audio sink is already opened before the PassThrough decoder is created.
     75     // Opening again might be relevant if decoder is instantiated after shutdown and
     76     // format is different.
     77     status_t err = mRenderer->openAudioSink(
     78             format, true /* offloadOnly */, hasVideo,
     79             AUDIO_OUTPUT_FLAG_NONE /* flags */, NULL /* isOffloaded */);
     80     if (err != OK) {
     81         handleError(err);
     82     }
     83 }
     84 
     85 void NuPlayer::DecoderPassThrough::onSetParameters(const sp<AMessage> &/*params*/) {
     86     ALOGW("onSetParameters() called unexpectedly");
     87 }
     88 
     89 void NuPlayer::DecoderPassThrough::onSetRenderer(
     90         const sp<Renderer> &renderer) {
     91     // renderer can't be changed during offloading
     92     ALOGW_IF(renderer != mRenderer,
     93             "ignoring request to change renderer");
     94 }
     95 
     96 void NuPlayer::DecoderPassThrough::onGetInputBuffers(
     97         Vector<sp<ABuffer> > * /* dstBuffers */) {
     98     ALOGE("onGetInputBuffers() called unexpectedly");
     99 }
    100 
    101 bool NuPlayer::DecoderPassThrough::isStaleReply(const sp<AMessage> &msg) {
    102     int32_t generation;
    103     CHECK(msg->findInt32("generation", &generation));
    104     return generation != mBufferGeneration;
    105 }
    106 
    107 bool NuPlayer::DecoderPassThrough::isDoneFetching() const {
    108     ALOGV("[%s] mCachedBytes = %zu, mReachedEOS = %d mPaused = %d",
    109             mComponentName.c_str(), mCachedBytes, mReachedEOS, mPaused);
    110 
    111     return mCachedBytes >= kMaxCachedBytes || mReachedEOS || mPaused;
    112 }
    113 
    114 /*
    115  * returns true if we should request more data
    116  */
    117 bool NuPlayer::DecoderPassThrough::doRequestBuffers() {
    118     status_t err = OK;
    119     while (!isDoneFetching()) {
    120         sp<AMessage> msg = new AMessage();
    121 
    122         err = fetchInputData(msg);
    123         if (err != OK) {
    124             break;
    125         }
    126 
    127         onInputBufferFetched(msg);
    128     }
    129 
    130     return err == -EWOULDBLOCK
    131             && mSource->feedMoreTSData() == OK;
    132 }
    133 
    134 status_t NuPlayer::DecoderPassThrough::dequeueAccessUnit(sp<ABuffer> *accessUnit) {
    135     status_t err;
    136 
    137     // Did we save an accessUnit earlier because of a discontinuity?
    138     if (mPendingAudioAccessUnit != NULL) {
    139         *accessUnit = mPendingAudioAccessUnit;
    140         mPendingAudioAccessUnit.clear();
    141         err = mPendingAudioErr;
    142         ALOGV("feedDecoderInputData() use mPendingAudioAccessUnit");
    143     } else {
    144         err = mSource->dequeueAccessUnit(true /* audio */, accessUnit);
    145     }
    146 
    147     if (err == INFO_DISCONTINUITY || err == ERROR_END_OF_STREAM) {
    148         if (mAggregateBuffer != NULL) {
    149             // We already have some data so save this for later.
    150             mPendingAudioErr = err;
    151             mPendingAudioAccessUnit = *accessUnit;
    152             (*accessUnit).clear();
    153             ALOGD("return aggregated buffer and save err(=%d) for later", err);
    154             err = OK;
    155         }
    156     }
    157 
    158     return err;
    159 }
    160 
    161 sp<ABuffer> NuPlayer::DecoderPassThrough::aggregateBuffer(
    162         const sp<ABuffer> &accessUnit) {
    163     sp<ABuffer> aggregate;
    164 
    165     if (accessUnit == NULL) {
    166         // accessUnit is saved to mPendingAudioAccessUnit
    167         // return current mAggregateBuffer
    168         aggregate = mAggregateBuffer;
    169         mAggregateBuffer.clear();
    170         return aggregate;
    171     }
    172 
    173     size_t smallSize = accessUnit->size();
    174     if ((mAggregateBuffer == NULL)
    175             // Don't bother if only room for a few small buffers.
    176             && (smallSize < (kAggregateBufferSizeBytes / 3))) {
    177         // Create a larger buffer for combining smaller buffers from the extractor.
    178         mAggregateBuffer = new ABuffer(kAggregateBufferSizeBytes);
    179         mAggregateBuffer->setRange(0, 0); // start empty
    180     }
    181 
    182     if (mAggregateBuffer != NULL) {
    183         int64_t timeUs;
    184         int64_t dummy;
    185         bool smallTimestampValid = accessUnit->meta()->findInt64("timeUs", &timeUs);
    186         bool bigTimestampValid = mAggregateBuffer->meta()->findInt64("timeUs", &dummy);
    187         // Will the smaller buffer fit?
    188         size_t bigSize = mAggregateBuffer->size();
    189         size_t roomLeft = mAggregateBuffer->capacity() - bigSize;
    190         // Should we save this small buffer for the next big buffer?
    191         // If the first small buffer did not have a timestamp then save
    192         // any buffer that does have a timestamp until the next big buffer.
    193         if ((smallSize > roomLeft)
    194             || (!bigTimestampValid && (bigSize > 0) && smallTimestampValid)) {
    195             mPendingAudioErr = OK;
    196             mPendingAudioAccessUnit = accessUnit;
    197             aggregate = mAggregateBuffer;
    198             mAggregateBuffer.clear();
    199         } else {
    200             // Grab time from first small buffer if available.
    201             if ((bigSize == 0) && smallTimestampValid) {
    202                 mAggregateBuffer->meta()->setInt64("timeUs", timeUs);
    203             }
    204             // Append small buffer to the bigger buffer.
    205             memcpy(mAggregateBuffer->base() + bigSize, accessUnit->data(), smallSize);
    206             bigSize += smallSize;
    207             mAggregateBuffer->setRange(0, bigSize);
    208 
    209             ALOGV("feedDecoderInputData() smallSize = %zu, bigSize = %zu, capacity = %zu",
    210                     smallSize, bigSize, mAggregateBuffer->capacity());
    211         }
    212     } else {
    213         // decided not to aggregate
    214         aggregate = accessUnit;
    215     }
    216 
    217     return aggregate;
    218 }
    219 
    220 status_t NuPlayer::DecoderPassThrough::fetchInputData(sp<AMessage> &reply) {
    221     sp<ABuffer> accessUnit;
    222 
    223     do {
    224         status_t err = dequeueAccessUnit(&accessUnit);
    225 
    226         if (err == -EWOULDBLOCK) {
    227             return err;
    228         } else if (err != OK) {
    229             if (err == INFO_DISCONTINUITY) {
    230                 int32_t type;
    231                 CHECK(accessUnit->meta()->findInt32("discontinuity", &type));
    232 
    233                 bool formatChange =
    234                         (type & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0;
    235 
    236                 bool timeChange =
    237                         (type & ATSParser::DISCONTINUITY_TIME) != 0;
    238 
    239                 ALOGI("audio discontinuity (formatChange=%d, time=%d)",
    240                         formatChange, timeChange);
    241 
    242                 if (formatChange || timeChange) {
    243                     sp<AMessage> msg = mNotify->dup();
    244                     msg->setInt32("what", kWhatInputDiscontinuity);
    245                     // will perform seamless format change,
    246                     // only notify NuPlayer to scan sources
    247                     msg->setInt32("formatChange", false);
    248                     msg->post();
    249                 }
    250 
    251                 if (timeChange) {
    252                     doFlush(false /* notifyComplete */);
    253                     err = OK;
    254                 } else if (formatChange) {
    255                     // do seamless format change
    256                     err = OK;
    257                 } else {
    258                     // This stream is unaffected by the discontinuity
    259                     return -EWOULDBLOCK;
    260                 }
    261             }
    262 
    263             reply->setInt32("err", err);
    264             return OK;
    265         }
    266 
    267         accessUnit = aggregateBuffer(accessUnit);
    268     } while (accessUnit == NULL);
    269 
    270 #if 0
    271     int64_t mediaTimeUs;
    272     CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs));
    273     ALOGV("feeding audio input buffer at media time %.2f secs",
    274          mediaTimeUs / 1E6);
    275 #endif
    276 
    277     reply->setBuffer("buffer", accessUnit);
    278 
    279     return OK;
    280 }
    281 
    282 void NuPlayer::DecoderPassThrough::onInputBufferFetched(
    283         const sp<AMessage> &msg) {
    284     if (mReachedEOS) {
    285         return;
    286     }
    287 
    288     sp<ABuffer> buffer;
    289     bool hasBuffer = msg->findBuffer("buffer", &buffer);
    290     if (buffer == NULL) {
    291         int32_t streamErr = ERROR_END_OF_STREAM;
    292         CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
    293         if (streamErr == OK) {
    294             return;
    295         }
    296 
    297         mReachedEOS = true;
    298         if (mRenderer != NULL) {
    299             mRenderer->queueEOS(true /* audio */, ERROR_END_OF_STREAM);
    300         }
    301         return;
    302     }
    303 
    304     sp<AMessage> extra;
    305     if (buffer->meta()->findMessage("extra", &extra) && extra != NULL) {
    306         int64_t resumeAtMediaTimeUs;
    307         if (extra->findInt64(
    308                     "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) {
    309             ALOGI("[%s] suppressing rendering until %lld us",
    310                     mComponentName.c_str(), (long long)resumeAtMediaTimeUs);
    311             mSkipRenderingUntilMediaTimeUs = resumeAtMediaTimeUs;
    312         }
    313     }
    314 
    315     int32_t bufferSize = buffer->size();
    316     mCachedBytes += bufferSize;
    317 
    318     if (mSkipRenderingUntilMediaTimeUs >= 0) {
    319         int64_t timeUs = 0;
    320         CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
    321 
    322         if (timeUs < mSkipRenderingUntilMediaTimeUs) {
    323             ALOGV("[%s] dropping buffer at time %lld as requested.",
    324                      mComponentName.c_str(), (long long)timeUs);
    325 
    326             onBufferConsumed(bufferSize);
    327             return;
    328         }
    329 
    330         mSkipRenderingUntilMediaTimeUs = -1;
    331     }
    332 
    333     if (mRenderer == NULL) {
    334         onBufferConsumed(bufferSize);
    335         return;
    336     }
    337 
    338     sp<AMessage> reply = new AMessage(kWhatBufferConsumed, this);
    339     reply->setInt32("generation", mBufferGeneration);
    340     reply->setInt32("size", bufferSize);
    341 
    342     mRenderer->queueBuffer(true /* audio */, buffer, reply);
    343 
    344     ++mPendingBuffersToDrain;
    345     ALOGV("onInputBufferFilled: #ToDrain = %zu, cachedBytes = %zu",
    346             mPendingBuffersToDrain, mCachedBytes);
    347 }
    348 
    349 void NuPlayer::DecoderPassThrough::onBufferConsumed(int32_t size) {
    350     --mPendingBuffersToDrain;
    351     mCachedBytes -= size;
    352     ALOGV("onBufferConsumed: #ToDrain = %zu, cachedBytes = %zu",
    353             mPendingBuffersToDrain, mCachedBytes);
    354     onRequestInputBuffers();
    355 }
    356 
    357 void NuPlayer::DecoderPassThrough::onResume(bool notifyComplete) {
    358     mPaused = false;
    359 
    360     onRequestInputBuffers();
    361 
    362     if (notifyComplete) {
    363         sp<AMessage> notify = mNotify->dup();
    364         notify->setInt32("what", kWhatResumeCompleted);
    365         notify->post();
    366     }
    367 }
    368 
    369 void NuPlayer::DecoderPassThrough::doFlush(bool notifyComplete) {
    370     ++mBufferGeneration;
    371     mSkipRenderingUntilMediaTimeUs = -1;
    372     mPendingAudioAccessUnit.clear();
    373     mPendingAudioErr = OK;
    374     mAggregateBuffer.clear();
    375 
    376     if (mRenderer != NULL) {
    377         mRenderer->flush(true /* audio */, notifyComplete);
    378         mRenderer->signalTimeDiscontinuity();
    379     }
    380 
    381     mPendingBuffersToDrain = 0;
    382     mCachedBytes = 0;
    383     mReachedEOS = false;
    384 }
    385 
    386 void NuPlayer::DecoderPassThrough::onFlush() {
    387     doFlush(true /* notifyComplete */);
    388 
    389     mPaused = true;
    390     sp<AMessage> notify = mNotify->dup();
    391     notify->setInt32("what", kWhatFlushCompleted);
    392     notify->post();
    393 
    394 }
    395 
    396 void NuPlayer::DecoderPassThrough::onShutdown(bool notifyComplete) {
    397     ++mBufferGeneration;
    398     mSkipRenderingUntilMediaTimeUs = -1;
    399 
    400     if (notifyComplete) {
    401         sp<AMessage> notify = mNotify->dup();
    402         notify->setInt32("what", kWhatShutdownCompleted);
    403         notify->post();
    404     }
    405 
    406     mReachedEOS = true;
    407 }
    408 
    409 void NuPlayer::DecoderPassThrough::onMessageReceived(const sp<AMessage> &msg) {
    410     ALOGV("[%s] onMessage: %s", mComponentName.c_str(),
    411             msg->debugString().c_str());
    412 
    413     switch (msg->what()) {
    414         case kWhatBufferConsumed:
    415         {
    416             if (!isStaleReply(msg)) {
    417                 int32_t size;
    418                 CHECK(msg->findInt32("size", &size));
    419                 onBufferConsumed(size);
    420             }
    421             break;
    422         }
    423 
    424         default:
    425             DecoderBase::onMessageReceived(msg);
    426             break;
    427     }
    428 }
    429 
    430 }  // namespace android
    431