Loading include/media/stagefright/ACodec.h +9 −0 Original line number Diff line number Diff line Loading @@ -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(); Loading Loading @@ -115,6 +117,7 @@ private: kWhatDrainDeferredMessages = 'drai', kWhatAllocateComponent = 'allo', kWhatConfigureComponent = 'conf', kWhatSetSurface = 'setS', kWhatCreateInputSurface = 'cisf', kWhatUsePersistentInputSurface = 'pisf', kWhatSignalEndOfInputStream = 'eois', Loading Loading @@ -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); Loading include/media/stagefright/CodecBase.h +2 −0 Original line number Diff line number Diff line Loading @@ -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; Loading include/media/stagefright/MediaCodec.h +6 −2 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -184,6 +186,7 @@ private: enum { kWhatInit = 'init', kWhatConfigure = 'conf', kWhatSetSurface = 'sSur', kWhatCreateInputSurface = 'cisf', kWhatUsePersistentInputSurface = 'pisf', kWhatStart = 'strt', Loading Loading @@ -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(); Loading media/libstagefright/ACodec.cpp +228 −98 Original line number Diff line number Diff line Loading @@ -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(); } Loading Loading @@ -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); Loading Loading @@ -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; 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; } 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; } } } // 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 Loading @@ -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) { Loading @@ -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. Loading Loading @@ -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 Loading Loading @@ -4012,32 +4148,10 @@ status_t ACodec::pushBlankBuffersToNativeWindow() { return err; } err = native_window_set_buffers_dimensions(mNativeWindow.get(), 1, 1); 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); 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_usage failed: %s (%d)", ALOGE("error pushing blank frames: set format failed: %s (%d)", strerror(-err), -err); goto error; } Loading Loading @@ -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: Loading media/libstagefright/MediaCodec.cpp +93 −22 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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: { Loading Loading @@ -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(); } 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; } status_t MediaCodec::handleSetSurface(const sp<Surface> &surface) { status_t err = OK; if (mSurface != NULL) { (void)disconnectFromSurface(); } if (surface != NULL) { err = connectToSurface(surface); if (err == OK) { mSurface = surface; } return OK; } return err; } void MediaCodec::onInputBufferAvailable() { Loading Loading
include/media/stagefright/ACodec.h +9 −0 Original line number Diff line number Diff line Loading @@ -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(); Loading Loading @@ -115,6 +117,7 @@ private: kWhatDrainDeferredMessages = 'drai', kWhatAllocateComponent = 'allo', kWhatConfigureComponent = 'conf', kWhatSetSurface = 'setS', kWhatCreateInputSurface = 'cisf', kWhatUsePersistentInputSurface = 'pisf', kWhatSignalEndOfInputStream = 'eois', Loading Loading @@ -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); Loading
include/media/stagefright/CodecBase.h +2 −0 Original line number Diff line number Diff line Loading @@ -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; Loading
include/media/stagefright/MediaCodec.h +6 −2 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -184,6 +186,7 @@ private: enum { kWhatInit = 'init', kWhatConfigure = 'conf', kWhatSetSurface = 'sSur', kWhatCreateInputSurface = 'cisf', kWhatUsePersistentInputSurface = 'pisf', kWhatStart = 'strt', Loading Loading @@ -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(); Loading
media/libstagefright/ACodec.cpp +228 −98 Original line number Diff line number Diff line Loading @@ -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(); } Loading Loading @@ -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); Loading Loading @@ -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; 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; } 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; } } } // 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 Loading @@ -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) { Loading @@ -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. Loading Loading @@ -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 Loading Loading @@ -4012,32 +4148,10 @@ status_t ACodec::pushBlankBuffersToNativeWindow() { return err; } err = native_window_set_buffers_dimensions(mNativeWindow.get(), 1, 1); 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); 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_usage failed: %s (%d)", ALOGE("error pushing blank frames: set format failed: %s (%d)", strerror(-err), -err); goto error; } Loading Loading @@ -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: Loading
media/libstagefright/MediaCodec.cpp +93 −22 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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: { Loading Loading @@ -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(); } 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; } status_t MediaCodec::handleSetSurface(const sp<Surface> &surface) { status_t err = OK; if (mSurface != NULL) { (void)disconnectFromSurface(); } if (surface != NULL) { err = connectToSurface(surface); if (err == OK) { mSurface = surface; } return OK; } return err; } void MediaCodec::onInputBufferAvailable() { Loading