Home | History | Annotate | Download | only in nuplayer
      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> &notify,
     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