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