Merge "Added two more video encoders"
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 8ab94ad..eb4b733 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+#define LOG_TAG "stagefright"
+#include <media/stagefright/foundation/ADebug.h>
+
 #include <sys/time.h>
 
 #include <stdlib.h>
@@ -30,7 +34,6 @@
 #include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/JPEGSource.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaExtractor.h>
@@ -43,6 +46,8 @@
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MPEG4Writer.h>
 
+#include <fcntl.h>
+
 using namespace android;
 
 static long gNumRepetitions;
@@ -120,7 +125,7 @@
 
             bool shouldSeek = false;
             if (err == INFO_FORMAT_CHANGED) {
-                CHECK_EQ(buffer, NULL);
+                CHECK(buffer == NULL);
 
                 printf("format changed.\n");
                 continue;
@@ -206,7 +211,7 @@
             options.clearSeekTo();
 
             if (err != OK) {
-                CHECK_EQ(buffer, NULL);
+                CHECK(buffer == NULL);
 
                 if (err == INFO_FORMAT_CHANGED) {
                     printf("format changed.\n");
@@ -267,14 +272,98 @@
     }
 }
 
-static void writeSourceToMP4(const sp<MediaSource> &source) {
+////////////////////////////////////////////////////////////////////////////////
+
+struct DetectSyncSource : public MediaSource {
+    DetectSyncSource(const sp<MediaSource> &source);
+
+    virtual status_t start(MetaData *params = NULL);
+    virtual status_t stop();
+    virtual sp<MetaData> getFormat();
+
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options);
+
+private:
+    sp<MediaSource> mSource;
+    bool mIsAVC;
+
+    DISALLOW_EVIL_CONSTRUCTORS(DetectSyncSource);
+};
+
+DetectSyncSource::DetectSyncSource(const sp<MediaSource> &source)
+    : mSource(source),
+      mIsAVC(false) {
+    const char *mime;
+    CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
+
+    mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
+}
+
+status_t DetectSyncSource::start(MetaData *params) {
+    return mSource->start(params);
+}
+
+status_t DetectSyncSource::stop() {
+    return mSource->stop();
+}
+
+sp<MetaData> DetectSyncSource::getFormat() {
+    return mSource->getFormat();
+}
+
+static bool isIDRFrame(MediaBuffer *buffer) {
+    const uint8_t *data =
+        (const uint8_t *)buffer->data() + buffer->range_offset();
+    size_t size = buffer->range_length();
+    for (size_t i = 0; i + 3 < size; ++i) {
+        if (!memcmp("\x00\x00\x01", &data[i], 3)) {
+            uint8_t nalType = data[i + 3] & 0x1f;
+            if (nalType == 5) {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+status_t DetectSyncSource::read(
+        MediaBuffer **buffer, const ReadOptions *options) {
+    status_t err = mSource->read(buffer, options);
+
+    if (err != OK) {
+        return err;
+    }
+
+    if (mIsAVC && isIDRFrame(*buffer)) {
+        (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame, true);
+    } else {
+        (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame, false);
+    }
+
+    return OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+static void writeSourceToMP4(
+        sp<MediaSource> &source, bool syncInfoPresent) {
+    if (!syncInfoPresent) {
+        source = new DetectSyncSource(source);
+    }
+
     sp<MPEG4Writer> writer =
         new MPEG4Writer(gWriteMP4Filename.string());
 
-    CHECK_EQ(writer->addSource(source), OK);
+    // at most one minute.
+    writer->setMaxFileDuration(60000000ll);
+
+    CHECK_EQ(writer->addSource(source), (status_t)OK);
 
     sp<MetaData> params = new MetaData;
-    CHECK_EQ(writer->start(), OK);
+    params->setInt32(kKeyNotRealTime, true);
+    CHECK_EQ(writer->start(params.get()), (status_t)OK);
 
     while (!writer->reachedEOS()) {
         usleep(100000);
@@ -283,7 +372,7 @@
 }
 
 static void performSeekTest(const sp<MediaSource> &source) {
-    CHECK_EQ(OK, source->start());
+    CHECK_EQ((status_t)OK, source->start());
 
     int64_t durationUs;
     CHECK(source->getFormat()->findInt64(kKeyDuration, &durationUs));
@@ -335,7 +424,7 @@
         }
     }
 
-    CHECK_EQ(OK, source->stop());
+    CHECK_EQ((status_t)OK, source->stop());
 }
 
 static void usage(const char *me) {
@@ -481,10 +570,10 @@
         for (int k = 0; k < argc; ++k) {
             const char *filename = argv[k];
 
-            CHECK_EQ(retriever->setDataSource(filename), OK);
+            CHECK_EQ(retriever->setDataSource(filename), (status_t)OK);
             CHECK_EQ(retriever->setMode(
                         METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL),
-                     OK);
+                     (status_t)OK);
 
             sp<IMemory> mem = retriever->captureFrame();
 
@@ -530,7 +619,7 @@
             Vector<CodecCapabilities> results;
             CHECK_EQ(QueryCodecs(omx, kMimeTypes[k],
                                  true, // queryDecoders
-                                 &results), OK);
+                                 &results), (status_t)OK);
 
             for (size_t i = 0; i < results.size(); ++i) {
                 printf("  decoder '%s' supports ",
@@ -579,6 +668,8 @@
     status_t err = client.connect();
 
     for (int k = 0; k < argc; ++k) {
+        bool syncInfoPresent = true;
+
         const char *filename = argv[k];
 
         sp<DataSource> dataSource = DataSource::CreateFromURI(filename);
@@ -625,6 +716,8 @@
                 }
 
                 extractor = rtspController.get();
+
+                syncInfoPresent = false;
             } else {
                 extractor = MediaExtractor::Create(dataSource);
                 if (extractor == NULL) {
@@ -674,7 +767,7 @@
         }
 
         if (gWriteMP4) {
-            writeSourceToMP4(mediaSource);
+            writeSourceToMP4(mediaSource, syncInfoPresent);
         } else if (seekTest) {
             performSeekTest(mediaSource);
         } else {
diff --git a/media/mtp/MtpCursor.cpp b/media/mtp/MtpCursor.cpp
index 8c964b4..865a294 100644
--- a/media/mtp/MtpCursor.cpp
+++ b/media/mtp/MtpCursor.cpp
@@ -66,7 +66,8 @@
 #define OBJECT_THUMB                221
 
 MtpCursor::MtpCursor(MtpClient* client, int queryType, int deviceID,
-                int storageID, int objectID, int columnCount, int* columns)
+                MtpStorageID storageID, MtpObjectHandle objectID,
+                int columnCount, int* columns)
         :   mClient(client),
             mQueryType(queryType),
             mDeviceID(deviceID),
@@ -427,7 +428,8 @@
     return true;
 }
 
-bool MtpCursor::putThumbnail(CursorWindow* window, int objectID, int format, int row, int column) {
+bool MtpCursor::putThumbnail(CursorWindow* window, MtpObjectHandle objectID,
+                            MtpObjectFormat format, int row, int column) {
     MtpDevice* device = mClient->getDevice(mDeviceID);
     void* thumbnail;
     int size, offset;
diff --git a/media/mtp/MtpCursor.h b/media/mtp/MtpCursor.h
index 3f84753..9e9833f 100644
--- a/media/mtp/MtpCursor.h
+++ b/media/mtp/MtpCursor.h
@@ -36,17 +36,18 @@
         OBJECT_CHILDREN     = 8,
     };
 
-    MtpClient*  mClient;
-    int         mQueryType;
-    int         mDeviceID;
-    int         mStorageID;
-    int         mQbjectID;
-    int         mColumnCount;
-    int*        mColumns;
+    MtpClient*      mClient;
+    int             mQueryType;
+    int             mDeviceID;
+    MtpStorageID    mStorageID;
+    MtpObjectHandle mQbjectID;
+    int             mColumnCount;
+    int*            mColumns;
 
 public:
                 MtpCursor(MtpClient* client, int queryType, int deviceID,
-                        int storageID, int objectID, int columnCount, int* columns);
+                        MtpStorageID storageID, MtpObjectHandle objectID,
+                        int columnCount, int* columns);
     virtual     ~MtpCursor();
 
     int         fillWindow(CursorWindow* window, int startPos);
@@ -68,7 +69,8 @@
     bool        prepareRow(CursorWindow* window);
     bool        putLong(CursorWindow* window, int value, int row, int column);
     bool        putString(CursorWindow* window, const char* text, int row, int column);
-    bool        putThumbnail(CursorWindow* window, int objectID, int format, int row, int column);
+    bool        putThumbnail(CursorWindow* window, MtpObjectHandle objectID,
+                            MtpObjectFormat format, int row, int column);
 };
 
 }; // namespace android
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 6332b4e..84a3e2c 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -26,6 +26,8 @@
 
 #include <cutils/properties.h>
 
+#define LOG_TAG "MtpServer"
+
 #include "MtpDebug.h"
 #include "MtpDatabase.h"
 #include "MtpProperty.h"
@@ -68,8 +70,8 @@
 //    MTP_OPERATION_INITIATE_OPEN_CAPTURE,
     MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
     MTP_OPERATION_GET_OBJECT_PROP_DESC,
-//    MTP_OPERATION_GET_OBJECT_PROP_VALUE,
-//    MTP_OPERATION_SET_OBJECT_PROP_VALUE,
+    MTP_OPERATION_GET_OBJECT_PROP_VALUE,
+    MTP_OPERATION_SET_OBJECT_PROP_VALUE,
     MTP_OPERATION_GET_OBJECT_REFERENCES,
     MTP_OPERATION_SET_OBJECT_REFERENCES,
 //    MTP_OPERATION_SKIP,
@@ -294,6 +296,7 @@
             response = doGetDevicePropDesc();
             break;
         default:
+            LOGE("got unsupported command %s", MtpDebug::getOperationCodeName(operation));
             response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
             break;
     }
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 56de765..8a732ed 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -4653,29 +4653,44 @@
         goto Exit;
     }
 
+    // check audio settings permission for global effects
+    if (sessionId == AudioSystem::SESSION_OUTPUT_MIX && !settingsAllowed()) {
+        lStatus = PERMISSION_DENIED;
+        goto Exit;
+    }
+
+    // Session AudioSystem::SESSION_OUTPUT_STAGE is reserved for output stage effects
+    // that can only be created by audio policy manager (running in same process)
+    if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE && getpid() != pid) {
+        lStatus = PERMISSION_DENIED;
+        goto Exit;
+    }
+
+    // check recording permission for visualizer
+    if ((memcmp(&pDesc->type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0 ||
+         memcmp(&pDesc->uuid, &VISUALIZATION_UUID_, sizeof(effect_uuid_t)) == 0) &&
+        !recordingAllowed()) {
+        lStatus = PERMISSION_DENIED;
+        goto Exit;
+    }
+
+    if (output == 0) {
+        if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE) {
+            // output must be specified by AudioPolicyManager when using session
+            // AudioSystem::SESSION_OUTPUT_STAGE
+            lStatus = BAD_VALUE;
+            goto Exit;
+        } else if (sessionId == AudioSystem::SESSION_OUTPUT_MIX) {
+            // if the output returned by getOutputForEffect() is removed before we lock the
+            // mutex below, the call to checkPlaybackThread_l(output) below will detect it
+            // and we will exit safely
+            output = AudioSystem::getOutputForEffect(&desc);
+        }
+    }
+
     {
         Mutex::Autolock _l(mLock);
 
-        // check audio settings permission for global effects
-        if (sessionId == AudioSystem::SESSION_OUTPUT_MIX && !settingsAllowed()) {
-            lStatus = PERMISSION_DENIED;
-            goto Exit;
-        }
-
-        // Session AudioSystem::SESSION_OUTPUT_STAGE is reserved for output stage effects
-        // that can only be created by audio policy manager (running in same process)
-        if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE && getpid() != pid) {
-            lStatus = PERMISSION_DENIED;
-            goto Exit;
-        }
-
-        // check recording permission for visualizer
-        if ((memcmp(&pDesc->type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0 ||
-             memcmp(&pDesc->uuid, &VISUALIZATION_UUID_, sizeof(effect_uuid_t)) == 0) &&
-            !recordingAllowed()) {
-            lStatus = PERMISSION_DENIED;
-            goto Exit;
-        }
 
         if (!EffectIsNullUuid(&pDesc->uuid)) {
             // if uuid is specified, request effect descriptor
@@ -4744,32 +4759,24 @@
 
         // If output is not specified try to find a matching audio session ID in one of the
         // output threads.
-        // TODO: allow attachment of effect to inputs
+        // If output is 0 here, sessionId is neither SESSION_OUTPUT_STAGE nor SESSION_OUTPUT_MIX
+        // because of code checking output when entering the function.
         if (output == 0) {
-            if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE) {
-                // output must be specified by AudioPolicyManager when using session
-                // AudioSystem::SESSION_OUTPUT_STAGE
-                lStatus = BAD_VALUE;
-                goto Exit;
-            } else if (sessionId == AudioSystem::SESSION_OUTPUT_MIX) {
-                output = AudioSystem::getOutputForEffect(&desc);
-                LOGV("createEffect() got output %d for effect %s", output, desc.name);
-            } else {
-                 // look for the thread where the specified audio session is present
-                for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
-                    if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
-                        output = mPlaybackThreads.keyAt(i);
-                        break;
-                    }
-                }
-                // If no output thread contains the requested session ID, default to
-                // first output. The effect chain will be moved to the correct output
-                // thread when a track with the same session ID is created
-                if (output == 0 && mPlaybackThreads.size()) {
-                    output = mPlaybackThreads.keyAt(0);
+             // look for the thread where the specified audio session is present
+            for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+                if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
+                    output = mPlaybackThreads.keyAt(i);
+                    break;
                 }
             }
+            // If no output thread contains the requested session ID, default to
+            // first output. The effect chain will be moved to the correct output
+            // thread when a track with the same session ID is created
+            if (output == 0 && mPlaybackThreads.size()) {
+                output = mPlaybackThreads.keyAt(0);
+            }
         }
+        LOGV("createEffect() got output %d for effect %s", output, desc.name);
         PlaybackThread *thread = checkPlaybackThread_l(output);
         if (thread == NULL) {
             LOGE("createEffect() unknown output thread");
@@ -4777,6 +4784,8 @@
             goto Exit;
         }
 
+        // TODO: allow attachment of effect to inputs
+
         wclient = mClients.valueFor(pid);
 
         if (wclient != NULL) {