summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/MediaCodec.cpp
diff options
context:
space:
mode:
authorLajos Molnar <lajos@google.com>2015-04-30 13:59:10 -0700
committerLajos Molnar <lajos@google.com>2015-05-01 18:45:35 -0700
commit1dcdfead2971c1fa7c02f24ba86f706890c9f99e (patch)
treee07226a98400e308d1a82499fbdb76757603937c /media/libstagefright/MediaCodec.cpp
parent64da6f045b1a1d1b8f01391b6e37287f77f85d1e (diff)
downloadframeworks_av-1dcdfead2971c1fa7c02f24ba86f706890c9f99e.zip
frameworks_av-1dcdfead2971c1fa7c02f24ba86f706890c9f99e.tar.gz
frameworks_av-1dcdfead2971c1fa7c02f24ba86f706890c9f99e.tar.bz2
stagefright: add support for dynamically setting MediaCodec output surface
Bug: 11990461 Change-Id: I2aee89ef504234dc66eb5fcf6e62e1706088f758
Diffstat (limited to 'media/libstagefright/MediaCodec.cpp')
-rw-r--r--media/libstagefright/MediaCodec.cpp115
1 files changed, 93 insertions, 22 deletions
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 9906a10..cf69418 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -523,6 +523,14 @@ status_t MediaCodec::configure(
return err;
}
+status_t MediaCodec::setSurface(const sp<Surface> &surface) {
+ sp<AMessage> msg = new AMessage(kWhatSetSurface, this);
+ msg->setObject("surface", surface);
+
+ sp<AMessage> response;
+ return PostAndAwaitResponse(msg, &response);
+}
+
status_t MediaCodec::createInputSurface(
sp<IGraphicBufferProducer>* bufferProducer) {
sp<AMessage> msg = new AMessage(kWhatCreateInputSurface, this);
@@ -1216,7 +1224,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
{
// response to initiateCreateInputSurface()
status_t err = NO_ERROR;
- sp<AMessage> response = new AMessage();
+ sp<AMessage> response = new AMessage;
if (!msg->findInt32("err", &err)) {
sp<RefBase> obj;
msg->findObject("input-surface", &obj);
@@ -1233,7 +1241,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
case CodecBase::kWhatSignaledInputEOS:
{
// response to signalEndOfInputStream()
- sp<AMessage> response = new AMessage();
+ sp<AMessage> response = new AMessage;
status_t err;
if (msg->findInt32("err", &err)) {
response->setInt32("err", err);
@@ -1639,6 +1647,61 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
break;
}
+ case kWhatSetSurface:
+ {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ status_t err = OK;
+ sp<Surface> surface;
+
+ switch (mState) {
+ case CONFIGURED:
+ case STARTED:
+ case FLUSHED:
+ {
+ sp<RefBase> obj;
+ (void)msg->findObject("surface", &obj);
+ sp<Surface> surface = static_cast<Surface *>(obj.get());
+ if (mSurface == NULL) {
+ // do not support setting surface if it was not set
+ err = INVALID_OPERATION;
+ } else if (obj == NULL) {
+ // do not support unsetting surface
+ err = BAD_VALUE;
+ } else {
+ err = connectToSurface(surface);
+ if (err == BAD_VALUE) {
+ // assuming reconnecting to same surface
+ // TODO: check if it is the same surface
+ err = OK;
+ } else {
+ if (err == OK) {
+ if (mFlags & kFlagUsesSoftwareRenderer) {
+ mSoftRenderer = new SoftwareRenderer(surface);
+ // TODO: check if this was successful
+ } else {
+ err = mCodec->setSurface(surface);
+ }
+ }
+ if (err == OK) {
+ (void)disconnectFromSurface();
+ mSurface = surface;
+ }
+ }
+ }
+ break;
+ }
+
+ default:
+ err = INVALID_OPERATION;
+ break;
+ }
+
+ PostReplyWithError(replyID, err);
+ break;
+ }
+
case kWhatCreateInputSurface:
{
sp<AReplyToken> replyID;
@@ -2401,36 +2464,44 @@ ssize_t MediaCodec::dequeuePortBuffer(int32_t portIndex) {
return index;
}
-status_t MediaCodec::handleSetSurface(const sp<Surface> &surface) {
- status_t err;
+status_t MediaCodec::connectToSurface(const sp<Surface> &surface) {
+ status_t err = OK;
+ if (surface != NULL) {
+ err = native_window_api_connect(surface.get(), NATIVE_WINDOW_API_MEDIA);
+ if (err == BAD_VALUE) {
+ ALOGI("native window already connected. Assuming no change of surface");
+ } else if (err != OK) {
+ ALOGE("native_window_api_connect returned an error: %s (%d)", strerror(-err), err);
+ }
+ }
+ return err;
+}
+status_t MediaCodec::disconnectFromSurface() {
+ status_t err = OK;
if (mSurface != NULL) {
- err = native_window_api_disconnect(
- mSurface.get(), NATIVE_WINDOW_API_MEDIA);
-
+ err = native_window_api_disconnect(mSurface.get(), NATIVE_WINDOW_API_MEDIA);
if (err != OK) {
- ALOGW("native_window_api_disconnect returned an error: %s (%d)",
- strerror(-err), err);
+ ALOGW("native_window_api_disconnect returned an error: %s (%d)", strerror(-err), err);
}
-
+ // assume disconnected even on error
mSurface.clear();
}
+ return err;
+}
+status_t MediaCodec::handleSetSurface(const sp<Surface> &surface) {
+ status_t err = OK;
+ if (mSurface != NULL) {
+ (void)disconnectFromSurface();
+ }
if (surface != NULL) {
- err = native_window_api_connect(
- surface.get(), NATIVE_WINDOW_API_MEDIA);
-
- if (err != OK) {
- ALOGE("native_window_api_connect returned an error: %s (%d)",
- strerror(-err), err);
-
- return err;
+ err = connectToSurface(surface);
+ if (err == OK) {
+ mSurface = surface;
}
-
- mSurface = surface;
}
-
- return OK;
+ return err;
}
void MediaCodec::onInputBufferAvailable() {