Merge "Bug 3361124 Remove drmioserver, continued"
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index f8daa4f..3251c28 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -305,6 +305,8 @@
 
     void restorePatchedDataPointer(BufferInfo *info);
 
+    status_t applyRotation();
+
     OMXCodec(const OMXCodec &);
     OMXCodec &operator=(const OMXCodec &);
 };
diff --git a/include/media/stagefright/foundation/ADebug.h b/include/media/stagefright/foundation/ADebug.h
index eb5e494..450dcfe 100644
--- a/include/media/stagefright/foundation/ADebug.h
+++ b/include/media/stagefright/foundation/ADebug.h
@@ -75,7 +75,10 @@
 #define CHECK_GE(x,y)   CHECK_OP(x,y,GE,>=)
 #define CHECK_GT(x,y)   CHECK_OP(x,y,GT,>)
 
-#define TRESPASS()      LOG_ALWAYS_FATAL("Should not be here.")
+#define TRESPASS() \
+        LOG_ALWAYS_FATAL(                                       \
+            __FILE__ ":" LITERAL_TO_STRING(__LINE__)            \
+                " Should not be here.");
 
 }  // namespace android
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 7f534c0..1fcf92b 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -92,11 +92,11 @@
 }
 
 void NuPlayer::pause() {
-    // XXX to be implemented
+    (new AMessage(kWhatPause, id()))->post();
 }
 
 void NuPlayer::resume() {
-    // XXX to be implemented
+    (new AMessage(kWhatResume, id()))->post();
 }
 
 void NuPlayer::resetAsync() {
@@ -430,6 +430,20 @@
             break;
         }
 
+        case kWhatPause:
+        {
+            CHECK(mRenderer != NULL);
+            mRenderer->pause();
+            break;
+        }
+
+        case kWhatResume:
+        {
+            CHECK(mRenderer != NULL);
+            mRenderer->resume();
+            break;
+        }
+
         default:
             TRESPASS();
             break;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 339b628..bb65162 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -75,6 +75,8 @@
         kWhatRendererNotify,
         kWhatReset,
         kWhatSeek,
+        kWhatPause,
+        kWhatResume,
     };
 
     wp<NuPlayerDriver> mDriver;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 5833697..369a3a8 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -40,9 +40,10 @@
       mAnchorTimeRealUs(-1),
       mFlushingAudio(false),
       mFlushingVideo(false),
-      mHasAudio(mAudioSink != NULL),
-      mHasVideo(true),
-      mSyncQueues(mHasAudio && mHasVideo) {
+      mHasAudio(false),
+      mHasVideo(false),
+      mSyncQueues(false),
+      mPaused(false) {
 }
 
 NuPlayer::Renderer::~Renderer() {
@@ -93,6 +94,14 @@
     mSyncQueues = mHasAudio && mHasVideo;
 }
 
+void NuPlayer::Renderer::pause() {
+    (new AMessage(kWhatPause, id()))->post();
+}
+
+void NuPlayer::Renderer::resume() {
+    (new AMessage(kWhatResume, id()))->post();
+}
+
 void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
         case kWhatDrainAudioQueue:
@@ -151,6 +160,18 @@
             break;
         }
 
+        case kWhatPause:
+        {
+            onPause();
+            break;
+        }
+
+        case kWhatResume:
+        {
+            onResume();
+            break;
+        }
+
         default:
             TRESPASS();
             break;
@@ -158,7 +179,7 @@
 }
 
 void NuPlayer::Renderer::postDrainAudioQueue() {
-    if (mDrainAudioQueuePending || mSyncQueues) {
+    if (mDrainAudioQueuePending || mSyncQueues || mPaused) {
         return;
     }
 
@@ -254,7 +275,7 @@
 }
 
 void NuPlayer::Renderer::postDrainVideoQueue() {
-    if (mDrainVideoQueuePending || mSyncQueues) {
+    if (mDrainVideoQueuePending || mSyncQueues || mPaused) {
         return;
     }
 
@@ -339,6 +360,12 @@
     int32_t audio;
     CHECK(msg->findInt32("audio", &audio));
 
+    if (audio) {
+        mHasAudio = true;
+    } else {
+        mHasVideo = true;
+    }
+
     if (dropBufferWhileFlushing(audio, msg)) {
         return;
     }
@@ -528,5 +555,39 @@
     notify->post();
 }
 
+void NuPlayer::Renderer::onPause() {
+    CHECK(!mPaused);
+
+    mDrainAudioQueuePending = false;
+    ++mAudioQueueGeneration;
+
+    mDrainVideoQueuePending = false;
+    ++mVideoQueueGeneration;
+
+    if (mHasAudio) {
+        mAudioSink->pause();
+    }
+
+    mPaused = true;
+}
+
+void NuPlayer::Renderer::onResume() {
+    CHECK(mPaused);
+
+    if (mHasAudio) {
+        mAudioSink->start();
+    }
+
+    mPaused = false;
+
+    if (!mAudioQueue.empty()) {
+        postDrainAudioQueue();
+    }
+
+    if (!mVideoQueue.empty()) {
+        postDrainVideoQueue();
+    }
+}
+
 }  // namespace android
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index dbf3ecf..703e971 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -41,6 +41,9 @@
 
     void signalAudioSinkChanged();
 
+    void pause();
+    void resume();
+
     enum {
         kWhatEOS,
         kWhatFlushComplete,
@@ -60,6 +63,8 @@
         kWhatQueueEOS,
         kWhatFlush,
         kWhatAudioSinkChanged,
+        kWhatPause,
+        kWhatResume,
     };
 
     struct QueueEntry {
@@ -91,6 +96,8 @@
     bool mHasVideo;
     bool mSyncQueues;
 
+    bool mPaused;
+
     void onDrainAudioQueue();
     void postDrainAudioQueue();
 
@@ -101,6 +108,8 @@
     void onQueueEOS(const sp<AMessage> &msg);
     void onFlush(const sp<AMessage> &msg);
     void onAudioSinkChanged();
+    void onPause();
+    void onResume();
 
     void notifyEOS(bool audio);
     void notifyFlushComplete(bool audio);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 11ac56c..89b3dab 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -378,14 +378,11 @@
 }
 
 void AwesomePlayer::reset() {
-    LOGI("reset");
-
     Mutex::Autolock autoLock(mLock);
     reset_l();
 }
 
 void AwesomePlayer::reset_l() {
-    LOGI("reset_l");
     mDisplayWidth = 0;
     mDisplayHeight = 0;
 
@@ -411,10 +408,6 @@
         }
     }
 
-    if (mFlags & PREPARING) {
-        LOGI("waiting until preparation is completes.");
-    }
-
     while (mFlags & PREPARING) {
         mPreparedCondition.wait(mLock);
     }
@@ -438,8 +431,6 @@
     }
     mAudioSource.clear();
 
-    LOGI("audio source cleared");
-
     mTimeSource = NULL;
 
     delete mAudioPlayer;
@@ -480,8 +471,6 @@
         IPCThreadState::self()->flushCommands();
     }
 
-    LOGI("video source cleared");
-
     mDurationUs = -1;
     mFlags = 0;
     mExtractorFlags = 0;
@@ -498,8 +487,6 @@
     mFileSource.clear();
 
     mBitrate = -1;
-
-    LOGI("reset_l completed");
 }
 
 void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index d842f65..94694a3 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1680,6 +1680,33 @@
     return OK;
 }
 
+status_t OMXCodec::applyRotation() {
+    sp<MetaData> meta = mSource->getFormat();
+
+    int32_t rotationDegrees;
+    if (!meta->findInt32(kKeyRotation, &rotationDegrees)) {
+        rotationDegrees = 0;
+    }
+
+    uint32_t transform;
+    switch (rotationDegrees) {
+        case 0: transform = 0; break;
+        case 90: transform = HAL_TRANSFORM_ROT_90; break;
+        case 180: transform = HAL_TRANSFORM_ROT_180; break;
+        case 270: transform = HAL_TRANSFORM_ROT_270; break;
+        default: transform = 0; break;
+    }
+
+    status_t err = OK;
+
+    if (transform) {
+        err = native_window_set_buffers_transform(
+                mNativeWindow.get(), transform);
+    }
+
+    return err;
+}
+
 status_t OMXCodec::allocateOutputBuffersFromNativeWindow() {
     // Get the number of buffers needed.
     OMX_PARAM_PORTDEFINITIONTYPE def;
@@ -1713,6 +1740,11 @@
         return err;
     }
 
+    err = applyRotation();
+    if (err != OK) {
+        return err;
+    }
+
     // Set up the native window.
     // XXX TODO: Get the gralloc usage flags from the OMX plugin!
     err = native_window_set_usage(
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index f20a4cb..c6c36e3 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -506,8 +506,21 @@
 
         LOGE("This doesn't look like a transport stream...");
 
-        mDataSource->queueEOS(ERROR_UNSUPPORTED);
-        return;
+        mBandwidthItems.removeAt(bandwidthIndex);
+
+        if (mBandwidthItems.isEmpty()) {
+            mDataSource->queueEOS(ERROR_UNSUPPORTED);
+            return;
+        }
+
+        LOGI("Retrying with a different bandwidth stream.");
+
+        mLastPlaylistFetchTimeUs = -1;
+        bandwidthIndex = getBandwidthIndex();
+        mPrevBandwidthIndex = bandwidthIndex;
+        mSeqNumber = -1;
+
+        goto rinse_repeat;
     }
 
     if ((size_t)mPrevBandwidthIndex != bandwidthIndex) {
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index d8ab080..4335b99 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -75,6 +75,10 @@
 struct ATSParser::Stream : public RefBase {
     Stream(Program *program, unsigned elementaryPID, unsigned streamType);
 
+    unsigned type() const { return mStreamType; }
+    unsigned pid() const { return mElementaryPID; }
+    void setPID(unsigned pid) { mElementaryPID = pid; }
+
     void parse(
             unsigned payload_unit_start_indicator,
             ABitReader *br);
@@ -95,6 +99,7 @@
     sp<ABuffer> mBuffer;
     sp<AnotherPacketSource> mSource;
     bool mPayloadStarted;
+    DiscontinuityType mPendingDiscontinuity;
 
     ElementaryStreamQueue mQueue;
 
@@ -107,6 +112,8 @@
 
     void extractAACFrames(const sp<ABuffer> &buffer);
 
+    void deferDiscontinuity(DiscontinuityType type);
+
     DISALLOW_EVIL_CONSTRUCTORS(Stream);
 };
 
@@ -155,6 +162,11 @@
     }
 }
 
+struct StreamInfo {
+    unsigned mType;
+    unsigned mPID;
+};
+
 void ATSParser::Program::parseProgramMap(ABitReader *br) {
     unsigned table_id = br->getBits(8);
     LOGV("  table_id = %u", table_id);
@@ -188,6 +200,8 @@
 
     br->skipBits(program_info_length * 8);  // skip descriptors
 
+    Vector<StreamInfo> infos;
+
     // infoBytesRemaining is the number of bytes that make up the
     // variable length section of ES_infos. It does not include the
     // final CRC.
@@ -231,24 +245,48 @@
         CHECK_EQ(info_bytes_remaining, 0u);
 #endif
 
-        ssize_t index = mStreams.indexOfKey(elementaryPID);
-#if 0  // XXX revisit
-        CHECK_LT(index, 0);
-        mStreams.add(elementaryPID,
-                     new Stream(this, elementaryPID, streamType));
-#else
-        if (index < 0) {
-            mStreams.add(elementaryPID,
-                         new Stream(this, elementaryPID, streamType));
-        }
-#endif
+        StreamInfo info;
+        info.mType = streamType;
+        info.mPID = elementaryPID;
+        infos.push(info);
 
         infoBytesRemaining -= 5 + ES_info_length;
     }
 
     CHECK_EQ(infoBytesRemaining, 0u);
-
     MY_LOGV("  CRC = 0x%08x", br->getBits(32));
+
+    bool PIDsChanged = false;
+    for (size_t i = 0; i < infos.size(); ++i) {
+        StreamInfo &info = infos.editItemAt(i);
+
+        ssize_t index = mStreams.indexOfKey(info.mPID);
+
+        if (index >= 0 && mStreams.editValueAt(index)->type() != info.mType) {
+            LOGI("uh oh. stream PIDs have changed.");
+            PIDsChanged = true;
+            break;
+        }
+    }
+
+    if (PIDsChanged) {
+        mStreams.clear();
+    }
+
+    for (size_t i = 0; i < infos.size(); ++i) {
+        StreamInfo &info = infos.editItemAt(i);
+
+        ssize_t index = mStreams.indexOfKey(info.mPID);
+
+        if (index < 0) {
+            sp<Stream> stream = new Stream(this, info.mPID, info.mType);
+            mStreams.add(info.mPID, stream);
+
+            if (PIDsChanged) {
+                stream->signalDiscontinuity(DISCONTINUITY_FORMATCHANGE);
+            }
+        }
+    }
 }
 
 sp<MediaSource> ATSParser::Program::getSource(SourceType type) {
@@ -290,6 +328,7 @@
       mStreamType(streamType),
       mBuffer(new ABuffer(192 * 1024)),
       mPayloadStarted(false),
+      mPendingDiscontinuity(DISCONTINUITY_NONE),
       mQueue(streamType == 0x1b
               ? ElementaryStreamQueue::H264 : ElementaryStreamQueue::AAC) {
     mBuffer->setRange(0, 0);
@@ -336,9 +375,13 @@
         {
             mQueue.clear(true);
 
-            if (mStreamType == 0x1b && mSource != NULL) {
+            if (mStreamType == 0x1b) {
                 // Don't signal discontinuities on audio streams.
-                mSource->queueDiscontinuity(type);
+                if (mSource != NULL) {
+                    mSource->queueDiscontinuity(type);
+                } else {
+                    deferDiscontinuity(type);
+                }
             }
             break;
         }
@@ -352,6 +395,8 @@
 
             if (mSource != NULL) {
                 mSource->queueDiscontinuity(type);
+            } else {
+                deferDiscontinuity(type);
             }
             break;
         }
@@ -362,6 +407,13 @@
     }
 }
 
+void ATSParser::Stream::deferDiscontinuity(DiscontinuityType type) {
+    if (type > mPendingDiscontinuity) {
+        // Only upgrade discontinuities.
+        mPendingDiscontinuity = type;
+    }
+}
+
 void ATSParser::Stream::signalEOS(status_t finalResult) {
     if (mSource != NULL) {
         mSource->signalEOS(finalResult);
@@ -558,6 +610,11 @@
                 LOGV("created source!");
                 mSource = new AnotherPacketSource(meta);
 
+                if (mPendingDiscontinuity != DISCONTINUITY_NONE) {
+                    mSource->queueDiscontinuity(mPendingDiscontinuity);
+                    mPendingDiscontinuity = DISCONTINUITY_NONE;
+                }
+
                 mSource->queueAccessUnit(accessUnit);
             }
         } else if (mQueue.getFormat() != NULL) {
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index fe31981..ec3be84 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -33,6 +33,7 @@
 
 struct ATSParser : public RefBase {
     enum DiscontinuityType {
+        DISCONTINUITY_NONE,
         DISCONTINUITY_HTTPLIVE,
         DISCONTINUITY_SEEK,
         DISCONTINUITY_FORMATCHANGE