Merge "Fix error recovery in Stagefright init."
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 178032d..1b13dd9 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -8,7 +8,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	libstagefright libmedia libutils libbinder libstagefright_foundation \
-        libskia
+        libskia libsurfaceflinger_client libgui
 
 LOCAL_C_INCLUDES:= \
 	$(JNI_H_INCLUDE) \
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index a43b190..a875c3a 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -55,6 +55,11 @@
 
 #include <fcntl.h>
 
+#include <gui/SurfaceTextureClient.h>
+
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+
 using namespace android;
 
 static long gNumRepetitions;
@@ -66,6 +71,10 @@
 static bool gDisplayHistogram;
 static String8 gWriteMP4Filename;
 
+static sp<ANativeWindow> gSurface;
+
+#define USE_SURFACE_COMPOSER 0
+
 static int64_t getNowUs() {
     struct timeval tv;
     gettimeofday(&tv, NULL);
@@ -138,7 +147,8 @@
         rawSource = OMXCodec::Create(
             client->interface(), meta, false /* createEncoder */, source,
             NULL /* matchComponentName */,
-            gPreferSoftwareCodec ? OMXCodec::kPreferSoftwareCodecs : 0);
+            gPreferSoftwareCodec ? OMXCodec::kPreferSoftwareCodecs : 0,
+            gSurface);
 
         if (rawSource == NULL) {
             fprintf(stderr, "Failed to instantiate decoder for '%s'.\n", mime);
@@ -540,6 +550,7 @@
     fprintf(stderr, "       -k seek test\n");
     fprintf(stderr, "       -x display a histogram of decoding times/fps "
                     "(video only)\n");
+    fprintf(stderr, "       -S allocate buffers from a surface\n");
 }
 
 int main(int argc, char **argv) {
@@ -550,6 +561,7 @@
     bool dumpProfiles = false;
     bool extractThumbnail = false;
     bool seekTest = false;
+    bool useSurfaceAlloc = false;
     gNumRepetitions = 1;
     gMaxNumFrames = 0;
     gReproduceBug = -1;
@@ -563,7 +575,7 @@
     sp<LiveSession> liveSession;
 
     int res;
-    while ((res = getopt(argc, argv, "han:lm:b:ptsow:kx")) >= 0) {
+    while ((res = getopt(argc, argv, "han:lm:b:ptsow:kxS")) >= 0) {
         switch (res) {
             case 'a':
             {
@@ -642,6 +654,12 @@
                 break;
             }
 
+            case 'S':
+            {
+                useSurfaceAlloc = true;
+                break;
+            }
+
             case '?':
             case 'h':
             default:
@@ -780,6 +798,39 @@
         }
     }
 
+    sp<SurfaceComposerClient> composerClient;
+    sp<SurfaceControl> control;
+
+    if (useSurfaceAlloc && !audioOnly) {
+#if USE_SURFACE_COMPOSER
+        composerClient = new SurfaceComposerClient;
+        CHECK_EQ(composerClient->initCheck(), (status_t)OK);
+
+        control = composerClient->createSurface(
+                getpid(),
+                String8("A Surface"),
+                0,
+                1280,
+                800,
+                PIXEL_FORMAT_RGB_565,
+                0);
+
+        CHECK(control != NULL);
+        CHECK(control->isValid());
+
+        CHECK_EQ(composerClient->openTransaction(), (status_t)OK);
+        CHECK_EQ(control->setLayer(30000), (status_t)OK);
+        CHECK_EQ(control->show(), (status_t)OK);
+        CHECK_EQ(composerClient->closeTransaction(), (status_t)OK);
+
+        gSurface = control->getSurface();
+        CHECK(gSurface != NULL);
+#else
+        sp<SurfaceTexture> texture = new SurfaceTexture(0 /* tex */);
+        gSurface = new SurfaceTextureClient(texture);
+#endif
+    }
+
     DataSource::RegisterDefaultSniffers();
 
     OMXClient client;
@@ -957,6 +1008,14 @@
         }
     }
 
+    if (useSurfaceAlloc && !audioOnly) {
+        gSurface.clear();
+
+#if USE_SURFACE_COMPOSER
+        composerClient->dispose();
+#endif
+    }
+
     client.disconnect();
 
     return 0;
diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp
index 647cf43..2809df5 100644
--- a/media/libstagefright/DRMExtractor.cpp
+++ b/media/libstagefright/DRMExtractor.cpp
@@ -243,6 +243,7 @@
       mDrmManagerClient(NULL) {
     mOriginalExtractor = MediaExtractor::Create(source, mime);
     mOriginalExtractor->setDrmFlag(true);
+    mOriginalExtractor->getMetaData()->setInt32(kKeyIsDRM, 1);
 
     source->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
 }
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index d4651c4..23bad5b 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -67,6 +67,7 @@
              mime, confidence);
     }
 
+    bool isDrm = false;
     // DRM MIME type syntax is "drm+type+original" where
     // type is "es_based" or "container_based" and
     // original is the content's cleartext MIME type
@@ -78,39 +79,45 @@
         }
         ++originalMime;
         if (!strncmp(mime, "drm+es_based+", 13)) {
+            // DRMExtractor sets container metadata kKeyIsDRM to 1
             return new DRMExtractor(source, originalMime);
         } else if (!strncmp(mime, "drm+container_based+", 20)) {
             mime = originalMime;
+            isDrm = true;
         } else {
             return NULL;
         }
     }
 
+    MediaExtractor *ret = NULL;
     if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
             || !strcasecmp(mime, "audio/mp4")) {
-        return new MPEG4Extractor(source);
+        ret = new MPEG4Extractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
-        return new MP3Extractor(source, meta);
+        ret = new MP3Extractor(source, meta);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
             || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
-        return new AMRExtractor(source);
+        ret = new AMRExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) {
-        return new FLACExtractor(source);
+        ret = new FLACExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {
-        return new WAVExtractor(source);
+        ret = new WAVExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {
-        return new OggExtractor(source);
+        ret = new OggExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {
-        return new MatroskaExtractor(source);
+        ret = new MatroskaExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
-        return new MPEG2TSExtractor(source);
+        ret = new MPEG2TSExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM)) {
-        return new WVMExtractor(source);
+        ret = new WVMExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
-        return new AACExtractor(source);
+        ret = new AACExtractor(source);
+    }
+    if (ret != NULL && isDrm) {
+        ret->getMetaData()->setInt32(kKeyIsDRM, 1);
     }
 
-    return NULL;
+    return ret;
 }
 
 }  // namespace android
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 600de7c..ea3b801 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -272,6 +272,12 @@
         return NULL;
     }
 
+    int32_t drm = 0;
+    if (mExtractor->getMetaData()->findInt32(kKeyIsDRM, &drm) && drm != 0) {
+        LOGE("frame grab not allowed.");
+        return NULL;
+    }
+
     size_t n = mExtractor->countTracks();
     size_t i;
     for (i = 0; i < n; ++i) {
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index d518c97..3b92e5d 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -187,7 +187,7 @@
 
 status_t ColorConverter::convertYUV420Planar(
         const BitmapParams &src, const BitmapParams &dst) {
-    if (!((dst.mWidth & 3) == 0
+    if (!((dst.mWidth & 1) == 0
             && (src.mCropLeft & 1) == 0
             && src.cropWidth() == dst.cropWidth()
             && src.cropHeight() == dst.cropHeight())) {
diff --git a/services/audioflinger/AudioPolicyManagerBase.cpp b/services/audioflinger/AudioPolicyManagerBase.cpp
index 3082d45..bfc80db 100644
--- a/services/audioflinger/AudioPolicyManagerBase.cpp
+++ b/services/audioflinger/AudioPolicyManagerBase.cpp
@@ -1889,7 +1889,15 @@
         mStreams[i].mVolDbAtt[StreamDescriptor::VOLMAX] = 0.0f;
     }
 
-    // TODO add modifications for music to have finer steps below knee1 and above knee2
+    // Modification for music: more attenuation for lower volumes, finer steps at high volumes
+    mStreams[AudioSystem::MUSIC].mVolIndex[StreamDescriptor::VOLMIN] = 1;
+    mStreams[AudioSystem::MUSIC].mVolDbAtt[StreamDescriptor::VOLMIN] = -58.0f;
+    mStreams[AudioSystem::MUSIC].mVolIndex[StreamDescriptor::VOLKNEE1] = 20;
+    mStreams[AudioSystem::MUSIC].mVolDbAtt[StreamDescriptor::VOLKNEE1] = -40.0f;
+    mStreams[AudioSystem::MUSIC].mVolIndex[StreamDescriptor::VOLKNEE2] = 60;
+    mStreams[AudioSystem::MUSIC].mVolDbAtt[StreamDescriptor::VOLKNEE2] = -17.0f;
+    mStreams[AudioSystem::MUSIC].mVolIndex[StreamDescriptor::VOLMAX] = 100;
+    mStreams[AudioSystem::MUSIC].mVolDbAtt[StreamDescriptor::VOLMAX] = 0.0f;
 }
 
 float AudioPolicyManagerBase::computeVolume(int stream, int index, audio_io_handle_t output, uint32_t device)