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