refactor getTrackInfo()

(this is in preparation for supporting other cc source)

- split into two methods: getTrackCount() and getTrackInfo()

- move track info parcelling to NuPlayer

- parcel in the mime type of the subtitle format

Bug: 15470448
Change-Id: If00724d8c3a2b2319cb9c5f29d3fe76347bfe947
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 563c0b5..45eb9e1 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -60,6 +60,7 @@
 
 extern const char *MEDIA_MIMETYPE_TEXT_3GPP;
 extern const char *MEDIA_MIMETYPE_TEXT_SUBRIP;
+extern const char *MEDIA_MIMETYPE_TEXT_VTT;
 
 }  // namespace android
 
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index cbedf5c..e8431e9 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -120,8 +120,12 @@
     return mLiveSession->getDuration(durationUs);
 }
 
-status_t NuPlayer::HTTPLiveSource::getTrackInfo(Parcel *reply) const {
-    return mLiveSession->getTrackInfo(reply);
+size_t NuPlayer::HTTPLiveSource::getTrackCount() const {
+    return mLiveSession->getTrackCount();
+}
+
+sp<AMessage> NuPlayer::HTTPLiveSource::getTrackInfo(size_t trackIndex) const {
+    return mLiveSession->getTrackInfo(trackIndex);
 }
 
 status_t NuPlayer::HTTPLiveSource::selectTrack(size_t trackIndex, bool select) {
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
index 4d7251f..6b5f6af 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
@@ -40,7 +40,8 @@
 
     virtual status_t feedMoreTSData();
     virtual status_t getDuration(int64_t *durationUs);
-    virtual status_t getTrackInfo(Parcel *reply) const;
+    virtual size_t getTrackCount() const;
+    virtual sp<AMessage> getTrackInfo(size_t trackIndex) const;
     virtual status_t selectTrack(size_t trackIndex, bool select);
     virtual status_t seekTo(int64_t seekTimeUs);
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 857e703..dc69f73 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -305,6 +305,34 @@
     }
 }
 
+void NuPlayer::writeTrackInfo(
+        Parcel* reply, const sp<AMessage> format) const {
+    int32_t trackType;
+    CHECK(format->findInt32("type", &trackType));
+
+    AString lang;
+    CHECK(format->findString("language", &lang));
+
+    reply->writeInt32(2); // write something non-zero
+    reply->writeInt32(trackType);
+    reply->writeString16(String16(lang.c_str()));
+
+    if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
+        AString mime;
+        CHECK(format->findString("mime", &mime));
+
+        int32_t isAuto, isDefault, isForced;
+        CHECK(format->findInt32("auto", &isAuto));
+        CHECK(format->findInt32("default", &isDefault));
+        CHECK(format->findInt32("forced", &isForced));
+
+        reply->writeString16(String16(mime.c_str()));
+        reply->writeInt32(isAuto);
+        reply->writeInt32(isDefault);
+        reply->writeInt32(isForced);
+    }
+}
+
 void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
         case kWhatSetDataSource:
@@ -339,16 +367,23 @@
             uint32_t replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
-            status_t err = INVALID_OPERATION;
+            Parcel* reply;
+            CHECK(msg->findPointer("reply", (void**)&reply));
+
+            size_t inbandTracks = 0;
             if (mSource != NULL) {
-                Parcel* reply;
-                CHECK(msg->findPointer("reply", (void**)&reply));
-                err = mSource->getTrackInfo(reply);
+                inbandTracks = mSource->getTrackCount();
+            }
+
+            // total track count
+            reply->writeInt32(inbandTracks);
+
+            // write inband tracks
+            for (size_t i = 0; i < inbandTracks; ++i) {
+                writeTrackInfo(reply, mSource->getTrackInfo(i));
             }
 
             sp<AMessage> response = new AMessage;
-            response->setInt32("err", err);
-
             response->postReply(replyID);
             break;
         }
@@ -358,12 +393,19 @@
             uint32_t replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
+            size_t trackIndex;
+            int32_t select;
+            CHECK(msg->findSize("trackIndex", &trackIndex));
+            CHECK(msg->findInt32("select", &select));
+
             status_t err = INVALID_OPERATION;
+
+            size_t inbandTracks = 0;
             if (mSource != NULL) {
-                size_t trackIndex;
-                int32_t select;
-                CHECK(msg->findSize("trackIndex", &trackIndex));
-                CHECK(msg->findInt32("select", &select));
+                inbandTracks = mSource->getTrackCount();
+            }
+
+            if (trackIndex < inbandTracks) {
                 err = mSource->selectTrack(trackIndex, select);
             }
 
@@ -1187,6 +1229,14 @@
     sp<AMessage> response;
     status_t err = msg->postAndAwaitResponse(&response);
 
+    if (err != OK) {
+        return err;
+    }
+
+    if (!response->findInt32("err", &err)) {
+        err = OK;
+    }
+
     return err;
 }
 
@@ -1438,21 +1488,7 @@
             sp<ABuffer> buffer;
             CHECK(msg->findBuffer("buffer", &buffer));
 
-            int32_t trackIndex;
-            int64_t timeUs, durationUs;
-            CHECK(buffer->meta()->findInt32("trackIndex", &trackIndex));
-            CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
-            CHECK(buffer->meta()->findInt64("durationUs", &durationUs));
-
-            Parcel in;
-            in.writeInt32(trackIndex);
-            in.writeInt64(timeUs);
-            in.writeInt64(durationUs);
-            in.writeInt32(buffer->size());
-            in.writeInt32(buffer->size());
-            in.write(buffer->data(), buffer->size());
-
-            notifyListener(MEDIA_SUBTITLE_DATA, 0, 0, &in);
+            sendSubtitleData(buffer, 0 /* baseIndex */);
             break;
         }
 
@@ -1474,6 +1510,23 @@
     }
 }
 
+void NuPlayer::sendSubtitleData(const sp<ABuffer> &buffer, int32_t baseIndex) {
+    int32_t trackIndex;
+    int64_t timeUs, durationUs;
+    CHECK(buffer->meta()->findInt32("trackIndex", &trackIndex));
+    CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
+    CHECK(buffer->meta()->findInt64("durationUs", &durationUs));
+
+    Parcel in;
+    in.writeInt32(trackIndex + baseIndex);
+    in.writeInt64(timeUs);
+    in.writeInt64(durationUs);
+    in.writeInt32(buffer->size());
+    in.writeInt32(buffer->size());
+    in.write(buffer->data(), buffer->size());
+
+    notifyListener(MEDIA_SUBTITLE_DATA, 0, 0, &in);
+}
 ////////////////////////////////////////////////////////////////////////////////
 
 void NuPlayer::Source::notifyFlagsChanged(uint32_t flags) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index f1d3d55..f95cc11 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -24,6 +24,7 @@
 
 namespace android {
 
+struct ABuffer;
 struct MetaData;
 struct NuPlayerDriver;
 
@@ -189,6 +190,10 @@
     void queueDecoderShutdown(
             bool audio, bool video, const sp<AMessage> &reply);
 
+    void sendSubtitleData(const sp<ABuffer> &buffer, int32_t baseIndex);
+
+    void writeTrackInfo(Parcel* reply, const sp<AMessage> format) const;
+
     DISALLOW_EVIL_CONSTRUCTORS(NuPlayer);
 };
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 11279fc..f5a1d6d 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -72,8 +72,12 @@
         return INVALID_OPERATION;
     }
 
-    virtual status_t getTrackInfo(Parcel* /* reply */) const {
-        return INVALID_OPERATION;
+    virtual size_t getTrackCount() const {
+        return 0;
+    }
+
+    virtual sp<AMessage> getTrackInfo(size_t /* trackIndex */) const {
+        return NULL;
     }
 
     virtual status_t selectTrack(size_t /* trackIndex */, bool /* select */) {
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 8229e55..f38729e 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -58,5 +58,6 @@
 
 const char *MEDIA_MIMETYPE_TEXT_3GPP = "text/3gpp-tt";
 const char *MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
+const char *MEDIA_MIMETYPE_TEXT_VTT = "text/vtt";
 
 }  // namespace android
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 08a146f..10cdde2 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -926,8 +926,12 @@
     return false;
 }
 
-status_t LiveSession::getTrackInfo(Parcel *reply) const {
-    return mPlaylist->getTrackInfo(reply);
+size_t LiveSession::getTrackCount() const {
+    return mPlaylist->getTrackCount();
+}
+
+sp<AMessage> LiveSession::getTrackInfo(size_t trackIndex) const {
+    return mPlaylist->getTrackInfo(trackIndex);
 }
 
 status_t LiveSession::selectTrack(size_t index, bool select) {
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index d7ed56f..ed3818f 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -70,7 +70,8 @@
     status_t seekTo(int64_t timeUs);
 
     status_t getDuration(int64_t *durationUs) const;
-    status_t getTrackInfo(Parcel *reply) const;
+    size_t getTrackCount() const;
+    sp<AMessage> getTrackInfo(size_t trackIndex) const;
     status_t selectTrack(size_t index, bool select);
 
     bool isSeekable() const;
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index 785c515..281e0da 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -23,6 +23,7 @@
 #include <cutils/properties.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/Utils.h>
 #include <media/mediaplayer.h>
@@ -58,8 +59,8 @@
 
     void pickRandomMediaItems();
     status_t selectTrack(size_t index, bool select);
-    void getTrackInfo(Parcel* reply) const;
     size_t countTracks() const;
+    sp<AMessage> getTrackInfo(size_t index) const;
 
 protected:
     virtual ~MediaGroup();
@@ -184,37 +185,44 @@
     return OK;
 }
 
-void M3UParser::MediaGroup::getTrackInfo(Parcel* reply) const {
-    for (size_t i = 0; i < mMediaItems.size(); ++i) {
-        reply->writeInt32(2); // 2 fields
-
-        if (mType == TYPE_AUDIO) {
-            reply->writeInt32(MEDIA_TRACK_TYPE_AUDIO);
-        } else if (mType == TYPE_VIDEO) {
-            reply->writeInt32(MEDIA_TRACK_TYPE_VIDEO);
-        } else if (mType == TYPE_SUBS) {
-            reply->writeInt32(MEDIA_TRACK_TYPE_SUBTITLE);
-        } else {
-            reply->writeInt32(MEDIA_TRACK_TYPE_UNKNOWN);
-        }
-
-        const Media &item = mMediaItems.itemAt(i);
-        const char *lang = item.mLanguage.empty() ? "und" : item.mLanguage.c_str();
-        reply->writeString16(String16(lang));
-
-        if (mType == TYPE_SUBS) {
-            // TO-DO: pass in a MediaFormat instead
-            reply->writeInt32(!!(item.mFlags & MediaGroup::FLAG_AUTOSELECT));
-            reply->writeInt32(!!(item.mFlags & MediaGroup::FLAG_DEFAULT));
-            reply->writeInt32(!!(item.mFlags & MediaGroup::FLAG_FORCED));
-        }
-    }
-}
-
 size_t M3UParser::MediaGroup::countTracks() const {
     return mMediaItems.size();
 }
 
+sp<AMessage> M3UParser::MediaGroup::getTrackInfo(size_t index) const {
+    if (index >= mMediaItems.size()) {
+        return NULL;
+    }
+
+    sp<AMessage> format = new AMessage();
+
+    int32_t trackType;
+    if (mType == TYPE_AUDIO) {
+        trackType = MEDIA_TRACK_TYPE_AUDIO;
+    } else if (mType == TYPE_VIDEO) {
+        trackType = MEDIA_TRACK_TYPE_VIDEO;
+    } else if (mType == TYPE_SUBS) {
+        trackType = MEDIA_TRACK_TYPE_SUBTITLE;
+    } else {
+        trackType = MEDIA_TRACK_TYPE_UNKNOWN;
+    }
+    format->setInt32("type", trackType);
+
+    const Media &item = mMediaItems.itemAt(index);
+    const char *lang = item.mLanguage.empty() ? "und" : item.mLanguage.c_str();
+    format->setString("language", lang);
+
+    if (mType == TYPE_SUBS) {
+        // TO-DO: pass in a MediaFormat instead
+        format->setString("mime", MEDIA_MIMETYPE_TEXT_VTT);
+        format->setInt32("auto", !!(item.mFlags & MediaGroup::FLAG_AUTOSELECT));
+        format->setInt32("default", !!(item.mFlags & MediaGroup::FLAG_DEFAULT));
+        format->setInt32("forced", !!(item.mFlags & MediaGroup::FLAG_FORCED));
+    }
+
+    return format;
+}
+
 bool M3UParser::MediaGroup::getActiveURI(AString *uri) const {
     for (size_t i = 0; i < mMediaItems.size(); ++i) {
         if (mSelectedIndex >= 0 && i == (size_t)mSelectedIndex) {
@@ -319,17 +327,24 @@
     return INVALID_OPERATION;
 }
 
-status_t M3UParser::getTrackInfo(Parcel* reply) const {
+size_t M3UParser::getTrackCount() const {
     size_t trackCount = 0;
     for (size_t i = 0; i < mMediaGroups.size(); ++i) {
         trackCount += mMediaGroups.valueAt(i)->countTracks();
     }
-    reply->writeInt32(trackCount);
+    return trackCount;
+}
 
-    for (size_t i = 0; i < mMediaGroups.size(); ++i) {
-        mMediaGroups.valueAt(i)->getTrackInfo(reply);
+sp<AMessage> M3UParser::getTrackInfo(size_t index) const {
+    for (size_t i = 0, ii = index; i < mMediaGroups.size(); ++i) {
+        sp<MediaGroup> group = mMediaGroups.valueAt(i);
+        size_t tracks = group->countTracks();
+        if (ii < tracks) {
+            return group->getTrackInfo(ii);
+        }
+        ii -= tracks;
     }
-    return OK;
+    return NULL;
 }
 
 ssize_t M3UParser::getSelectedIndex() const {
diff --git a/media/libstagefright/httplive/M3UParser.h b/media/libstagefright/httplive/M3UParser.h
index ccd6556..fe9fb9d 100644
--- a/media/libstagefright/httplive/M3UParser.h
+++ b/media/libstagefright/httplive/M3UParser.h
@@ -42,7 +42,8 @@
 
     void pickRandomMediaItems();
     status_t selectTrack(size_t index, bool select);
-    status_t getTrackInfo(Parcel* reply) const;
+    size_t getTrackCount() const;
+    sp<AMessage> getTrackInfo(size_t index) const;
     ssize_t getSelectedIndex() const;
 
     bool getTypeURI(size_t index, const char *key, AString *uri) const;