NuPlayerDecoder.cpp revision 87603c0dd1f4e62e52feffa8d6e960ad21f68893
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/ABitReader.h> 26#include <media/stagefright/foundation/ABuffer.h> 27#include <media/stagefright/foundation/ADebug.h> 28#include <media/stagefright/foundation/AMessage.h> 29#include <media/stagefright/MediaBuffer.h> 30#include <media/stagefright/MediaCodec.h> 31#include <media/stagefright/MediaDefs.h> 32#include <media/stagefright/MediaErrors.h> 33 34namespace android { 35 36NuPlayer::Decoder::Decoder( 37 const sp<AMessage> ¬ify, 38 const sp<NativeWindowWrapper> &nativeWindow) 39 : mNotify(notify), 40 mNativeWindow(nativeWindow), 41 mBufferGeneration(0), 42 mPaused(true), 43 mComponentName("decoder") { 44 // Every decoder has its own looper because MediaCodec operations 45 // are blocking, but NuPlayer needs asynchronous operations. 46 mDecoderLooper = new ALooper; 47 mDecoderLooper->setName("NPDecoder"); 48 mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO); 49 50 mCodecLooper = new ALooper; 51 mCodecLooper->setName("NPDecoder-CL"); 52 mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO); 53} 54 55NuPlayer::Decoder::~Decoder() { 56} 57 58static 59status_t PostAndAwaitResponse( 60 const sp<AMessage> &msg, sp<AMessage> *response) { 61 status_t err = msg->postAndAwaitResponse(response); 62 63 if (err != OK) { 64 return err; 65 } 66 67 if (!(*response)->findInt32("err", &err)) { 68 err = OK; 69 } 70 71 return err; 72} 73 74void NuPlayer::Decoder::rememberCodecSpecificData(const sp<AMessage> &format) { 75 mCSDsForCurrentFormat.clear(); 76 for (int32_t i = 0; ; ++i) { 77 AString tag = "csd-"; 78 tag.append(i); 79 sp<ABuffer> buffer; 80 if (!format->findBuffer(tag.c_str(), &buffer)) { 81 break; 82 } 83 mCSDsForCurrentFormat.push(buffer); 84 } 85} 86 87void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) { 88 CHECK(mCodec == NULL); 89 90 ++mBufferGeneration; 91 92 AString mime; 93 CHECK(format->findString("mime", &mime)); 94 95 sp<Surface> surface = NULL; 96 if (mNativeWindow != NULL) { 97 surface = mNativeWindow->getSurfaceTextureClient(); 98 } 99 100 mComponentName = mime; 101 mComponentName.append(" decoder"); 102 ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), surface.get()); 103 104 mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */); 105 int32_t secure = 0; 106 if (format->findInt32("secure", &secure) && secure != 0) { 107 if (mCodec != NULL) { 108 mCodec->getName(&mComponentName); 109 mComponentName.append(".secure"); 110 mCodec->release(); 111 ALOGI("[%s] creating", mComponentName.c_str()); 112 mCodec = MediaCodec::CreateByComponentName( 113 mCodecLooper, mComponentName.c_str()); 114 } 115 } 116 if (mCodec == NULL) { 117 ALOGE("Failed to create %s%s decoder", 118 (secure ? "secure " : ""), mime.c_str()); 119 handleError(UNKNOWN_ERROR); 120 return; 121 } 122 123 mCodec->getName(&mComponentName); 124 125 if (mNativeWindow != NULL) { 126 // disconnect from surface as MediaCodec will reconnect 127 CHECK_EQ((int)NO_ERROR, 128 native_window_api_disconnect( 129 surface.get(), 130 NATIVE_WINDOW_API_MEDIA)); 131 } 132 status_t err = mCodec->configure( 133 format, surface, NULL /* crypto */, 0 /* flags */); 134 if (err != OK) { 135 ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err); 136 handleError(err); 137 return; 138 } 139 rememberCodecSpecificData(format); 140 141 // the following should work in configured state 142 CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat)); 143 CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat)); 144 145 err = mCodec->start(); 146 if (err != OK) { 147 ALOGE("Failed to start %s decoder (err=%d)", mComponentName.c_str(), err); 148 handleError(err); 149 return; 150 } 151 152 // the following should work after start 153 CHECK_EQ((status_t)OK, mCodec->getInputBuffers(&mInputBuffers)); 154 releaseAndResetMediaBuffers(); 155 CHECK_EQ((status_t)OK, mCodec->getOutputBuffers(&mOutputBuffers)); 156 ALOGV("[%s] got %zu input and %zu output buffers", 157 mComponentName.c_str(), 158 mInputBuffers.size(), 159 mOutputBuffers.size()); 160 161 requestCodecNotification(); 162 mPaused = false; 163} 164 165void NuPlayer::Decoder::releaseAndResetMediaBuffers() { 166 for (size_t i = 0; i < mMediaBuffers.size(); i++) { 167 if (mMediaBuffers[i] != NULL) { 168 mMediaBuffers[i]->release(); 169 mMediaBuffers.editItemAt(i) = NULL; 170 } 171 } 172 mMediaBuffers.resize(mInputBuffers.size()); 173 for (size_t i = 0; i < mMediaBuffers.size(); i++) { 174 mMediaBuffers.editItemAt(i) = NULL; 175 } 176 mInputBufferIsDequeued.clear(); 177 mInputBufferIsDequeued.resize(mInputBuffers.size()); 178 for (size_t i = 0; i < mInputBufferIsDequeued.size(); i++) { 179 mInputBufferIsDequeued.editItemAt(i) = false; 180 } 181} 182 183void NuPlayer::Decoder::requestCodecNotification() { 184 if (mCodec != NULL) { 185 sp<AMessage> reply = new AMessage(kWhatCodecNotify, id()); 186 reply->setInt32("generation", mBufferGeneration); 187 mCodec->requestActivityNotification(reply); 188 } 189} 190 191bool NuPlayer::Decoder::isStaleReply(const sp<AMessage> &msg) { 192 int32_t generation; 193 CHECK(msg->findInt32("generation", &generation)); 194 return generation != mBufferGeneration; 195} 196 197void NuPlayer::Decoder::init() { 198 mDecoderLooper->registerHandler(this); 199} 200 201void NuPlayer::Decoder::configure(const sp<AMessage> &format) { 202 sp<AMessage> msg = new AMessage(kWhatConfigure, id()); 203 msg->setMessage("format", format); 204 msg->post(); 205} 206 207void NuPlayer::Decoder::signalUpdateFormat(const sp<AMessage> &format) { 208 sp<AMessage> msg = new AMessage(kWhatUpdateFormat, id()); 209 msg->setMessage("format", format); 210 msg->post(); 211} 212 213status_t NuPlayer::Decoder::getInputBuffers(Vector<sp<ABuffer> > *buffers) const { 214 sp<AMessage> msg = new AMessage(kWhatGetInputBuffers, id()); 215 msg->setPointer("buffers", buffers); 216 217 sp<AMessage> response; 218 return PostAndAwaitResponse(msg, &response); 219} 220 221void NuPlayer::Decoder::handleError(int32_t err) 222{ 223 sp<AMessage> notify = mNotify->dup(); 224 notify->setInt32("what", kWhatError); 225 notify->setInt32("err", err); 226 notify->post(); 227} 228 229bool NuPlayer::Decoder::handleAnInputBuffer() { 230 size_t bufferIx = -1; 231 status_t res = mCodec->dequeueInputBuffer(&bufferIx); 232 ALOGV("[%s] dequeued input: %d", 233 mComponentName.c_str(), res == OK ? (int)bufferIx : res); 234 if (res != OK) { 235 if (res != -EAGAIN) { 236 handleError(res); 237 } 238 return false; 239 } 240 241 CHECK_LT(bufferIx, mInputBuffers.size()); 242 243 if (mMediaBuffers[bufferIx] != NULL) { 244 mMediaBuffers[bufferIx]->release(); 245 mMediaBuffers.editItemAt(bufferIx) = NULL; 246 } 247 mInputBufferIsDequeued.editItemAt(bufferIx) = true; 248 249 sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, id()); 250 reply->setSize("buffer-ix", bufferIx); 251 reply->setInt32("generation", mBufferGeneration); 252 253 if (!mCSDsToSubmit.isEmpty()) { 254 sp<ABuffer> buffer = mCSDsToSubmit.itemAt(0); 255 ALOGI("[%s] resubmitting CSD", mComponentName.c_str()); 256 reply->setBuffer("buffer", buffer); 257 mCSDsToSubmit.removeAt(0); 258 reply->post(); 259 return true; 260 } 261 262 sp<AMessage> notify = mNotify->dup(); 263 notify->setInt32("what", kWhatFillThisBuffer); 264 notify->setBuffer("buffer", mInputBuffers[bufferIx]); 265 notify->setMessage("reply", reply); 266 notify->post(); 267 return true; 268} 269 270void android::NuPlayer::Decoder::onInputBufferFilled(const sp<AMessage> &msg) { 271 size_t bufferIx; 272 CHECK(msg->findSize("buffer-ix", &bufferIx)); 273 CHECK_LT(bufferIx, mInputBuffers.size()); 274 sp<ABuffer> codecBuffer = mInputBuffers[bufferIx]; 275 276 sp<ABuffer> buffer; 277 bool hasBuffer = msg->findBuffer("buffer", &buffer); 278 279 // handle widevine classic source - that fills an arbitrary input buffer 280 MediaBuffer *mediaBuffer = NULL; 281 if (hasBuffer && buffer->meta()->findPointer( 282 "mediaBuffer", (void **)&mediaBuffer)) { 283 if (mediaBuffer == NULL) { 284 // received no actual buffer 285 ALOGW("[%s] received null MediaBuffer %s", 286 mComponentName.c_str(), msg->debugString().c_str()); 287 buffer = NULL; 288 } else { 289 // likely filled another buffer than we requested: adjust buffer index 290 size_t ix; 291 for (ix = 0; ix < mInputBuffers.size(); ix++) { 292 const sp<ABuffer> &buf = mInputBuffers[ix]; 293 if (buf->data() == mediaBuffer->data()) { 294 // all input buffers are dequeued on start, hence the check 295 CHECK(mInputBufferIsDequeued[ix]); 296 ALOGV("[%s] received MediaBuffer for #%zu instead of #%zu", 297 mComponentName.c_str(), ix, bufferIx); 298 299 // TRICKY: need buffer for the metadata, so instead, set 300 // codecBuffer to the same (though incorrect) buffer to 301 // avoid a memcpy into the codecBuffer 302 codecBuffer = buffer; 303 codecBuffer->setRange( 304 mediaBuffer->range_offset(), 305 mediaBuffer->range_length()); 306 bufferIx = ix; 307 break; 308 } 309 } 310 CHECK(ix < mInputBuffers.size()); 311 } 312 } 313 314 mInputBufferIsDequeued.editItemAt(bufferIx) = false; 315 316 if (buffer == NULL /* includes !hasBuffer */) { 317 int32_t streamErr = ERROR_END_OF_STREAM; 318 CHECK(msg->findInt32("err", &streamErr) || !hasBuffer); 319 320 if (streamErr == OK) { 321 /* buffers are returned to hold on to */ 322 return; 323 } 324 325 // attempt to queue EOS 326 status_t err = mCodec->queueInputBuffer( 327 bufferIx, 328 0, 329 0, 330 0, 331 MediaCodec::BUFFER_FLAG_EOS); 332 if (streamErr == ERROR_END_OF_STREAM && err != OK) { 333 streamErr = err; 334 // err will not be ERROR_END_OF_STREAM 335 } 336 337 if (streamErr != ERROR_END_OF_STREAM) { 338 handleError(streamErr); 339 } 340 } else { 341 int64_t timeUs = 0; 342 uint32_t flags = 0; 343 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 344 345 int32_t eos, csd; 346 // we do not expect SYNCFRAME for decoder 347 if (buffer->meta()->findInt32("eos", &eos) && eos) { 348 flags |= MediaCodec::BUFFER_FLAG_EOS; 349 } else if (buffer->meta()->findInt32("csd", &csd) && csd) { 350 flags |= MediaCodec::BUFFER_FLAG_CODECCONFIG; 351 } 352 353 // copy into codec buffer 354 if (buffer != codecBuffer) { 355 CHECK_LE(buffer->size(), codecBuffer->capacity()); 356 codecBuffer->setRange(0, buffer->size()); 357 memcpy(codecBuffer->data(), buffer->data(), buffer->size()); 358 } 359 360 status_t err = mCodec->queueInputBuffer( 361 bufferIx, 362 codecBuffer->offset(), 363 codecBuffer->size(), 364 timeUs, 365 flags); 366 if (err != OK) { 367 ALOGE("Failed to queue input buffer for %s (err=%d)", 368 mComponentName.c_str(), err); 369 handleError(err); 370 } 371 372 if (mediaBuffer != NULL) { 373 CHECK(mMediaBuffers[bufferIx] == NULL); 374 mMediaBuffers.editItemAt(bufferIx) = mediaBuffer; 375 } 376 } 377} 378 379bool NuPlayer::Decoder::handleAnOutputBuffer() { 380 size_t bufferIx = -1; 381 size_t offset; 382 size_t size; 383 int64_t timeUs; 384 uint32_t flags; 385 status_t res = mCodec->dequeueOutputBuffer( 386 &bufferIx, &offset, &size, &timeUs, &flags); 387 388 if (res != OK) { 389 ALOGV("[%s] dequeued output: %d", mComponentName.c_str(), res); 390 } else { 391 ALOGV("[%s] dequeued output: %d (time=%lld flags=%" PRIu32 ")", 392 mComponentName.c_str(), (int)bufferIx, timeUs, flags); 393 } 394 395 if (res == INFO_OUTPUT_BUFFERS_CHANGED) { 396 res = mCodec->getOutputBuffers(&mOutputBuffers); 397 if (res != OK) { 398 ALOGE("Failed to get output buffers for %s after INFO event (err=%d)", 399 mComponentName.c_str(), res); 400 handleError(res); 401 return false; 402 } 403 // NuPlayer ignores this 404 return true; 405 } else if (res == INFO_FORMAT_CHANGED) { 406 sp<AMessage> format = new AMessage(); 407 res = mCodec->getOutputFormat(&format); 408 if (res != OK) { 409 ALOGE("Failed to get output format for %s after INFO event (err=%d)", 410 mComponentName.c_str(), res); 411 handleError(res); 412 return false; 413 } 414 415 sp<AMessage> notify = mNotify->dup(); 416 notify->setInt32("what", kWhatOutputFormatChanged); 417 notify->setMessage("format", format); 418 notify->post(); 419 return true; 420 } else if (res == INFO_DISCONTINUITY) { 421 // nothing to do 422 return true; 423 } else if (res != OK) { 424 if (res != -EAGAIN) { 425 handleError(res); 426 } 427 return false; 428 } 429 430 CHECK_LT(bufferIx, mOutputBuffers.size()); 431 sp<ABuffer> buffer = mOutputBuffers[bufferIx]; 432 buffer->setRange(offset, size); 433 buffer->meta()->clear(); 434 buffer->meta()->setInt64("timeUs", timeUs); 435 if (flags & MediaCodec::BUFFER_FLAG_EOS) { 436 buffer->meta()->setInt32("eos", true); 437 } 438 // we do not expect CODECCONFIG or SYNCFRAME for decoder 439 440 sp<AMessage> reply = new AMessage(kWhatRenderBuffer, id()); 441 reply->setSize("buffer-ix", bufferIx); 442 reply->setInt32("generation", mBufferGeneration); 443 444 sp<AMessage> notify = mNotify->dup(); 445 notify->setInt32("what", kWhatDrainThisBuffer); 446 notify->setBuffer("buffer", buffer); 447 notify->setMessage("reply", reply); 448 notify->post(); 449 450 // FIXME: This should be handled after rendering is complete, 451 // but Renderer needs it now 452 if (flags & MediaCodec::BUFFER_FLAG_EOS) { 453 ALOGV("queueing eos [%s]", mComponentName.c_str()); 454 sp<AMessage> notify = mNotify->dup(); 455 notify->setInt32("what", kWhatEOS); 456 notify->setInt32("err", ERROR_END_OF_STREAM); 457 notify->post(); 458 } 459 return true; 460} 461 462void NuPlayer::Decoder::onRenderBuffer(const sp<AMessage> &msg) { 463 status_t err; 464 int32_t render; 465 size_t bufferIx; 466 CHECK(msg->findSize("buffer-ix", &bufferIx)); 467 if (msg->findInt32("render", &render) && render) { 468 err = mCodec->renderOutputBufferAndRelease(bufferIx); 469 } else { 470 err = mCodec->releaseOutputBuffer(bufferIx); 471 } 472 if (err != OK) { 473 ALOGE("failed to release output buffer for %s (err=%d)", 474 mComponentName.c_str(), err); 475 handleError(err); 476 } 477} 478 479void NuPlayer::Decoder::onFlush() { 480 status_t err = OK; 481 if (mCodec != NULL) { 482 err = mCodec->flush(); 483 mCSDsToSubmit = mCSDsForCurrentFormat; // copy operator 484 ++mBufferGeneration; 485 } 486 487 if (err != OK) { 488 ALOGE("failed to flush %s (err=%d)", mComponentName.c_str(), err); 489 handleError(err); 490 return; 491 } 492 493 releaseAndResetMediaBuffers(); 494 495 sp<AMessage> notify = mNotify->dup(); 496 notify->setInt32("what", kWhatFlushCompleted); 497 notify->post(); 498 mPaused = true; 499} 500 501void NuPlayer::Decoder::onResume() { 502 mPaused = false; 503} 504 505void NuPlayer::Decoder::onShutdown() { 506 status_t err = OK; 507 if (mCodec != NULL) { 508 err = mCodec->release(); 509 mCodec = NULL; 510 ++mBufferGeneration; 511 512 if (mNativeWindow != NULL) { 513 // reconnect to surface as MediaCodec disconnected from it 514 status_t error = 515 native_window_api_connect( 516 mNativeWindow->getNativeWindow().get(), 517 NATIVE_WINDOW_API_MEDIA); 518 ALOGW_IF(error != NO_ERROR, 519 "[%s] failed to connect to native window, error=%d", 520 mComponentName.c_str(), error); 521 } 522 mComponentName = "decoder"; 523 } 524 525 releaseAndResetMediaBuffers(); 526 527 if (err != OK) { 528 ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err); 529 handleError(err); 530 return; 531 } 532 533 sp<AMessage> notify = mNotify->dup(); 534 notify->setInt32("what", kWhatShutdownCompleted); 535 notify->post(); 536 mPaused = true; 537} 538 539void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) { 540 ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str()); 541 542 switch (msg->what()) { 543 case kWhatConfigure: 544 { 545 sp<AMessage> format; 546 CHECK(msg->findMessage("format", &format)); 547 onConfigure(format); 548 break; 549 } 550 551 case kWhatUpdateFormat: 552 { 553 sp<AMessage> format; 554 CHECK(msg->findMessage("format", &format)); 555 rememberCodecSpecificData(format); 556 break; 557 } 558 559 case kWhatGetInputBuffers: 560 { 561 uint32_t replyID; 562 CHECK(msg->senderAwaitsResponse(&replyID)); 563 564 Vector<sp<ABuffer> > *dstBuffers; 565 CHECK(msg->findPointer("buffers", (void **)&dstBuffers)); 566 567 dstBuffers->clear(); 568 for (size_t i = 0; i < mInputBuffers.size(); i++) { 569 dstBuffers->push(mInputBuffers[i]); 570 } 571 572 (new AMessage)->postReply(replyID); 573 break; 574 } 575 576 case kWhatCodecNotify: 577 { 578 if (!isStaleReply(msg)) { 579 if (!mPaused) { 580 while (handleAnInputBuffer()) { 581 } 582 } 583 584 while (handleAnOutputBuffer()) { 585 } 586 } 587 588 requestCodecNotification(); 589 break; 590 } 591 592 case kWhatInputBufferFilled: 593 { 594 if (!isStaleReply(msg)) { 595 onInputBufferFilled(msg); 596 } 597 break; 598 } 599 600 case kWhatRenderBuffer: 601 { 602 if (!isStaleReply(msg)) { 603 onRenderBuffer(msg); 604 } 605 break; 606 } 607 608 case kWhatFlush: 609 { 610 sp<AMessage> format; 611 if (msg->findMessage("new-format", &format)) { 612 rememberCodecSpecificData(format); 613 } 614 onFlush(); 615 break; 616 } 617 618 case kWhatResume: 619 { 620 onResume(); 621 break; 622 } 623 624 case kWhatShutdown: 625 { 626 onShutdown(); 627 break; 628 } 629 630 default: 631 TRESPASS(); 632 break; 633 } 634} 635 636void NuPlayer::Decoder::signalFlush(const sp<AMessage> &format) { 637 sp<AMessage> msg = new AMessage(kWhatFlush, id()); 638 if (format != NULL) { 639 msg->setMessage("new-format", format); 640 } 641 msg->post(); 642} 643 644void NuPlayer::Decoder::signalResume() { 645 (new AMessage(kWhatResume, id()))->post(); 646} 647 648void NuPlayer::Decoder::initiateShutdown() { 649 (new AMessage(kWhatShutdown, id()))->post(); 650} 651 652bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const { 653 if (targetFormat == NULL) { 654 return true; 655 } 656 657 AString mime; 658 if (!targetFormat->findString("mime", &mime)) { 659 return false; 660 } 661 662 if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) { 663 // field-by-field comparison 664 const char * keys[] = { "channel-count", "sample-rate", "is-adts" }; 665 for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) { 666 int32_t oldVal, newVal; 667 if (!mOutputFormat->findInt32(keys[i], &oldVal) || 668 !targetFormat->findInt32(keys[i], &newVal) || 669 oldVal != newVal) { 670 return false; 671 } 672 } 673 674 sp<ABuffer> oldBuf, newBuf; 675 if (mOutputFormat->findBuffer("csd-0", &oldBuf) && 676 targetFormat->findBuffer("csd-0", &newBuf)) { 677 if (oldBuf->size() != newBuf->size()) { 678 return false; 679 } 680 return !memcmp(oldBuf->data(), newBuf->data(), oldBuf->size()); 681 } 682 } 683 return false; 684} 685 686bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetFormat) const { 687 if (mOutputFormat == NULL) { 688 return false; 689 } 690 691 if (targetFormat == NULL) { 692 return true; 693 } 694 695 AString oldMime, newMime; 696 if (!mOutputFormat->findString("mime", &oldMime) 697 || !targetFormat->findString("mime", &newMime) 698 || !(oldMime == newMime)) { 699 return false; 700 } 701 702 bool audio = !strncasecmp(oldMime.c_str(), "audio/", strlen("audio/")); 703 bool seamless; 704 if (audio) { 705 seamless = supportsSeamlessAudioFormatChange(targetFormat); 706 } else { 707 int32_t isAdaptive; 708 seamless = (mCodec != NULL && 709 mInputFormat->findInt32("adaptive-playback", &isAdaptive) && 710 isAdaptive); 711 } 712 713 ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str()); 714 return seamless; 715} 716 717struct NuPlayer::CCDecoder::CCData { 718 CCData(uint8_t type, uint8_t data1, uint8_t data2) 719 : mType(type), mData1(data1), mData2(data2) { 720 } 721 722 uint8_t mType; 723 uint8_t mData1; 724 uint8_t mData2; 725}; 726 727NuPlayer::CCDecoder::CCDecoder(const sp<AMessage> ¬ify) 728 : mNotify(notify), 729 mTrackCount(0), 730 mSelectedTrack(-1) { 731} 732 733size_t NuPlayer::CCDecoder::getTrackCount() const { 734 return mTrackCount; 735} 736 737sp<AMessage> NuPlayer::CCDecoder::getTrackInfo(size_t index) const { 738 CHECK(index == 0); 739 740 sp<AMessage> format = new AMessage(); 741 742 format->setInt32("type", MEDIA_TRACK_TYPE_SUBTITLE); 743 format->setString("language", "und"); 744 format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608); 745 format->setInt32("auto", 1); 746 format->setInt32("default", 1); 747 format->setInt32("forced", 0); 748 749 return format; 750} 751 752status_t NuPlayer::CCDecoder::selectTrack(size_t index, bool select) { 753 CHECK(index < mTrackCount); 754 755 if (select) { 756 if (mSelectedTrack == (ssize_t)index) { 757 ALOGE("track %zu already selected", index); 758 return BAD_VALUE; 759 } 760 ALOGV("selected track %zu", index); 761 mSelectedTrack = index; 762 } else { 763 if (mSelectedTrack != (ssize_t)index) { 764 ALOGE("track %zu is not selected", index); 765 return BAD_VALUE; 766 } 767 ALOGV("unselected track %zu", index); 768 mSelectedTrack = -1; 769 } 770 771 return OK; 772} 773 774bool NuPlayer::CCDecoder::isSelected() const { 775 return mSelectedTrack >= 0 && mSelectedTrack < (int32_t)mTrackCount; 776} 777 778bool NuPlayer::CCDecoder::isNullPad(CCData *cc) const { 779 return cc->mData1 < 0x10 && cc->mData2 < 0x10; 780} 781 782void NuPlayer::CCDecoder::dumpBytePair(const sp<ABuffer> &ccBuf) const { 783 size_t offset = 0; 784 AString out; 785 786 while (offset < ccBuf->size()) { 787 char tmp[128]; 788 789 CCData *cc = (CCData *) (ccBuf->data() + offset); 790 791 if (isNullPad(cc)) { 792 // 1 null pad or XDS metadata, ignore 793 offset += sizeof(CCData); 794 continue; 795 } 796 797 if (cc->mData1 >= 0x20 && cc->mData1 <= 0x7f) { 798 // 2 basic chars 799 sprintf(tmp, "[%d]Basic: %c %c", cc->mType, cc->mData1, cc->mData2); 800 } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19) 801 && cc->mData2 >= 0x30 && cc->mData2 <= 0x3f) { 802 // 1 special char 803 sprintf(tmp, "[%d]Special: %02x %02x", cc->mType, cc->mData1, cc->mData2); 804 } else if ((cc->mData1 == 0x12 || cc->mData1 == 0x1A) 805 && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){ 806 // 1 Spanish/French char 807 sprintf(tmp, "[%d]Spanish: %02x %02x", cc->mType, cc->mData1, cc->mData2); 808 } else if ((cc->mData1 == 0x13 || cc->mData1 == 0x1B) 809 && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){ 810 // 1 Portuguese/German/Danish char 811 sprintf(tmp, "[%d]German: %02x %02x", cc->mType, cc->mData1, cc->mData2); 812 } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19) 813 && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f){ 814 // Mid-Row Codes (Table 69) 815 sprintf(tmp, "[%d]Mid-row: %02x %02x", cc->mType, cc->mData1, cc->mData2); 816 } else if (((cc->mData1 == 0x14 || cc->mData1 == 0x1c) 817 && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f) 818 || 819 ((cc->mData1 == 0x17 || cc->mData1 == 0x1f) 820 && cc->mData2 >= 0x21 && cc->mData2 <= 0x23)){ 821 // Misc Control Codes (Table 70) 822 sprintf(tmp, "[%d]Ctrl: %02x %02x", cc->mType, cc->mData1, cc->mData2); 823 } else if ((cc->mData1 & 0x70) == 0x10 824 && (cc->mData2 & 0x40) == 0x40 825 && ((cc->mData1 & 0x07) || !(cc->mData2 & 0x20)) ) { 826 // Preamble Address Codes (Table 71) 827 sprintf(tmp, "[%d]PAC: %02x %02x", cc->mType, cc->mData1, cc->mData2); 828 } else { 829 sprintf(tmp, "[%d]Invalid: %02x %02x", cc->mType, cc->mData1, cc->mData2); 830 } 831 832 if (out.size() > 0) { 833 out.append(", "); 834 } 835 836 out.append(tmp); 837 838 offset += sizeof(CCData); 839 } 840 841 ALOGI("%s", out.c_str()); 842} 843 844bool NuPlayer::CCDecoder::extractFromSEI(const sp<ABuffer> &accessUnit) { 845 int64_t timeUs; 846 CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs)); 847 848 sp<ABuffer> sei; 849 if (!accessUnit->meta()->findBuffer("sei", &sei) || sei == NULL) { 850 return false; 851 } 852 853 bool hasCC = false; 854 855 NALBitReader br(sei->data() + 1, sei->size() - 1); 856 // sei_message() 857 while (br.atLeastNumBitsLeft(16)) { // at least 16-bit for sei_message() 858 uint32_t payload_type = 0; 859 size_t payload_size = 0; 860 uint8_t last_byte; 861 862 do { 863 last_byte = br.getBits(8); 864 payload_type += last_byte; 865 } while (last_byte == 0xFF); 866 867 do { 868 last_byte = br.getBits(8); 869 payload_size += last_byte; 870 } while (last_byte == 0xFF); 871 872 // sei_payload() 873 if (payload_type == 4) { 874 // user_data_registered_itu_t_t35() 875 876 // ATSC A/72: 6.4.2 877 uint8_t itu_t_t35_country_code = br.getBits(8); 878 uint16_t itu_t_t35_provider_code = br.getBits(16); 879 uint32_t user_identifier = br.getBits(32); 880 uint8_t user_data_type_code = br.getBits(8); 881 882 payload_size -= 1 + 2 + 4 + 1; 883 884 if (itu_t_t35_country_code == 0xB5 885 && itu_t_t35_provider_code == 0x0031 886 && user_identifier == 'GA94' 887 && user_data_type_code == 0x3) { 888 hasCC = true; 889 890 // MPEG_cc_data() 891 // ATSC A/53 Part 4: 6.2.3.1 892 br.skipBits(1); //process_em_data_flag 893 bool process_cc_data_flag = br.getBits(1); 894 br.skipBits(1); //additional_data_flag 895 size_t cc_count = br.getBits(5); 896 br.skipBits(8); // em_data; 897 payload_size -= 2; 898 899 if (process_cc_data_flag) { 900 AString out; 901 902 sp<ABuffer> ccBuf = new ABuffer(cc_count * sizeof(CCData)); 903 ccBuf->setRange(0, 0); 904 905 for (size_t i = 0; i < cc_count; i++) { 906 uint8_t marker = br.getBits(5); 907 CHECK_EQ(marker, 0x1f); 908 909 bool cc_valid = br.getBits(1); 910 uint8_t cc_type = br.getBits(2); 911 // remove odd parity bit 912 uint8_t cc_data_1 = br.getBits(8) & 0x7f; 913 uint8_t cc_data_2 = br.getBits(8) & 0x7f; 914 915 if (cc_valid 916 && (cc_type == 0 || cc_type == 1)) { 917 CCData cc(cc_type, cc_data_1, cc_data_2); 918 if (!isNullPad(&cc)) { 919 memcpy(ccBuf->data() + ccBuf->size(), 920 (void *)&cc, sizeof(cc)); 921 ccBuf->setRange(0, ccBuf->size() + sizeof(CCData)); 922 } 923 } 924 } 925 payload_size -= cc_count * 3; 926 927 mCCMap.add(timeUs, ccBuf); 928 break; 929 } 930 } else { 931 ALOGV("Malformed SEI payload type 4"); 932 } 933 } else { 934 ALOGV("Unsupported SEI payload type %d", payload_type); 935 } 936 937 // skipping remaining bits of this payload 938 br.skipBits(payload_size * 8); 939 } 940 941 return hasCC; 942} 943 944void NuPlayer::CCDecoder::decode(const sp<ABuffer> &accessUnit) { 945 if (extractFromSEI(accessUnit) && mTrackCount == 0) { 946 mTrackCount++; 947 948 ALOGI("Found CEA-608 track"); 949 sp<AMessage> msg = mNotify->dup(); 950 msg->setInt32("what", kWhatTrackAdded); 951 msg->post(); 952 } 953 // TODO: extract CC from other sources 954} 955 956void NuPlayer::CCDecoder::display(int64_t timeUs) { 957 ssize_t index = mCCMap.indexOfKey(timeUs); 958 if (index < 0) { 959 ALOGV("cc for timestamp %" PRId64 " not found", timeUs); 960 return; 961 } 962 963 sp<ABuffer> &ccBuf = mCCMap.editValueAt(index); 964 965 if (ccBuf->size() > 0) { 966#if 0 967 dumpBytePair(ccBuf); 968#endif 969 970 ccBuf->meta()->setInt32("trackIndex", mSelectedTrack); 971 ccBuf->meta()->setInt64("timeUs", timeUs); 972 ccBuf->meta()->setInt64("durationUs", 0ll); 973 974 sp<AMessage> msg = mNotify->dup(); 975 msg->setInt32("what", kWhatClosedCaptionData); 976 msg->setBuffer("buffer", ccBuf); 977 msg->post(); 978 } 979 980 // remove all entries before timeUs 981 mCCMap.removeItemsAt(0, index + 1); 982} 983 984} // namespace android 985 986