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