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 21 #include "NuPlayerDecoder.h" 22 23 #include <media/stagefright/foundation/ABuffer.h> 24 #include <media/stagefright/foundation/ADebug.h> 25 #include <media/stagefright/foundation/AMessage.h> 26 #include <media/stagefright/ACodec.h> 27 #include <media/stagefright/MediaDefs.h> 28 29 namespace android { 30 31 NuPlayer::Decoder::Decoder( 32 const sp<AMessage> ¬ify, 33 const sp<NativeWindowWrapper> &nativeWindow) 34 : mNotify(notify), 35 mNativeWindow(nativeWindow) { 36 } 37 38 NuPlayer::Decoder::~Decoder() { 39 } 40 41 void NuPlayer::Decoder::configure(const sp<AMessage> &format) { 42 CHECK(mCodec == NULL); 43 44 AString mime; 45 CHECK(format->findString("mime", &mime)); 46 47 sp<AMessage> notifyMsg = 48 new AMessage(kWhatCodecNotify, id()); 49 50 mCSDIndex = 0; 51 for (size_t i = 0;; ++i) { 52 sp<ABuffer> csd; 53 if (!format->findBuffer(StringPrintf("csd-%d", i).c_str(), &csd)) { 54 break; 55 } 56 57 mCSD.push(csd); 58 } 59 60 if (mNativeWindow != NULL) { 61 format->setObject("native-window", mNativeWindow); 62 } 63 64 // Current video decoders do not return from OMX_FillThisBuffer 65 // quickly, violating the OpenMAX specs, until that is remedied 66 // we need to invest in an extra looper to free the main event 67 // queue. 68 bool needDedicatedLooper = !strncasecmp(mime.c_str(), "video/", 6); 69 70 mFormat = format; 71 mCodec = new ACodec; 72 73 if (needDedicatedLooper && mCodecLooper == NULL) { 74 mCodecLooper = new ALooper; 75 mCodecLooper->setName("NuPlayerDecoder"); 76 mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO); 77 } 78 79 (needDedicatedLooper ? mCodecLooper : looper())->registerHandler(mCodec); 80 81 mCodec->setNotificationMessage(notifyMsg); 82 mCodec->initiateSetup(format); 83 } 84 85 void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) { 86 switch (msg->what()) { 87 case kWhatCodecNotify: 88 { 89 int32_t what; 90 CHECK(msg->findInt32("what", &what)); 91 92 if (what == ACodec::kWhatFillThisBuffer) { 93 onFillThisBuffer(msg); 94 } else { 95 sp<AMessage> notify = mNotify->dup(); 96 notify->setMessage("codec-request", msg); 97 notify->post(); 98 } 99 break; 100 } 101 102 default: 103 TRESPASS(); 104 break; 105 } 106 } 107 108 void NuPlayer::Decoder::onFillThisBuffer(const sp<AMessage> &msg) { 109 sp<AMessage> reply; 110 CHECK(msg->findMessage("reply", &reply)); 111 112 #if 0 113 sp<ABuffer> outBuffer; 114 CHECK(msg->findBuffer("buffer", &outBuffer)); 115 #else 116 sp<ABuffer> outBuffer; 117 #endif 118 119 if (mCSDIndex < mCSD.size()) { 120 outBuffer = mCSD.editItemAt(mCSDIndex++); 121 outBuffer->meta()->setInt64("timeUs", 0); 122 123 reply->setBuffer("buffer", outBuffer); 124 reply->post(); 125 return; 126 } 127 128 sp<AMessage> notify = mNotify->dup(); 129 notify->setMessage("codec-request", msg); 130 notify->post(); 131 } 132 133 void NuPlayer::Decoder::signalFlush() { 134 if (mCodec != NULL) { 135 mCodec->signalFlush(); 136 } 137 } 138 139 void NuPlayer::Decoder::signalResume() { 140 if (mCodec != NULL) { 141 mCodec->signalResume(); 142 } 143 } 144 145 void NuPlayer::Decoder::initiateShutdown() { 146 if (mCodec != NULL) { 147 mCodec->initiateShutdown(); 148 } 149 } 150 151 bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const { 152 if (targetFormat == NULL) { 153 return true; 154 } 155 156 AString mime; 157 if (!targetFormat->findString("mime", &mime)) { 158 return false; 159 } 160 161 if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) { 162 // field-by-field comparison 163 const char * keys[] = { "channel-count", "sample-rate", "is-adts" }; 164 for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) { 165 int32_t oldVal, newVal; 166 if (!mFormat->findInt32(keys[i], &oldVal) || !targetFormat->findInt32(keys[i], &newVal) 167 || oldVal != newVal) { 168 return false; 169 } 170 } 171 172 sp<ABuffer> oldBuf, newBuf; 173 if (mFormat->findBuffer("csd-0", &oldBuf) && targetFormat->findBuffer("csd-0", &newBuf)) { 174 if (oldBuf->size() != newBuf->size()) { 175 return false; 176 } 177 return !memcmp(oldBuf->data(), newBuf->data(), oldBuf->size()); 178 } 179 } 180 return false; 181 } 182 183 bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetFormat) const { 184 if (mFormat == NULL) { 185 return false; 186 } 187 188 if (targetFormat == NULL) { 189 return true; 190 } 191 192 AString oldMime, newMime; 193 if (!mFormat->findString("mime", &oldMime) 194 || !targetFormat->findString("mime", &newMime) 195 || !(oldMime == newMime)) { 196 return false; 197 } 198 199 bool audio = !strncasecmp(oldMime.c_str(), "audio/", strlen("audio/")); 200 bool seamless; 201 if (audio) { 202 seamless = supportsSeamlessAudioFormatChange(targetFormat); 203 } else { 204 seamless = mCodec != NULL && mCodec->isConfiguredForAdaptivePlayback(); 205 } 206 207 ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str()); 208 return seamless; 209 } 210 211 } // namespace android 212 213