NuPlayerDecoder.cpp revision 6d96582e2310212381489da68bee74c44a0a5926
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//#define LOG_NDEBUG 0 18#define LOG_TAG "NuPlayerDecoder" 19#include <utils/Log.h> 20#include <inttypes.h> 21 22#include "NuPlayerDecoder.h" 23 24#include <media/ICrypto.h> 25#include <media/stagefright/foundation/ABuffer.h> 26#include <media/stagefright/foundation/ADebug.h> 27#include <media/stagefright/foundation/AMessage.h> 28#include <media/stagefright/MediaCodec.h> 29#include <media/stagefright/MediaDefs.h> 30#include <media/stagefright/MediaErrors.h> 31 32namespace android { 33 34NuPlayer::Decoder::Decoder( 35 const sp<AMessage> ¬ify, 36 const sp<NativeWindowWrapper> &nativeWindow) 37 : mNotify(notify), 38 mNativeWindow(nativeWindow), 39 mBufferGeneration(0), 40 mPaused(true), 41 mComponentName("decoder") { 42 // Every decoder has its own looper because MediaCodec operations 43 // are blocking, but NuPlayer needs asynchronous operations. 44 mDecoderLooper = new ALooper; 45 mDecoderLooper->setName("NuPlayerDecoder"); 46 mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO); 47 48 mCodecLooper = new ALooper; 49 mCodecLooper->setName("NuPlayerDecoder-MC"); 50 mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO); 51} 52 53NuPlayer::Decoder::~Decoder() { 54} 55 56void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) { 57 CHECK(mCodec == NULL); 58 59 ++mBufferGeneration; 60 61 AString mime; 62 CHECK(format->findString("mime", &mime)); 63 64 sp<Surface> surface = NULL; 65 if (mNativeWindow != NULL) { 66 surface = mNativeWindow->getSurfaceTextureClient(); 67 } 68 69 mComponentName = mime; 70 mComponentName.append(" decoder"); 71 ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), surface.get()); 72 73 mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */); 74 if (mCodec == NULL) { 75 ALOGE("Failed to create %s decoder", mime.c_str()); 76 handleError(UNKNOWN_ERROR); 77 return; 78 } 79 80 mCodec->getName(&mComponentName); 81 82 if (mNativeWindow != NULL) { 83 // disconnect from surface as MediaCodec will reconnect 84 CHECK_EQ((int)NO_ERROR, 85 native_window_api_disconnect( 86 surface.get(), 87 NATIVE_WINDOW_API_MEDIA)); 88 } 89 status_t err = mCodec->configure( 90 format, surface, NULL /* crypto */, 0 /* flags */); 91 if (err != OK) { 92 ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err); 93 handleError(err); 94 return; 95 } 96 // the following should work in configured state 97 CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat)); 98 CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat)); 99 100 err = mCodec->start(); 101 if (err != OK) { 102 ALOGE("Failed to start %s decoder (err=%d)", mComponentName.c_str(), err); 103 handleError(err); 104 return; 105 } 106 107 // the following should work after start 108 CHECK_EQ((status_t)OK, mCodec->getInputBuffers(&mInputBuffers)); 109 CHECK_EQ((status_t)OK, mCodec->getOutputBuffers(&mOutputBuffers)); 110 ALOGV("[%s] got %zu input and %zu output buffers", 111 mComponentName.c_str(), 112 mInputBuffers.size(), 113 mOutputBuffers.size()); 114 115 requestCodecNotification(); 116 mPaused = false; 117} 118 119void NuPlayer::Decoder::requestCodecNotification() { 120 if (mCodec != NULL) { 121 sp<AMessage> reply = new AMessage(kWhatCodecNotify, id()); 122 reply->setInt32("generation", mBufferGeneration); 123 mCodec->requestActivityNotification(reply); 124 } 125} 126 127bool NuPlayer::Decoder::isStaleReply(const sp<AMessage> &msg) { 128 int32_t generation; 129 CHECK(msg->findInt32("generation", &generation)); 130 return generation != mBufferGeneration; 131} 132 133void NuPlayer::Decoder::init() { 134 mDecoderLooper->registerHandler(this); 135} 136 137void NuPlayer::Decoder::configure(const sp<AMessage> &format) { 138 sp<AMessage> msg = new AMessage(kWhatConfigure, id()); 139 msg->setMessage("format", format); 140 msg->post(); 141} 142 143void NuPlayer::Decoder::handleError(int32_t err) 144{ 145 sp<AMessage> notify = mNotify->dup(); 146 notify->setInt32("what", kWhatError); 147 notify->setInt32("err", err); 148 notify->post(); 149} 150 151bool NuPlayer::Decoder::handleAnInputBuffer() { 152 size_t bufferIx = -1; 153 status_t res = mCodec->dequeueInputBuffer(&bufferIx); 154 ALOGV("[%s] dequeued input: %d", 155 mComponentName.c_str(), res == OK ? (int)bufferIx : res); 156 if (res != OK) { 157 if (res != -EAGAIN) { 158 handleError(res); 159 } 160 return false; 161 } 162 163 CHECK_LT(bufferIx, mInputBuffers.size()); 164 165 sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, id()); 166 reply->setSize("buffer-ix", bufferIx); 167 reply->setInt32("generation", mBufferGeneration); 168 169 sp<AMessage> notify = mNotify->dup(); 170 notify->setInt32("what", kWhatFillThisBuffer); 171 notify->setBuffer("buffer", mInputBuffers[bufferIx]); 172 notify->setMessage("reply", reply); 173 notify->post(); 174 return true; 175} 176 177void android::NuPlayer::Decoder::onInputBufferFilled(const sp<AMessage> &msg) { 178 size_t bufferIx; 179 CHECK(msg->findSize("buffer-ix", &bufferIx)); 180 CHECK_LT(bufferIx, mInputBuffers.size()); 181 sp<ABuffer> codecBuffer = mInputBuffers[bufferIx]; 182 183 sp<ABuffer> buffer; 184 bool hasBuffer = msg->findBuffer("buffer", &buffer); 185 if (buffer == NULL /* includes !hasBuffer */) { 186 int32_t streamErr = ERROR_END_OF_STREAM; 187 CHECK(msg->findInt32("err", &streamErr) || !hasBuffer); 188 189 if (streamErr == OK) { 190 /* buffers are returned to hold on to */ 191 return; 192 } 193 194 // attempt to queue EOS 195 status_t err = mCodec->queueInputBuffer( 196 bufferIx, 197 0, 198 0, 199 0, 200 MediaCodec::BUFFER_FLAG_EOS); 201 if (streamErr == ERROR_END_OF_STREAM && err != OK) { 202 streamErr = err; 203 // err will not be ERROR_END_OF_STREAM 204 } 205 206 if (streamErr != ERROR_END_OF_STREAM) { 207 handleError(streamErr); 208 } 209 } else { 210 int64_t timeUs = 0; 211 uint32_t flags = 0; 212 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 213 214 int32_t eos; 215 // we do not expect CODECCONFIG or SYNCFRAME for decoder 216 if (buffer->meta()->findInt32("eos", &eos) && eos) { 217 flags |= MediaCodec::BUFFER_FLAG_EOS; 218 } 219 220 // copy into codec buffer 221 if (buffer != codecBuffer) { 222 CHECK_LE(buffer->size(), codecBuffer->capacity()); 223 codecBuffer->setRange(0, buffer->size()); 224 memcpy(codecBuffer->data(), buffer->data(), buffer->size()); 225 } 226 227 status_t err = mCodec->queueInputBuffer( 228 bufferIx, 229 codecBuffer->offset(), 230 codecBuffer->size(), 231 timeUs, 232 flags); 233 if (err != OK) { 234 ALOGE("Failed to queue input buffer for %s (err=%d)", 235 mComponentName.c_str(), err); 236 handleError(err); 237 } 238 } 239} 240 241bool NuPlayer::Decoder::handleAnOutputBuffer() { 242 size_t bufferIx = -1; 243 size_t offset; 244 size_t size; 245 int64_t timeUs; 246 uint32_t flags; 247 status_t res = mCodec->dequeueOutputBuffer( 248 &bufferIx, &offset, &size, &timeUs, &flags); 249 250 if (res != OK) { 251 ALOGV("[%s] dequeued output: %d", mComponentName.c_str(), res); 252 } else { 253 ALOGV("[%s] dequeued output: %d (time=%lld flags=%" PRIu32 ")", 254 mComponentName.c_str(), (int)bufferIx, timeUs, flags); 255 } 256 257 if (res == INFO_OUTPUT_BUFFERS_CHANGED) { 258 res = mCodec->getOutputBuffers(&mOutputBuffers); 259 if (res != OK) { 260 ALOGE("Failed to get output buffers for %s after INFO event (err=%d)", 261 mComponentName.c_str(), res); 262 handleError(res); 263 return false; 264 } 265 // NuPlayer ignores this 266 return true; 267 } else if (res == INFO_FORMAT_CHANGED) { 268 sp<AMessage> format = new AMessage(); 269 res = mCodec->getOutputFormat(&format); 270 if (res != OK) { 271 ALOGE("Failed to get output format for %s after INFO event (err=%d)", 272 mComponentName.c_str(), res); 273 handleError(res); 274 return false; 275 } 276 277 sp<AMessage> notify = mNotify->dup(); 278 notify->setInt32("what", kWhatOutputFormatChanged); 279 notify->setMessage("format", format); 280 notify->post(); 281 return true; 282 } else if (res == INFO_DISCONTINUITY) { 283 // nothing to do 284 return true; 285 } else if (res != OK) { 286 if (res != -EAGAIN) { 287 handleError(res); 288 } 289 return false; 290 } 291 292 CHECK_LT(bufferIx, mOutputBuffers.size()); 293 sp<ABuffer> buffer = mOutputBuffers[bufferIx]; 294 buffer->setRange(offset, size); 295 buffer->meta()->clear(); 296 buffer->meta()->setInt64("timeUs", timeUs); 297 if (flags & MediaCodec::BUFFER_FLAG_EOS) { 298 buffer->meta()->setInt32("eos", true); 299 } 300 // we do not expect CODECCONFIG or SYNCFRAME for decoder 301 302 sp<AMessage> reply = new AMessage(kWhatRenderBuffer, id()); 303 reply->setSize("buffer-ix", bufferIx); 304 reply->setInt32("generation", mBufferGeneration); 305 306 sp<AMessage> notify = mNotify->dup(); 307 notify->setInt32("what", kWhatDrainThisBuffer); 308 notify->setBuffer("buffer", buffer); 309 notify->setMessage("reply", reply); 310 notify->post(); 311 312 // FIXME: This should be handled after rendering is complete, 313 // but Renderer needs it now 314 if (flags & MediaCodec::BUFFER_FLAG_EOS) { 315 ALOGV("queueing eos [%s]", mComponentName.c_str()); 316 sp<AMessage> notify = mNotify->dup(); 317 notify->setInt32("what", kWhatEOS); 318 notify->setInt32("err", ERROR_END_OF_STREAM); 319 notify->post(); 320 } 321 return true; 322} 323 324void NuPlayer::Decoder::onRenderBuffer(const sp<AMessage> &msg) { 325 status_t err; 326 int32_t render; 327 size_t bufferIx; 328 CHECK(msg->findSize("buffer-ix", &bufferIx)); 329 if (msg->findInt32("render", &render) && render) { 330 err = mCodec->renderOutputBufferAndRelease(bufferIx); 331 } else { 332 err = mCodec->releaseOutputBuffer(bufferIx); 333 } 334 if (err != OK) { 335 ALOGE("failed to release output buffer for %s (err=%d)", 336 mComponentName.c_str(), err); 337 handleError(err); 338 } 339} 340 341void NuPlayer::Decoder::onFlush() { 342 status_t err = OK; 343 if (mCodec != NULL) { 344 err = mCodec->flush(); 345 ++mBufferGeneration; 346 } 347 348 if (err != OK) { 349 ALOGE("failed to flush %s (err=%d)", mComponentName.c_str(), err); 350 handleError(err); 351 return; 352 } 353 354 sp<AMessage> notify = mNotify->dup(); 355 notify->setInt32("what", kWhatFlushCompleted); 356 notify->post(); 357 mPaused = true; 358} 359 360void NuPlayer::Decoder::onResume() { 361 mPaused = false; 362} 363 364void NuPlayer::Decoder::onShutdown() { 365 status_t err = OK; 366 if (mCodec != NULL) { 367 err = mCodec->release(); 368 mCodec = NULL; 369 ++mBufferGeneration; 370 371 if (mNativeWindow != NULL) { 372 // reconnect to surface as MediaCodec disconnected from it 373 CHECK_EQ((int)NO_ERROR, 374 native_window_api_connect( 375 mNativeWindow->getNativeWindow().get(), 376 NATIVE_WINDOW_API_MEDIA)); 377 } 378 mComponentName = "decoder"; 379 } 380 381 if (err != OK) { 382 ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err); 383 handleError(err); 384 return; 385 } 386 387 sp<AMessage> notify = mNotify->dup(); 388 notify->setInt32("what", kWhatShutdownCompleted); 389 notify->post(); 390 mPaused = true; 391} 392 393void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) { 394 ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str()); 395 396 switch (msg->what()) { 397 case kWhatConfigure: 398 { 399 sp<AMessage> format; 400 CHECK(msg->findMessage("format", &format)); 401 onConfigure(format); 402 break; 403 } 404 405 case kWhatCodecNotify: 406 { 407 if (!isStaleReply(msg)) { 408 if (!mPaused) { 409 while (handleAnInputBuffer()) { 410 } 411 } 412 413 while (handleAnOutputBuffer()) { 414 } 415 } 416 417 requestCodecNotification(); 418 break; 419 } 420 421 case kWhatInputBufferFilled: 422 { 423 if (!isStaleReply(msg)) { 424 onInputBufferFilled(msg); 425 } 426 break; 427 } 428 429 case kWhatRenderBuffer: 430 { 431 if (!isStaleReply(msg)) { 432 onRenderBuffer(msg); 433 } 434 break; 435 } 436 437 case kWhatFlush: 438 { 439 onFlush(); 440 break; 441 } 442 443 case kWhatResume: 444 { 445 onResume(); 446 break; 447 } 448 449 case kWhatShutdown: 450 { 451 onShutdown(); 452 break; 453 } 454 455 default: 456 TRESPASS(); 457 break; 458 } 459} 460 461void NuPlayer::Decoder::signalFlush() { 462 (new AMessage(kWhatFlush, id()))->post(); 463} 464 465void NuPlayer::Decoder::signalResume() { 466 (new AMessage(kWhatResume, id()))->post(); 467} 468 469void NuPlayer::Decoder::initiateShutdown() { 470 (new AMessage(kWhatShutdown, id()))->post(); 471} 472 473bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const { 474 if (targetFormat == NULL) { 475 return true; 476 } 477 478 AString mime; 479 if (!targetFormat->findString("mime", &mime)) { 480 return false; 481 } 482 483 if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) { 484 // field-by-field comparison 485 const char * keys[] = { "channel-count", "sample-rate", "is-adts" }; 486 for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) { 487 int32_t oldVal, newVal; 488 if (!mOutputFormat->findInt32(keys[i], &oldVal) || 489 !targetFormat->findInt32(keys[i], &newVal) || 490 oldVal != newVal) { 491 return false; 492 } 493 } 494 495 sp<ABuffer> oldBuf, newBuf; 496 if (mOutputFormat->findBuffer("csd-0", &oldBuf) && 497 targetFormat->findBuffer("csd-0", &newBuf)) { 498 if (oldBuf->size() != newBuf->size()) { 499 return false; 500 } 501 return !memcmp(oldBuf->data(), newBuf->data(), oldBuf->size()); 502 } 503 } 504 return false; 505} 506 507bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetFormat) const { 508 if (mOutputFormat == NULL) { 509 return false; 510 } 511 512 if (targetFormat == NULL) { 513 return true; 514 } 515 516 AString oldMime, newMime; 517 if (!mOutputFormat->findString("mime", &oldMime) 518 || !targetFormat->findString("mime", &newMime) 519 || !(oldMime == newMime)) { 520 return false; 521 } 522 523 bool audio = !strncasecmp(oldMime.c_str(), "audio/", strlen("audio/")); 524 bool seamless; 525 if (audio) { 526 seamless = supportsSeamlessAudioFormatChange(targetFormat); 527 } else { 528 int32_t isAdaptive; 529 seamless = (mCodec != NULL && 530 mInputFormat->findInt32("adaptive-playback", &isAdaptive) && 531 isAdaptive); 532 } 533 534 ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str()); 535 return seamless; 536} 537 538} // namespace android 539 540