Merge "Update camera continuous autofocus javadoc." into ics-mr0
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index e98d55c..08835fb 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -209,7 +209,6 @@
status_t prepareAsync_l();
status_t getDuration_l(int *msec);
status_t attachNewPlayer(const sp<IMediaPlayer>& player);
- void disconnectNativeWindow();
status_t reset_l();
sp<IMediaPlayer> mPlayer;
@@ -233,8 +232,6 @@
int mVideoHeight;
int mAudioSessionId;
float mSendLevel;
- sp<ANativeWindow> mConnectedWindow;
- sp<IBinder> mConnectedWindowBinder;
};
}; // namespace android
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 0d5a726..c21d19d 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -277,6 +277,7 @@
status_t queueBufferToNativeWindow(BufferInfo *info);
status_t cancelBufferToNativeWindow(BufferInfo *info);
BufferInfo* dequeueBufferFromNativeWindow();
+ status_t pushBlankBuffersToNativeWindow();
status_t freeBuffersOnPort(
OMX_U32 portIndex, bool onlyThoseWeOwn = false);
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 37a82e9..f72300b 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -86,8 +86,6 @@
if (p != 0) {
p->disconnect();
}
-
- disconnectNativeWindow();
}
// always call with lock held
@@ -221,63 +219,12 @@
return mPlayer->getMetadata(update_only, apply_filter, metadata);
}
-void MediaPlayer::disconnectNativeWindow() {
- if (mConnectedWindow != NULL) {
- status_t err = native_window_api_disconnect(mConnectedWindow.get(),
- NATIVE_WINDOW_API_MEDIA);
-
- if (err != OK) {
- LOGW("native_window_api_disconnect returned an error: %s (%d)",
- strerror(-err), err);
- }
- }
- mConnectedWindow.clear();
-}
-
status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
{
LOGV("setVideoSurface");
Mutex::Autolock _l(mLock);
if (mPlayer == 0) return NO_INIT;
-
- sp<IBinder> binder(surface == NULL ? NULL : surface->asBinder());
- if (mConnectedWindowBinder == binder) {
- return OK;
- }
-
- if (surface != NULL) {
- status_t err = native_window_api_connect(surface.get(),
- NATIVE_WINDOW_API_MEDIA);
-
- if (err != OK) {
- LOGE("setVideoSurface failed: %d", err);
- // Note that we must do the reset before disconnecting from the ANW.
- // Otherwise queue/dequeue calls could be made on the disconnected
- // ANW, which may result in errors.
- reset_l();
-
- disconnectNativeWindow();
-
- return err;
- }
- }
-
- // Note that we must set the player's new surface before disconnecting the
- // old one. Otherwise queue/dequeue calls could be made on the disconnected
- // ANW, which may result in errors.
- status_t err = mPlayer->setVideoSurface(surface);
-
- disconnectNativeWindow();
-
- mConnectedWindow = surface;
-
- if (err == OK) {
- mConnectedWindowBinder = binder;
- } else {
- disconnectNativeWindow();
- }
-
- return err;
+ return mPlayer->setVideoSurface(surface);
}
status_t MediaPlayer::setVideoSurfaceTexture(
@@ -286,48 +233,7 @@
LOGV("setVideoSurfaceTexture");
Mutex::Autolock _l(mLock);
if (mPlayer == 0) return NO_INIT;
-
- sp<IBinder> binder(surfaceTexture == NULL ? NULL :
- surfaceTexture->asBinder());
- if (mConnectedWindowBinder == binder) {
- return OK;
- }
-
- sp<ANativeWindow> anw;
- if (surfaceTexture != NULL) {
- anw = new SurfaceTextureClient(surfaceTexture);
- status_t err = native_window_api_connect(anw.get(),
- NATIVE_WINDOW_API_MEDIA);
-
- if (err != OK) {
- LOGE("setVideoSurfaceTexture failed: %d", err);
- // Note that we must do the reset before disconnecting from the ANW.
- // Otherwise queue/dequeue calls could be made on the disconnected
- // ANW, which may result in errors.
- reset_l();
-
- disconnectNativeWindow();
-
- return err;
- }
- }
-
- // Note that we must set the player's new SurfaceTexture before
- // disconnecting the old one. Otherwise queue/dequeue calls could be made
- // on the disconnected ANW, which may result in errors.
- status_t err = mPlayer->setVideoSurfaceTexture(surfaceTexture);
-
- disconnectNativeWindow();
-
- mConnectedWindow = anw;
-
- if (err == OK) {
- mConnectedWindowBinder = binder;
- } else {
- disconnectNativeWindow();
- }
-
- return err;
+ return mPlayer->setVideoSurfaceTexture(surfaceTexture);
}
// must call with lock held
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 3ebe989..ba9f54f 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -40,6 +40,7 @@
#include <binder/IServiceManager.h>
#include <binder/MemoryHeapBase.h>
#include <binder/MemoryBase.h>
+#include <gui/SurfaceTextureClient.h>
#include <utils/Errors.h> // for status_t
#include <utils/String8.h>
#include <utils/SystemClock.h>
@@ -528,6 +529,8 @@
p->reset();
}
+ disconnectNativeWindow();
+
IPCThreadState::self()->flushCommands();
}
@@ -789,13 +792,67 @@
return p->setVideoSurface(surface);
}
+void MediaPlayerService::Client::disconnectNativeWindow() {
+ if (mConnectedWindow != NULL) {
+ status_t err = native_window_api_disconnect(mConnectedWindow.get(),
+ NATIVE_WINDOW_API_MEDIA);
+
+ if (err != OK) {
+ LOGW("native_window_api_disconnect returned an error: %s (%d)",
+ strerror(-err), err);
+ }
+ }
+ mConnectedWindow.clear();
+}
+
status_t MediaPlayerService::Client::setVideoSurfaceTexture(
const sp<ISurfaceTexture>& surfaceTexture)
{
LOGV("[%d] setVideoSurfaceTexture(%p)", mConnId, surfaceTexture.get());
sp<MediaPlayerBase> p = getPlayer();
if (p == 0) return UNKNOWN_ERROR;
- return p->setVideoSurfaceTexture(surfaceTexture);
+
+ sp<IBinder> binder(surfaceTexture == NULL ? NULL :
+ surfaceTexture->asBinder());
+ if (mConnectedWindowBinder == binder) {
+ return OK;
+ }
+
+ sp<ANativeWindow> anw;
+ if (surfaceTexture != NULL) {
+ anw = new SurfaceTextureClient(surfaceTexture);
+ status_t err = native_window_api_connect(anw.get(),
+ NATIVE_WINDOW_API_MEDIA);
+
+ if (err != OK) {
+ LOGE("setVideoSurfaceTexture failed: %d", err);
+ // Note that we must do the reset before disconnecting from the ANW.
+ // Otherwise queue/dequeue calls could be made on the disconnected
+ // ANW, which may result in errors.
+ reset();
+
+ disconnectNativeWindow();
+
+ return err;
+ }
+ }
+
+ // Note that we must set the player's new SurfaceTexture before
+ // disconnecting the old one. Otherwise queue/dequeue calls could be made
+ // on the disconnected ANW, which may result in errors.
+ status_t err = p->setVideoSurfaceTexture(surfaceTexture);
+
+ disconnectNativeWindow();
+
+ mConnectedWindow = anw;
+
+ if (err == OK) {
+ mConnectedWindowBinder = binder;
+ } else {
+ disconnectNativeWindow();
+ }
+
+ return err;
}
status_t MediaPlayerService::Client::invoke(const Parcel& request,
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 53e625a..62214ba 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -318,6 +318,9 @@
// @param type Of the metadata to be recorded.
void addNewMetadataUpdate(media::Metadata::Type type);
+ // Disconnect from the currently connected ANativeWindow.
+ void disconnectNativeWindow();
+
mutable Mutex mLock;
sp<MediaPlayerBase> mPlayer;
sp<MediaPlayerService> mService;
@@ -329,6 +332,8 @@
int32_t mConnId;
int mAudioSessionId;
uid_t mUID;
+ sp<ANativeWindow> mConnectedWindow;
+ sp<IBinder> mConnectedWindowBinder;
// Metadata filters.
media::Metadata::Filter mMetadataAllow; // protected by mLock
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 00d414c..b20bfcb 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -2001,6 +2001,157 @@
return bufInfo;
}
+status_t OMXCodec::pushBlankBuffersToNativeWindow() {
+ status_t err = NO_ERROR;
+ ANativeWindowBuffer* anb = NULL;
+ int numBufs = 0;
+ int minUndequeuedBufs = 0;
+
+ // We need to reconnect to the ANativeWindow as a CPU client to ensure that
+ // no frames get dropped by SurfaceFlinger assuming that these are video
+ // frames.
+ err = native_window_api_disconnect(mNativeWindow.get(),
+ NATIVE_WINDOW_API_MEDIA);
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: api_disconnect failed: %s (%d)",
+ strerror(-err), -err);
+ return err;
+ }
+
+ err = native_window_api_connect(mNativeWindow.get(),
+ NATIVE_WINDOW_API_CPU);
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: api_connect failed: %s (%d)",
+ strerror(-err), -err);
+ return err;
+ }
+
+ err = native_window_set_scaling_mode(mNativeWindow.get(),
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: set_buffers_geometry failed: %s (%d)",
+ strerror(-err), -err);
+ goto error;
+ }
+
+ err = native_window_set_buffers_geometry(mNativeWindow.get(), 1, 1,
+ HAL_PIXEL_FORMAT_RGBX_8888);
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: set_buffers_geometry failed: %s (%d)",
+ strerror(-err), -err);
+ goto error;
+ }
+
+ err = native_window_set_usage(mNativeWindow.get(),
+ GRALLOC_USAGE_SW_WRITE_OFTEN);
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: set_usage failed: %s (%d)",
+ strerror(-err), -err);
+ goto error;
+ }
+
+ err = mNativeWindow->query(mNativeWindow.get(),
+ NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query "
+ "failed: %s (%d)", strerror(-err), -err);
+ goto error;
+ }
+
+ numBufs = minUndequeuedBufs + 1;
+ err = native_window_set_buffer_count(mNativeWindow.get(), numBufs);
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: set_buffer_count failed: %s (%d)",
+ strerror(-err), -err);
+ goto error;
+ }
+
+ // We push numBufs + 1 buffers to ensure that we've drawn into the same
+ // buffer twice. This should guarantee that the buffer has been displayed
+ // on the screen and then been replaced, so an previous video frames are
+ // guaranteed NOT to be currently displayed.
+ for (int i = 0; i < numBufs + 1; i++) {
+ err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &anb);
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)",
+ strerror(-err), -err);
+ goto error;
+ }
+
+ sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+ err = mNativeWindow->lockBuffer(mNativeWindow.get(),
+ buf->getNativeBuffer());
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: lockBuffer failed: %s (%d)",
+ strerror(-err), -err);
+ goto error;
+ }
+
+ // Fill the buffer with the a 1x1 checkerboard pattern ;)
+ uint32_t* img = NULL;
+ err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: lock failed: %s (%d)",
+ strerror(-err), -err);
+ goto error;
+ }
+
+ *img = 0;
+
+ err = buf->unlock();
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: unlock failed: %s (%d)",
+ strerror(-err), -err);
+ goto error;
+ }
+
+ err = mNativeWindow->queueBuffer(mNativeWindow.get(),
+ buf->getNativeBuffer());
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: queueBuffer failed: %s (%d)",
+ strerror(-err), -err);
+ goto error;
+ }
+
+ anb = NULL;
+ }
+
+error:
+
+ if (err != NO_ERROR) {
+ // Clean up after an error.
+ if (anb != NULL) {
+ mNativeWindow->cancelBuffer(mNativeWindow.get(), anb);
+ }
+
+ native_window_api_disconnect(mNativeWindow.get(),
+ NATIVE_WINDOW_API_CPU);
+ native_window_api_connect(mNativeWindow.get(),
+ NATIVE_WINDOW_API_MEDIA);
+
+ return err;
+ } else {
+ // Clean up after success.
+ err = native_window_api_disconnect(mNativeWindow.get(),
+ NATIVE_WINDOW_API_CPU);
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: api_disconnect failed: %s (%d)",
+ strerror(-err), -err);
+ return err;
+ }
+
+ err = native_window_api_connect(mNativeWindow.get(),
+ NATIVE_WINDOW_API_MEDIA);
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: api_connect failed: %s (%d)",
+ strerror(-err), -err);
+ return err;
+ }
+
+ return NO_ERROR;
+ }
+}
+
int64_t OMXCodec::retrieveDecodingTimeUs(bool isCodecSpecific) {
CHECK(mIsEncoder);
@@ -2589,6 +2740,15 @@
mPortStatus[kPortIndexInput] = ENABLED;
mPortStatus[kPortIndexOutput] = ENABLED;
+ if ((mFlags & kEnableGrallocUsageProtected) &&
+ mNativeWindow != NULL) {
+ // We push enough 1x1 blank buffers to ensure that one of
+ // them has made it to the display. This allows the OMX
+ // component teardown to zero out any protected buffers
+ // without the risk of scanning out one of those buffers.
+ pushBlankBuffersToNativeWindow();
+ }
+
setState(IDLE_TO_LOADED);
}
break;