Merge "Expose an API to run the WV extractor in crypto plugin mode." into jb-dev
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index b15cb67..1387e74 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1345,7 +1345,7 @@
 }
 
 void AwesomePlayer::addTextSource(size_t trackIndex, const sp<MediaSource>& source) {
-    Mutex::Autolock autoLock(mTimedTextLock);
+    Mutex::Autolock autoLock(mLock);
     CHECK(source != NULL);
 
     if (mTextDriver == NULL) {
@@ -1395,7 +1395,6 @@
     if (mAudioSource != NULL) {
         Mutex::Autolock autoLock(mStatsLock);
         TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex);
-
         const char *component;
         if (!mAudioSource->getFormat()
                 ->findCString(kKeyDecoderComponent, &component)) {
@@ -2268,13 +2267,13 @@
 }
 
 status_t AwesomePlayer::getTrackInfo(Parcel *reply) const {
-    Mutex::Autolock autoLock(mTimedTextLock);
-    if (mTextDriver == NULL) {
-        return INVALID_OPERATION;
+    Mutex::Autolock autoLock(mLock);
+    size_t trackCount = mExtractor->countTracks();
+    if (mTextDriver != NULL) {
+        trackCount += mTextDriver->countExternalTracks();
     }
 
-    reply->writeInt32(mTextDriver->countExternalTracks() +
-                mExtractor->countTracks());
+    reply->writeInt32(trackCount);
     for (size_t i = 0; i < mExtractor->countTracks(); ++i) {
         sp<MetaData> meta = mExtractor->getTrackMetaData(i);
 
@@ -2296,28 +2295,31 @@
         }
 
         const char *lang;
-        if (meta->findCString(kKeyMediaLanguage, &lang)) {
-            reply->writeString16(String16(lang));
-        } else {
-            reply->writeString16(String16(""));
+        if (!meta->findCString(kKeyMediaLanguage, &lang)) {
+            lang = "und";
         }
+        reply->writeString16(String16(lang));
     }
 
-    mTextDriver->getExternalTrackInfo(reply);
+    if (mTextDriver != NULL) {
+        mTextDriver->getExternalTrackInfo(reply);
+    }
     return OK;
 }
 
 // FIXME:
 // At present, only timed text track is able to be selected or unselected.
 status_t AwesomePlayer::selectTrack(size_t trackIndex, bool select) {
-    Mutex::Autolock autoLock(mTimedTextLock);
-    if (mTextDriver == NULL) {
-        return INVALID_OPERATION;
+    ALOGV("selectTrack: trackIndex = %d and select=%d", trackIndex, select);
+    Mutex::Autolock autoLock(mLock);
+    size_t trackCount = mExtractor->countTracks();
+    if (mTextDriver != NULL) {
+        trackCount += mTextDriver->countExternalTracks();
     }
 
-    if (trackIndex >= mExtractor->countTracks()
-                + mTextDriver->countExternalTracks()) {
-        return BAD_VALUE;
+    if (trackIndex >= trackCount) {
+        ALOGE("Track index (%d) is out of range [0, %d)", trackIndex, trackCount);
+        return ERROR_OUT_OF_RANGE;
     }
 
     if (trackIndex < mExtractor->countTracks()) {
@@ -2331,6 +2333,11 @@
         }
     }
 
+    // Timed text track handling
+    if (mTextDriver == NULL) {
+        return INVALID_OPERATION;
+    }
+
     status_t err = OK;
     if (select) {
         err = mTextDriver->selectTrack(trackIndex);
@@ -2371,7 +2378,7 @@
         }
         case INVOKE_ID_ADD_EXTERNAL_SOURCE:
         {
-            Mutex::Autolock autoLock(mTimedTextLock);
+            Mutex::Autolock autoLock(mLock);
             if (mTextDriver == NULL) {
                 mTextDriver = new TimedTextDriver(mListener);
             }
@@ -2383,7 +2390,7 @@
         }
         case INVOKE_ID_ADD_EXTERNAL_SOURCE_FD:
         {
-            Mutex::Autolock autoLock(mTimedTextLock);
+            Mutex::Autolock autoLock(mLock);
             if (mTextDriver == NULL) {
                 mTextDriver = new TimedTextDriver(mListener);
             }
@@ -2398,12 +2405,12 @@
         case INVOKE_ID_SELECT_TRACK:
         {
             int trackIndex = request.readInt32();
-            return selectTrack(trackIndex, true);
+            return selectTrack(trackIndex, true /* select */);
         }
         case INVOKE_ID_UNSELECT_TRACK:
         {
             int trackIndex = request.readInt32();
-            return selectTrack(trackIndex, false);
+            return selectTrack(trackIndex, false /* select */);
         }
         default:
         {
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 7706bf6..547a554 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -108,6 +108,7 @@
             status = OK;
         }
     }
+    mIsFirst = true;
     return status;
 }
 
@@ -298,7 +299,16 @@
             inInfo->mOwnedByUs = false;
             notifyEmptyBufferDone(inHeader);
 
-            outHeader->nFilledLen = 0;
+            // flush out the decoder's delayed data by calling DecodeFrame one more time, with
+            // the AACDEC_FLUSH flag set
+            INT_PCM *outBuffer =
+                    reinterpret_cast<INT_PCM *>(outHeader->pBuffer + outHeader->nOffset);
+            decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
+                                                outBuffer,
+                                                outHeader->nAllocLen,
+                                                AACDEC_FLUSH);
+            outHeader->nFilledLen =
+                    mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
             outHeader->nFlags = OMX_BUFFERFLAG_EOS;
 
             outQueue.erase(outQueue.begin());
@@ -412,6 +422,12 @@
             // We'll only output data if we successfully decoded it or
             // we've previously decoded valid data, in the latter case
             // (decode failed) we'll output a silent frame.
+            if (mIsFirst) {
+                mIsFirst = false;
+                // the first decoded frame should be discarded to account for decoder delay
+                numOutBytes = 0;
+            }
+
             outHeader->nFilledLen = numOutBytes;
             outHeader->nFlags = 0;
 
@@ -447,6 +463,7 @@
         // Make sure that the next buffer output does not still
         // depend on fragments from the last one decoded.
         mInputDiscontinuity = true;
+        mIsFirst = true;
     }
 }
 
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h
index d93685c..e5a1e3e 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.h
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h
@@ -50,6 +50,7 @@
     HANDLE_AACDECODER mAACDecoder;
     CStreamInfo *mStreamInfo;
     bool mIsADTS;
+    bool mIsFirst;
     size_t mInputBufferCount;
     bool mSignalledError;
     bool mInputDiscontinuity;
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 9115f91..a2e2e85 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -232,7 +232,6 @@
 
     int64_t mLastVideoTimeUs;
     TimedTextDriver *mTextDriver;
-    mutable Mutex mTimedTextLock;
 
     sp<WVMExtractor> mWVMExtractor;
     sp<MediaExtractor> mExtractor;
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp
index dc5f6b8..f855d90 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.cpp
+++ b/media/libstagefright/timedtext/TimedTextPlayer.cpp
@@ -112,15 +112,14 @@
               break;
             }
             sp<RefBase> obj;
-            msg->findObject("subtitle", &obj);
-            if (obj != NULL) {
+            if (msg->findObject("subtitle", &obj)) {
                 sp<ParcelEvent> parcelEvent;
                 parcelEvent = static_cast<ParcelEvent*>(obj.get());
                 notifyListener(&(parcelEvent->parcel));
+                doRead();
             } else {
                 notifyListener();
             }
-            doRead();
             break;
         }
         case kWhatSetSource: {