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/MediaCodecBuffer.h>
     29 #include <media/stagefright/foundation/ABuffer.h>
     30 #include <media/stagefright/foundation/ADebug.h>
     31 #include <media/stagefright/foundation/AMessage.h>
     32 #include <media/stagefright/MediaErrors.h>
     33 
     34 #include "ATSParser.h"
     35 
     36 namespace android {
     37 
     38 // TODO optimize buffer size for power consumption
     39 // The offload read buffer size is 32 KB but 24 KB uses less power.
     40 static const size_t kAggregateBufferSizeBytes = 24 * 1024;
     41 static const size_t kMaxCachedBytes = 200000;
     42 
     43 NuPlayer::DecoderPassThrough::DecoderPassThrough(
     44         const sp<AMessage> &notify,
     45         const sp<Source> &source,
     46         const sp<Renderer> &renderer)
     47     : DecoderBase(notify),
     48       mSource(source),
     49       mRenderer(renderer),
     50       mSkipRenderingUntilMediaTimeUs(-1ll),
     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 */, mSource->isStreaming());
     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 bool NuPlayer::DecoderPassThrough::isStaleReply(const sp<AMessage> &msg) {
     97     int32_t generation;
     98     CHECK(msg->findInt32("generation", &generation));
     99     return generation != mBufferGeneration;
    100 }
    101 
    102 bool NuPlayer::DecoderPassThrough::isDoneFetching() const {
    103     ALOGV("[%s] mCachedBytes = %zu, mReachedEOS = %d mPaused = %d",
    104             mComponentName.c_str(), mCachedBytes, mReachedEOS, mPaused);
    105 
    106     return mCachedBytes >= kMaxCachedBytes || mReachedEOS || mPaused;
    107 }
    108 
    109 /*
    110  * returns true if we should request more data
    111  */
    112 bool NuPlayer::DecoderPassThrough::doRequestBuffers() {
    113     status_t err = OK;
    114     while (!isDoneFetching()) {
    115         sp<AMessage> msg = new AMessage();
    116 
    117         err = fetchInputData(msg);
    118         if (err != OK) {
    119             break;
    120         }
    121 
    122         onInputBufferFetched(msg);
    123     }
    124 
    125     return err == -EWOULDBLOCK
    126             && mSource->feedMoreTSData() == OK;
    127 }
    128 
    129 status_t NuPlayer::DecoderPassThrough::dequeueAccessUnit(sp<ABuffer> *accessUnit) {
    130     status_t err;
    131 
    132     // Did we save an accessUnit earlier because of a discontinuity?
    133     if (mPendingAudioAccessUnit != NULL) {
    134         *accessUnit = mPendingAudioAccessUnit;
    135         mPendingAudioAccessUnit.clear();
    136         err = mPendingAudioErr;
    137         ALOGV("feedDecoderInputData() use mPendingAudioAccessUnit");
    138     } else {
    139         err = mSource->dequeueAccessUnit(true /* audio */, accessUnit);
    140     }
    141 
    142     if (err == INFO_DISCONTINUITY || err == ERROR_END_OF_STREAM) {
    143         if (mAggregateBuffer != NULL) {
    144             // We already have some data so save this for later.
    145             mPendingAudioErr = err;
    146             mPendingAudioAccessUnit = *accessUnit;
    147             (*accessUnit).clear();
    148             ALOGD("return aggregated buffer and save err(=%d) for later", err);
    149             err = OK;
    150         }
    151     }
    152 
    153     return err;
    154 }
    155 
    156 sp<ABuffer> NuPlayer::DecoderPassThrough::aggregateBuffer(
    157         const sp<ABuffer> &accessUnit) {
    158     sp<ABuffer> aggregate;
    159 
    160     if (accessUnit == NULL) {
    161         // accessUnit is saved to mPendingAudioAccessUnit
    162         // return current mAggregateBuffer
    163         aggregate = mAggregateBuffer;
    164         mAggregateBuffer.clear();
    165         return aggregate;
    166     }
    167 
    168     size_t smallSize = accessUnit->size();
    169     if ((mAggregateBuffer == NULL)
    170             // Don't bother if only room for a few small buffers.
    171             && (smallSize < (kAggregateBufferSizeBytes / 3))) {
    172         // Create a larger buffer for combining smaller buffers from the extractor.
    173         mAggregateBuffer = new ABuffer(kAggregateBufferSizeBytes);
    174         mAggregateBuffer->setRange(0, 0); // start empty
    175     }
    176 
    177     if (mAggregateBuffer != NULL) {
    178         int64_t timeUs;
    179         int64_t dummy;
    180         bool smallTimestampValid = accessUnit->meta()->findInt64("timeUs", &timeUs);
    181         bool bigTimestampValid = mAggregateBuffer->meta()->findInt64("timeUs", &dummy);
    182         // Will the smaller buffer fit?
    183         size_t bigSize = mAggregateBuffer->size();
    184         size_t roomLeft = mAggregateBuffer->capacity() - bigSize;
    185         // Should we save this small buffer for the next big buffer?
    186         // If the first small buffer did not have a timestamp then save
    187         // any buffer that does have a timestamp until the next big buffer.
    188         if ((smallSize > roomLeft)
    189             || (!bigTimestampValid && (bigSize > 0) && smallTimestampValid)) {
    190             mPendingAudioErr = OK;
    191             mPendingAudioAccessUnit = accessUnit;
    192             aggregate = mAggregateBuffer;
    193             mAggregateBuffer.clear();
    194         } else {
    195             // Grab time from first small buffer if available.
    196             if ((bigSize == 0) && smallTimestampValid) {
    197                 mAggregateBuffer->meta()->setInt64("timeUs", timeUs);
    198             }
    199             // Append small buffer to the bigger buffer.
    200             memcpy(mAggregateBuffer->base() + bigSize, accessUnit->data(), smallSize);
    201             bigSize += smallSize;
    202             mAggregateBuffer->setRange(0, bigSize);
    203 
    204             ALOGV("feedDecoderInputData() smallSize = %zu, bigSize = %zu, capacity = %zu",
    205                     smallSize, bigSize, mAggregateBuffer->capacity());
    206         }
    207     } else {
    208         // decided not to aggregate
    209         aggregate = accessUnit;
    210     }
    211 
    212     return aggregate;
    213 }
    214 
    215 status_t NuPlayer::DecoderPassThrough::fetchInputData(sp<AMessage> &reply) {
    216     sp<ABuffer> accessUnit;
    217 
    218     do {
    219         status_t err = dequeueAccessUnit(&accessUnit);
    220 
    221         if (err == -EWOULDBLOCK) {
    222             // Flush out the aggregate buffer to try to avoid underrun.
    223             accessUnit = aggregateBuffer(NULL /* accessUnit */);
    224             if (accessUnit != NULL) {
    225                 break;
    226             }
    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         if (streamErr != ERROR_END_OF_STREAM) {
    298             handleError(streamErr);
    299         }
    300         mReachedEOS = true;
    301         if (mRenderer != NULL) {
    302             mRenderer->queueEOS(true /* audio */, ERROR_END_OF_STREAM);
    303         }
    304         return;
    305     }
    306 
    307     sp<AMessage> extra;
    308     if (buffer->meta()->findMessage("extra", &extra) && extra != NULL) {
    309         int64_t resumeAtMediaTimeUs;
    310         if (extra->findInt64(
    311                     "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) {
    312             ALOGI("[%s] suppressing rendering until %lld us",
    313                     mComponentName.c_str(), (long long)resumeAtMediaTimeUs);
    314             mSkipRenderingUntilMediaTimeUs = resumeAtMediaTimeUs;
    315         }
    316     }
    317 
    318     int32_t bufferSize = buffer->size();
    319     mCachedBytes += bufferSize;
    320 
    321     int64_t timeUs = 0;
    322     CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
    323     if (mSkipRenderingUntilMediaTimeUs >= 0) {
    324         if (timeUs < mSkipRenderingUntilMediaTimeUs) {
    325             ALOGV("[%s] dropping buffer at time %lld as requested.",
    326                      mComponentName.c_str(), (long long)timeUs);
    327 
    328             onBufferConsumed(bufferSize);
    329             return;
    330         }
    331 
    332         mSkipRenderingUntilMediaTimeUs = -1;
    333     }
    334 
    335     if (mRenderer == NULL) {
    336         onBufferConsumed(bufferSize);
    337         return;
    338     }
    339 
    340     sp<AMessage> reply = new AMessage(kWhatBufferConsumed, this);
    341     reply->setInt32("generation", mBufferGeneration);
    342     reply->setInt32("size", bufferSize);
    343 
    344     sp<MediaCodecBuffer> mcBuffer = new MediaCodecBuffer(nullptr, buffer);
    345     mcBuffer->meta()->setInt64("timeUs", timeUs);
    346 
    347     mRenderer->queueBuffer(true /* audio */, mcBuffer, reply);
    348 
    349     ++mPendingBuffersToDrain;
    350     ALOGV("onInputBufferFilled: #ToDrain = %zu, cachedBytes = %zu",
    351             mPendingBuffersToDrain, mCachedBytes);
    352 }
    353 
    354 void NuPlayer::DecoderPassThrough::onBufferConsumed(int32_t size) {
    355     --mPendingBuffersToDrain;
    356     mCachedBytes -= size;
    357     ALOGV("onBufferConsumed: #ToDrain = %zu, cachedBytes = %zu",
    358             mPendingBuffersToDrain, mCachedBytes);
    359     onRequestInputBuffers();
    360 }
    361 
    362 void NuPlayer::DecoderPassThrough::onResume(bool notifyComplete) {
    363     mPaused = false;
    364 
    365     onRequestInputBuffers();
    366 
    367     if (notifyComplete) {
    368         sp<AMessage> notify = mNotify->dup();
    369         notify->setInt32("what", kWhatResumeCompleted);
    370         notify->post();
    371     }
    372 }
    373 
    374 void NuPlayer::DecoderPassThrough::doFlush(bool notifyComplete) {
    375     ++mBufferGeneration;
    376     mSkipRenderingUntilMediaTimeUs = -1;
    377     mPendingAudioAccessUnit.clear();
    378     mPendingAudioErr = OK;
    379     mAggregateBuffer.clear();
    380 
    381     if (mRenderer != NULL) {
    382         mRenderer->flush(true /* audio */, notifyComplete);
    383         mRenderer->signalTimeDiscontinuity();
    384     }
    385 
    386     mPendingBuffersToDrain = 0;
    387     mCachedBytes = 0;
    388     mReachedEOS = false;
    389 }
    390 
    391 void NuPlayer::DecoderPassThrough::onFlush() {
    392     doFlush(true /* notifyComplete */);
    393 
    394     mPaused = true;
    395     sp<AMessage> notify = mNotify->dup();
    396     notify->setInt32("what", kWhatFlushCompleted);
    397     notify->post();
    398 
    399 }
    400 
    401 void NuPlayer::DecoderPassThrough::onShutdown(bool notifyComplete) {
    402     ++mBufferGeneration;
    403     mSkipRenderingUntilMediaTimeUs = -1;
    404 
    405     if (notifyComplete) {
    406         sp<AMessage> notify = mNotify->dup();
    407         notify->setInt32("what", kWhatShutdownCompleted);
    408         notify->post();
    409     }
    410 
    411     mReachedEOS = true;
    412 }
    413 
    414 void NuPlayer::DecoderPassThrough::onMessageReceived(const sp<AMessage> &msg) {
    415     ALOGV("[%s] onMessage: %s", mComponentName.c_str(),
    416             msg->debugString().c_str());
    417 
    418     switch (msg->what()) {
    419         case kWhatBufferConsumed:
    420         {
    421             if (!isStaleReply(msg)) {
    422                 int32_t size;
    423                 CHECK(msg->findInt32("size", &size));
    424                 onBufferConsumed(size);
    425             }
    426             break;
    427         }
    428 
    429         default:
    430             DecoderBase::onMessageReceived(msg);
    431             break;
    432     }
    433 }
    434 
    435 }  // namespace android
    436