Merge "Camera hal change for 0-memcpy in media recording framework"
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 2bb7783..1d94160 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -33,7 +33,11 @@
                   public MediaBufferObserver {
     enum CreationFlags {
         kPreferSoftwareCodecs    = 1,
-        kIgnoreCodecSpecificData = 2
+        kIgnoreCodecSpecificData = 2,
+
+        // The client wants to access the output buffer's video
+        // data for example for thumbnail extraction.
+        kClientNeedsFramebuffer  = 4,
     };
     static sp<MediaSource> Create(
             const sp<IOMX> &omx,
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index a0b7f70..ad6cb5b 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1079,6 +1079,32 @@
     return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
 }
 
+void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
+    if (!mSeeking) {
+        return;
+    }
+
+    if (mAudioPlayer != NULL) {
+        LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
+
+        // If we don't have a video time, seek audio to the originally
+        // requested seek time instead.
+
+        mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs);
+        mAudioPlayer->resume();
+        mWatchForAudioSeekComplete = true;
+        mWatchForAudioEOS = true;
+    } else if (!mSeekNotificationSent) {
+        // If we're playing video only, report seek complete now,
+        // otherwise audio player will notify us later.
+        notifyListener_l(MEDIA_SEEK_COMPLETE);
+    }
+
+    mFlags |= FIRST_FRAME;
+    mSeeking = false;
+    mSeekNotificationSent = false;
+}
+
 void AwesomePlayer::onVideoEvent() {
     Mutex::Autolock autoLock(mLock);
     if (!mVideoEventPending) {
@@ -1142,6 +1168,14 @@
                     continue;
                 }
 
+                // So video playback is complete, but we may still have
+                // a seek request pending that needs to be applied
+                // to the audio track.
+                if (mSeeking) {
+                    LOGV("video stream ended while seeking!");
+                }
+                finishSeekIfNecessary(-1);
+
                 mFlags |= VIDEO_AT_EOS;
                 postStreamDoneEvent_l(err);
                 return;
@@ -1168,24 +1202,7 @@
         mVideoTimeUs = timeUs;
     }
 
-    if (mSeeking) {
-        if (mAudioPlayer != NULL) {
-            LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
-
-            mAudioPlayer->seekTo(timeUs);
-            mAudioPlayer->resume();
-            mWatchForAudioSeekComplete = true;
-            mWatchForAudioEOS = true;
-        } else if (!mSeekNotificationSent) {
-            // If we're playing video only, report seek complete now,
-            // otherwise audio player will notify us later.
-            notifyListener_l(MEDIA_SEEK_COMPLETE);
-        }
-
-        mFlags |= FIRST_FRAME;
-        mSeeking = false;
-        mSeekNotificationSent = false;
-    }
+    finishSeekIfNecessary(timeUs);
 
     TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
 
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
index b3daf67..81a2b0d 100644
--- a/media/libstagefright/MPEG2TSWriter.cpp
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -725,6 +725,14 @@
 
     size_t PES_packet_length = accessUnit->size() + 8;
 
+    if (PES_packet_length >= 65536) {
+        // This really should only happen for video.
+        CHECK_EQ(stream_id, 0xe0u);
+
+        // It's valid to set this to 0 for video according to the specs.
+        PES_packet_length = 0;
+    }
+
     uint8_t *ptr = buffer->data();
     *ptr++ = 0x47;
     *ptr++ = 0x40 | (PID >> 8);
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 5e70888..4be1b38 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -510,12 +510,29 @@
 
         LOGV("Attempting to allocate OMX node '%s'", componentName);
 
+        uint32_t quirks = getComponentQuirks(componentName, createEncoder);
+
+        if (!createEncoder
+                && (quirks & kOutputBuffersAreUnreadable)
+                && (flags & kClientNeedsFramebuffer)) {
+            if (strncmp(componentName, "OMX.SEC.", 8)) {
+                // For OMX.SEC.* decoders we can enable a special mode that
+                // gives the client access to the framebuffer contents.
+
+                LOGW("Component '%s' does not give the client access to "
+                     "the framebuffer contents. Skipping.",
+                     componentName);
+
+                continue;
+            }
+        }
+
         status_t err = omx->allocateNode(componentName, observer, &node);
         if (err == OK) {
             LOGV("Successfully allocated OMX node '%s'", componentName);
 
             sp<OMXCodec> codec = new OMXCodec(
-                    omx, node, getComponentQuirks(componentName, createEncoder),
+                    omx, node, quirks,
                     createEncoder, mime, componentName,
                     source);
 
@@ -698,6 +715,33 @@
 
     initOutputFormat(meta);
 
+    if ((flags & kClientNeedsFramebuffer)
+            && !strncmp(mComponentName, "OMX.SEC.", 8)) {
+        OMX_INDEXTYPE index;
+
+        status_t err =
+            mOMX->getExtensionIndex(
+                    mNode,
+                    "OMX.SEC.index.ThumbnailMode",
+                    &index);
+
+        if (err != OK) {
+            return err;
+        }
+
+        OMX_BOOL enable = OMX_TRUE;
+        err = mOMX->setConfig(mNode, index, &enable, sizeof(enable));
+
+        if (err != OK) {
+            CODEC_LOGE("setConfig('OMX.SEC.index.ThumbnailMode') "
+                       "returned error 0x%08x", err);
+
+            return err;
+        }
+
+        mQuirks &= ~kOutputBuffersAreUnreadable;
+    }
+
     return OK;
 }
 
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index af9c70c..a800a93 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -112,7 +112,7 @@
     sp<MediaSource> decoder =
         OMXCodec::Create(
                 client->interface(), source->getFormat(), false, source,
-                NULL, flags);
+                NULL, flags | OMXCodec::kClientNeedsFramebuffer);
 
     if (decoder.get() == NULL) {
         LOGV("unable to instantiate video decoder.");
diff --git a/media/libstagefright/foundation/ALooperRoster.cpp b/media/libstagefright/foundation/ALooperRoster.cpp
index 7683113..8aa1b15 100644
--- a/media/libstagefright/foundation/ALooperRoster.cpp
+++ b/media/libstagefright/foundation/ALooperRoster.cpp
@@ -54,7 +54,10 @@
     Mutex::Autolock autoLock(mLock);
 
     ssize_t index = mHandlers.indexOfKey(handlerID);
-    CHECK_GE(index, 0);
+
+    if (index < 0) {
+        return;
+    }
 
     const HandlerInfo &info = mHandlers.valueAt(index);
 
@@ -84,7 +87,8 @@
 
     if (looper == NULL) {
         LOGW("failed to post message. "
-             "Target handler still registered, but object gone.");
+             "Target handler %d still registered, but object gone.",
+             msg->target());
 
         mHandlers.removeItemsAt(index);
         return;
@@ -111,7 +115,8 @@
 
         if (handler == NULL) {
             LOGW("failed to deliver message. "
-                 "Target handler registered, but object gone.");
+                 "Target handler %d registered, but object gone.",
+                 msg->target());
 
             mHandlers.removeItemsAt(index);
             return;
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 5a1d7e7..0837be8 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -261,6 +261,8 @@
 
     bool getBitrate(int64_t *bitrate);
 
+    void finishSeekIfNecessary(int64_t videoTimeUs);
+
     AwesomePlayer(const AwesomePlayer &);
     AwesomePlayer &operator=(const AwesomePlayer &);
 };