diff options
Diffstat (limited to 'media')
-rw-r--r-- | media/libstagefright/ACodec.cpp | 326 | ||||
-rw-r--r-- | media/libstagefright/MediaCodec.cpp | 115 |
2 files changed, 321 insertions, 120 deletions
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 7b87676..3439c3a 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -476,6 +476,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(); } @@ -523,6 +536,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); @@ -617,74 +738,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 @@ -693,11 +775,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) { @@ -707,26 +788,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. @@ -1479,9 +1618,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 @@ -4002,32 +4138,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; } @@ -4199,6 +4313,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::kWhatSignalEndOfInputStream: { 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() { |