Merge "ProCameraTests: Minor add grey/frame count debug-only print outs" into jb-mr2-dev
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 3596b38..88df6b0 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -35,7 +35,13 @@
     MPEG4Writer(const char *filename);
     MPEG4Writer(int fd);
 
+    // Limitations
+    // 1. No more than 2 tracks can be added
+    // 2. Only video or audio source can be added
+    // 3. No more than one video and/or one audio source can be added.
     virtual status_t addSource(const sp<MediaSource> &source);
+
+    // Returns INVALID_OPERATION if there is no source or track.
     virtual status_t start(MetaData *param = NULL);
     virtual status_t stop() { return reset(); }
     virtual status_t pause();
diff --git a/libvideoeditor/vss/3gpwriter/src/M4MP4W_Writer.c b/libvideoeditor/vss/3gpwriter/src/M4MP4W_Writer.c
index 9ad94e0..cdfc441 100755
--- a/libvideoeditor/vss/3gpwriter/src/M4MP4W_Writer.c
+++ b/libvideoeditor/vss/3gpwriter/src/M4MP4W_Writer.c
@@ -2486,6 +2486,12 @@
 
 #endif
 
+        if ((M4MP4W_Time32)auPtr->CTS < mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS) {
+            // Do not report as error, it will abort the entire filewrite. Just skip this frame.
+            M4OSA_TRACE1_0("Skip frame. Video frame has too old timestamp.");
+            return M4NO_ERROR;
+        }
+
         mMp4FileDataPtr->videoTrackPtr->currentPos += auPtr->size;
 
         /* Warning: time conversion cast 64to32! */
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index b2e60be..56fad60 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -2067,17 +2067,30 @@
         sampleRate = br.getBits(24);
         numChannels = br.getBits(4);
     } else {
-        static uint32_t kSamplingRate[] = {
-            96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
-            16000, 12000, 11025, 8000, 7350
-        };
-
-        if (freqIndex == 13 || freqIndex == 14) {
-            return ERROR_MALFORMED;
+        numChannels = br.getBits(4);
+        if (objectType == 5) {
+            // SBR specific config per 14496-3 table 1.13
+            freqIndex = br.getBits(4);
+            if (freqIndex == 15) {
+                if (csd_size < 8) {
+                    return ERROR_MALFORMED;
+                }
+                sampleRate = br.getBits(24);
+            }
         }
 
-        sampleRate = kSamplingRate[freqIndex];
-        numChannels = br.getBits(4);
+        if (sampleRate == 0) {
+            static uint32_t kSamplingRate[] = {
+                96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+                16000, 12000, 11025, 8000, 7350
+            };
+
+            if (freqIndex == 13 || freqIndex == 14) {
+                return ERROR_MALFORMED;
+            }
+
+            sampleRate = kSamplingRate[freqIndex];
+        }
     }
 
     if (numChannels == 0) {
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 056b47a..316f669 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -428,6 +428,42 @@
         ALOGE("Attempt to add source AFTER recording is started");
         return UNKNOWN_ERROR;
     }
+
+    // At most 2 tracks can be supported.
+    if (mTracks.size() >= 2) {
+        ALOGE("Too many tracks (%d) to add", mTracks.size());
+        return ERROR_UNSUPPORTED;
+    }
+
+    CHECK(source.get() != NULL);
+
+    // A track of type other than video or audio is not supported.
+    const char *mime;
+    source->getFormat()->findCString(kKeyMIMEType, &mime);
+    bool isAudio = !strncasecmp(mime, "audio/", 6);
+    bool isVideo = !strncasecmp(mime, "video/", 6);
+    if (!isAudio && !isVideo) {
+        ALOGE("Track (%s) other than video or audio is not supported",
+            mime);
+        return ERROR_UNSUPPORTED;
+    }
+
+    // At this point, we know the track to be added is either
+    // video or audio. Thus, we only need to check whether it
+    // is an audio track or not (if it is not, then it must be
+    // a video track).
+
+    // No more than one video or one audio track is supported.
+    for (List<Track*>::iterator it = mTracks.begin();
+         it != mTracks.end(); ++it) {
+        if ((*it)->isAudio() == isAudio) {
+            ALOGE("%s track already exists", isAudio? "Audio": "Video");
+            return ERROR_UNSUPPORTED;
+        }
+    }
+
+    // This is the first track of either audio or video.
+    // Go ahead to add the track.
     Track *track = new Track(this, source, 1 + mTracks.size());
     mTracks.push_back(track);
 
@@ -435,6 +471,11 @@
 }
 
 status_t MPEG4Writer::startTracks(MetaData *params) {
+    if (mTracks.empty()) {
+        ALOGE("No source added");
+        return INVALID_OPERATION;
+    }
+
     for (List<Track *>::iterator it = mTracks.begin();
          it != mTracks.end(); ++it) {
         status_t err = (*it)->start(params);
diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp
index aefc270..21841b3 100644
--- a/media/libstagefright/MediaMuxer.cpp
+++ b/media/libstagefright/MediaMuxer.cpp
@@ -76,17 +76,17 @@
     convertMessageToMetaData(format, meta);
 
     sp<MediaAdapter> newTrack = new MediaAdapter(meta);
-    return mTrackList.add(newTrack);
+    status_t result = mWriter->addSource(newTrack);
+    if (result == OK) {
+        return mTrackList.add(newTrack);
+    }
+    return -1;
 }
 
 status_t MediaMuxer::start() {
     Mutex::Autolock autoLock(mMuxerLock);
-
     if (mState == INITED) {
         mState = STARTED;
-        for (size_t i = 0 ; i < mTrackList.size(); i++) {
-            mWriter->addSource(mTrackList[i]);
-        }
         return mWriter->start();
     } else {
         ALOGE("start() is called in invalid state %d", mState);
@@ -100,7 +100,9 @@
     if (mState == STARTED) {
         mState = STOPPED;
         for (size_t i = 0; i < mTrackList.size(); i++) {
-            mTrackList[i]->stop();
+            if (mTrackList[i]->stop() != OK) {
+                return INVALID_OPERATION;
+            }
         }
         return mWriter->stop();
     } else {
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 5d760d3..95ed43a 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -511,6 +511,9 @@
 
                     if (response->mStatusCode != 200) {
                         result = UNKNOWN_ERROR;
+                    } else if (response->mContent == NULL) {
+                        result = ERROR_MALFORMED;
+                        ALOGE("The response has no content.");
                     } else {
                         mSessionDesc = new ASessionDescription;