diff options
author | Lajos Molnar <lajos@google.com> | 2015-05-02 02:23:06 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-05-02 02:23:07 +0000 |
commit | 8651c6f5069cca40ef805b800a9730617ff7f9b8 (patch) | |
tree | 129d2b9634ed11d920253265e86b171033887b39 | |
parent | e2a2dfcbf0c9d6bb7139263ecf0d8e53b4ca1049 (diff) | |
parent | 1dcdfead2971c1fa7c02f24ba86f706890c9f99e (diff) | |
download | frameworks_av-8651c6f5069cca40ef805b800a9730617ff7f9b8.zip frameworks_av-8651c6f5069cca40ef805b800a9730617ff7f9b8.tar.gz frameworks_av-8651c6f5069cca40ef805b800a9730617ff7f9b8.tar.bz2 |
Merge "stagefright: add support for dynamically setting MediaCodec output surface" into mnc-dev
-rw-r--r-- | include/media/stagefright/ACodec.h | 9 | ||||
-rw-r--r-- | include/media/stagefright/CodecBase.h | 2 | ||||
-rw-r--r-- | include/media/stagefright/MediaCodec.h | 8 | ||||
-rw-r--r-- | media/libstagefright/ACodec.cpp | 326 | ||||
-rw-r--r-- | media/libstagefright/MediaCodec.cpp | 115 |
5 files changed, 338 insertions, 122 deletions
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h index f941512..cdb923d 100644 --- a/include/media/stagefright/ACodec.h +++ b/include/media/stagefright/ACodec.h @@ -49,6 +49,8 @@ struct ACodec : public AHierarchicalStateMachine, public CodecBase { virtual void initiateStart(); virtual void initiateShutdown(bool keepComponentAllocated = false); + virtual status_t setSurface(const sp<Surface> &surface); + virtual void signalFlush(); virtual void signalResume(); @@ -115,6 +117,7 @@ private: kWhatDrainDeferredMessages = 'drai', kWhatAllocateComponent = 'allo', kWhatConfigureComponent = 'conf', + kWhatSetSurface = 'setS', kWhatCreateInputSurface = 'cisf', kWhatUsePersistentInputSurface = 'pisf', kWhatSignalEndOfInputStream = 'eois', @@ -232,6 +235,12 @@ private: status_t freeBuffersOnPort(OMX_U32 portIndex); status_t freeBuffer(OMX_U32 portIndex, size_t i); + status_t handleSetSurface(const sp<Surface> &surface); + status_t setNativeWindowSizeFormatAndUsage( + ANativeWindow *nativeWindow /* nonnull */, + int width, int height, int format, int rotation, int usage); + status_t setupNativeWindowSizeFormatAndUsage(ANativeWindow *nativeWindow /* nonnull */); + status_t configureOutputBuffersFromNativeWindow( OMX_U32 *nBufferCount, OMX_U32 *nBufferSize, OMX_U32 *nMinUndequeuedBuffers); diff --git a/include/media/stagefright/CodecBase.h b/include/media/stagefright/CodecBase.h index ce53eda..51213b6 100644 --- a/include/media/stagefright/CodecBase.h +++ b/include/media/stagefright/CodecBase.h @@ -58,6 +58,8 @@ struct CodecBase : public AHandler { // require an explicit message handler virtual void onMessageReceived(const sp<AMessage> &msg) = 0; + virtual status_t setSurface(const sp<Surface> &surface) { return INVALID_OPERATION; } + virtual void signalFlush() = 0; virtual void signalResume() = 0; diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h index bab1426..f5d523d 100644 --- a/include/media/stagefright/MediaCodec.h +++ b/include/media/stagefright/MediaCodec.h @@ -146,6 +146,8 @@ struct MediaCodec : public AHandler { status_t getOutputFormat(size_t index, sp<AMessage> *format); status_t getInputBuffer(size_t index, sp<ABuffer> *buffer); + status_t setSurface(const sp<Surface> &nativeWindow); + status_t requestIDRFrame(); // Notification will be posted once there "is something to do", i.e. @@ -184,6 +186,7 @@ private: enum { kWhatInit = 'init', kWhatConfigure = 'conf', + kWhatSetSurface = 'sSur', kWhatCreateInputSurface = 'cisf', kWhatUsePersistentInputSurface = 'pisf', kWhatStart = 'strt', @@ -340,8 +343,9 @@ private: void extractCSD(const sp<AMessage> &format); status_t queueCSDInputBuffer(size_t bufferIndex); - status_t handleSetSurface( - const sp<Surface> &surface); + status_t handleSetSurface(const sp<Surface> &surface); + status_t connectToSurface(const sp<Surface> &surface); + status_t disconnectFromSurface(); void postActivityNotificationIfPossible(); diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 5001c16..b7798d2 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -479,6 +479,19 @@ void ACodec::initiateConfigureComponent(const sp<AMessage> &msg) { msg->post(); } +status_t ACodec::setSurface(const sp<Surface> &surface) { + sp<AMessage> msg = new AMessage(kWhatSetSurface, this); + msg->setObject("surface", surface); + + sp<AMessage> response; + status_t err = msg->postAndAwaitResponse(&response); + + if (err == OK) { + (void)response->findInt32("err", &err); + } + return err; +} + void ACodec::initiateCreateInputSurface() { (new AMessage(kWhatCreateInputSurface, this))->post(); } @@ -533,6 +546,114 @@ void ACodec::signalSubmitOutputMetaDataBufferIfEOS_workaround() { } } +status_t ACodec::handleSetSurface(const sp<Surface> &surface) { + // allow keeping unset surface + if (surface == NULL) { + if (mNativeWindow != NULL) { + ALOGW("cannot unset a surface"); + return INVALID_OPERATION; + } + return OK; + } + + // allow keeping unset surface + if (mNativeWindow == NULL) { + ALOGW("component was not configured with a surface"); + return INVALID_OPERATION; + } + + ANativeWindow *nativeWindow = surface.get(); + // if we have not yet started the codec, we can simply set the native window + if (mBuffers[kPortIndexInput].size() == 0) { + mNativeWindow = surface; + return OK; + } + + // we do not support changing a tunneled surface after start + if (mTunneled) { + ALOGW("cannot change tunneled surface"); + return INVALID_OPERATION; + } + + status_t err = setupNativeWindowSizeFormatAndUsage(nativeWindow); + if (err != OK) { + return err; + } + + // get min undequeued count. We cannot switch to a surface that has a higher + // undequeued count than we allocated. + int minUndequeuedBuffers = 0; + err = nativeWindow->query( + nativeWindow, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, + &minUndequeuedBuffers); + if (err != 0) { + ALOGE("NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d)", + strerror(-err), -err); + return err; + } + if (minUndequeuedBuffers > (int)mNumUndequeuedBuffers) { + ALOGE("new surface holds onto more buffers (%d) than planned for (%zu)", + minUndequeuedBuffers, mNumUndequeuedBuffers); + return BAD_VALUE; + } + + // we cannot change the number of output buffers while OMX is running + // set up surface to the same count + Vector<BufferInfo> &buffers = mBuffers[kPortIndexOutput]; + ALOGV("setting up surface for %zu buffers", buffers.size()); + + err = native_window_set_buffer_count(nativeWindow, buffers.size()); + if (err != 0) { + ALOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err), + -err); + return err; + } + + // for meta data mode, we move dequeud buffers to the new surface. + // for non-meta mode, we must move all registered buffers + for (size_t i = 0; i < buffers.size(); ++i) { + const BufferInfo &info = buffers[i]; + // skip undequeued buffers for meta data mode + if (mStoreMetaDataInOutputBuffers + && info.mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW) { + ALOGV("skipping buffer %p", info.mGraphicBuffer->getNativeBuffer()); + continue; + } + ALOGV("attaching buffer %p", info.mGraphicBuffer->getNativeBuffer()); + + err = surface->attachBuffer(info.mGraphicBuffer->getNativeBuffer()); + if (err != OK) { + ALOGE("failed to attach buffer %p to the new surface: %s (%d)", + info.mGraphicBuffer->getNativeBuffer(), + strerror(-err), -err); + return err; + } + } + + // cancel undequeued buffers to new surface + if (!mStoreMetaDataInOutputBuffers) { + for (size_t i = 0; i < buffers.size(); ++i) { + const BufferInfo &info = buffers[i]; + if (info.mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW) { + ALOGV("canceling buffer %p", info.mGraphicBuffer->getNativeBuffer()); + err = nativeWindow->cancelBuffer( + nativeWindow, info.mGraphicBuffer->getNativeBuffer(), -1); + if (err != OK) { + ALOGE("failed to cancel buffer %p to the new surface: %s (%d)", + info.mGraphicBuffer->getNativeBuffer(), + strerror(-err), -err); + return err; + } + } + } + // disallow further allocation + (void)surface->getIGraphicBufferProducer()->allowAllocation(false); + } + + mNativeWindow = nativeWindow; + return OK; +} + status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) { CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput); @@ -627,74 +748,35 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) { return OK; } -status_t ACodec::configureOutputBuffersFromNativeWindow( - OMX_U32 *bufferCount, OMX_U32 *bufferSize, - OMX_U32 *minUndequeuedBuffers) { - OMX_PARAM_PORTDEFINITIONTYPE def; - InitOMXParams(&def); - def.nPortIndex = kPortIndexOutput; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - if (err != OK) { - return err; - } - - err = native_window_set_buffers_dimensions( - mNativeWindow.get(), - def.format.video.nFrameWidth, - def.format.video.nFrameHeight); - +status_t ACodec::setNativeWindowSizeFormatAndUsage( + ANativeWindow *nativeWindow /* nonnull */, + int width, int height, int format, int rotation, int usage) { + status_t err = native_window_set_buffers_dimensions(nativeWindow, width, height); if (err != 0) { - ALOGE("native_window_set_buffers_dimensions failed: %s (%d)", - strerror(-err), -err); + ALOGE("native_window_set_buffers_dimensions failed: %s (%d)", strerror(-err), -err); return err; } - err = native_window_set_buffers_format( - mNativeWindow.get(), - def.format.video.eColorFormat); - + err = native_window_set_buffers_format(nativeWindow, format); if (err != 0) { - ALOGE("native_window_set_buffers_format failed: %s (%d)", - strerror(-err), -err); + ALOGE("native_window_set_buffers_format failed: %s (%d)", strerror(-err), -err); return err; } - if (mRotationDegrees != 0) { - uint32_t transform = 0; - switch (mRotationDegrees) { - case 0: transform = 0; break; - case 90: transform = HAL_TRANSFORM_ROT_90; break; - case 180: transform = HAL_TRANSFORM_ROT_180; break; - case 270: transform = HAL_TRANSFORM_ROT_270; break; - default: transform = 0; break; - } - - if (transform > 0) { - err = native_window_set_buffers_transform( - mNativeWindow.get(), transform); - if (err != 0) { - ALOGE("native_window_set_buffers_transform failed: %s (%d)", - strerror(-err), -err); - return err; - } + int transform = 0; + if ((rotation % 90) == 0) { + switch ((rotation / 90) & 3) { + case 1: transform = HAL_TRANSFORM_ROT_90; break; + case 2: transform = HAL_TRANSFORM_ROT_180; break; + case 3: transform = HAL_TRANSFORM_ROT_270; break; + default: transform = 0; break; } } - // Set up the native window. - OMX_U32 usage = 0; - err = mOMX->getGraphicBufferUsage(mNode, kPortIndexOutput, &usage); + err = native_window_set_buffers_transform(nativeWindow, transform); if (err != 0) { - ALOGW("querying usage flags from OMX IL component failed: %d", err); - // XXX: Currently this error is logged, but not fatal. - usage = 0; - } - int omxUsage = usage; - - if (mFlags & kFlagIsGrallocUsageProtected) { - usage |= GRALLOC_USAGE_PROTECTED; + ALOGE("native_window_set_buffers_transform failed: %s (%d)", strerror(-err), -err); + return err; } // Make sure to check whether either Stagefright or the video decoder @@ -703,11 +785,10 @@ status_t ACodec::configureOutputBuffersFromNativeWindow( // Verify that the ANativeWindow sends images directly to // SurfaceFlinger. int queuesToNativeWindow = 0; - err = mNativeWindow->query( - mNativeWindow.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, - &queuesToNativeWindow); + err = nativeWindow->query( + nativeWindow, NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &queuesToNativeWindow); if (err != 0) { - ALOGE("error authenticating native window: %d", err); + ALOGE("error authenticating native window: %s (%d)", strerror(-err), -err); return err; } if (queuesToNativeWindow != 1) { @@ -717,26 +798,84 @@ status_t ACodec::configureOutputBuffersFromNativeWindow( } int consumerUsage = 0; - err = mNativeWindow->query( - mNativeWindow.get(), NATIVE_WINDOW_CONSUMER_USAGE_BITS, - &consumerUsage); + err = nativeWindow->query(nativeWindow, NATIVE_WINDOW_CONSUMER_USAGE_BITS, &consumerUsage); if (err != 0) { ALOGW("failed to get consumer usage bits. ignoring"); err = 0; } - ALOGV("gralloc usage: %#x(OMX) => %#x(ACodec) + %#x(Consumer) = %#x", - omxUsage, usage, consumerUsage, usage | consumerUsage); - usage |= consumerUsage; - err = native_window_set_usage( - mNativeWindow.get(), - usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP); - + int finalUsage = usage | consumerUsage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP; + ALOGV("gralloc usage: %#x(ACodec) + %#x(Consumer) = %#x", usage, consumerUsage, finalUsage); + err = native_window_set_usage(nativeWindow, finalUsage); if (err != 0) { ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err); return err; } + err = native_window_set_scaling_mode( + nativeWindow, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + if (err != 0) { + ALOGE("native_window_set_scaling_mode failed: %s (%d)", strerror(-err), -err); + return err; + } + + ALOGD("set up nativeWindow %p for %dx%d, color %#x, rotation %d, usage %#x", + nativeWindow, width, height, format, rotation, finalUsage); + return OK; +} + +status_t ACodec::setupNativeWindowSizeFormatAndUsage(ANativeWindow *nativeWindow /* nonnull */) { + OMX_PARAM_PORTDEFINITIONTYPE def; + InitOMXParams(&def); + def.nPortIndex = kPortIndexOutput; + + status_t err = mOMX->getParameter( + mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); + + if (err != OK) { + return err; + } + + OMX_U32 usage = 0; + err = mOMX->getGraphicBufferUsage(mNode, kPortIndexOutput, &usage); + if (err != 0) { + ALOGW("querying usage flags from OMX IL component failed: %d", err); + // XXX: Currently this error is logged, but not fatal. + usage = 0; + } + int omxUsage = usage; + + if (mFlags & kFlagIsGrallocUsageProtected) { + usage |= GRALLOC_USAGE_PROTECTED; + } + + ALOGV("gralloc usage: %#x(OMX) => %#x(ACodec)", omxUsage, usage); + return setNativeWindowSizeFormatAndUsage( + nativeWindow, + def.format.video.nFrameWidth, + def.format.video.nFrameHeight, + def.format.video.eColorFormat, + mRotationDegrees, + usage); +} + +status_t ACodec::configureOutputBuffersFromNativeWindow( + OMX_U32 *bufferCount, OMX_U32 *bufferSize, + OMX_U32 *minUndequeuedBuffers) { + OMX_PARAM_PORTDEFINITIONTYPE def; + InitOMXParams(&def); + def.nPortIndex = kPortIndexOutput; + + status_t err = mOMX->getParameter( + mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); + + if (err == OK) { + err = setupNativeWindowSizeFormatAndUsage(mNativeWindow.get()); + } + if (err != OK) { + return err; + } + // Exits here for tunneled video playback codecs -- i.e. skips native window // buffer allocation step as this is managed by the tunneled OMX omponent // itself and explicitly sets def.nBufferCountActual to 0. @@ -1489,9 +1628,6 @@ status_t ACodec::configureCodec( if (haveNativeWindow) { mNativeWindow = static_cast<Surface *>(obj.get()); CHECK(mNativeWindow != NULL); - - native_window_set_scaling_mode( - mNativeWindow.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); } // initialize native window now to get actual output format @@ -4012,32 +4148,10 @@ status_t ACodec::pushBlankBuffersToNativeWindow() { return err; } - err = native_window_set_buffers_dimensions(mNativeWindow.get(), 1, 1); + err = setNativeWindowSizeFormatAndUsage( + mNativeWindow.get(), 1, 1, HAL_PIXEL_FORMAT_RGBX_8888, 0, GRALLOC_USAGE_SW_WRITE_OFTEN); if (err != NO_ERROR) { - ALOGE("error pushing blank frames: set_buffers_dimensions failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - err = native_window_set_buffers_format(mNativeWindow.get(), HAL_PIXEL_FORMAT_RGBX_8888); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: set_buffers_format failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - err = native_window_set_scaling_mode(mNativeWindow.get(), - NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - if (err != NO_ERROR) { - ALOGE("error pushing blank_frames: set_scaling_mode failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - err = native_window_set_usage(mNativeWindow.get(), - GRALLOC_USAGE_SW_WRITE_OFTEN); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: set_usage failed: %s (%d)", + ALOGE("error pushing blank frames: set format failed: %s (%d)", strerror(-err), -err); goto error; } @@ -4209,6 +4323,22 @@ bool ACodec::BaseState::onMessageReceived(const sp<AMessage> &msg) { return onOMXMessage(msg); } + case ACodec::kWhatSetSurface: + { + sp<AReplyToken> replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + sp<RefBase> obj; + CHECK(msg->findObject("surface", &obj)); + + status_t err = mCodec->handleSetSurface(static_cast<Surface *>(obj.get())); + + sp<AMessage> response = new AMessage; + response->setInt32("err", err); + response->postReply(replyID); + break; + } + case ACodec::kWhatCreateInputSurface: case ACodec::kWhatUsePersistentInputSurface: case ACodec::kWhatSignalEndOfInputStream: diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index ace7826..ed4f682 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -556,6 +556,14 @@ status_t MediaCodec::usePersistentInputSurface( return PostAndAwaitResponse(msg, &response); } +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); @@ -1249,7 +1257,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); @@ -1280,7 +1288,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); @@ -1686,6 +1694,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: case kWhatUsePersistentInputSurface: { @@ -2456,36 +2519,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() { |