The hello_video example uses a slightly different shutdown approach then described in the spec (I might be wrong here, but I think they take a different approach). When I folllow the approach from hello_video.c, 9 out of 10 shutdowns work fine but sometimes I get an OMX_ErrorInsufficientResources when switching from executing into idle state for the decoder. From the IL spec 188.8.131.52 OMX_CommandStateSet this error means: The transition required the allocation of resources and the component failed to acquire the resources. At the point where I want to transition into idle state, I have already removed the tunnel between 131 -> 90, I have deallocated the buffers (cpu), called OMX_FreeBuffer() for the buffer headers on port 130.
The calls I make after I have fed the last nal, look like:
- send a buffer with OMX_BUFFERFLAG_EOS and nFilledLen = 0.
- send OMX_CommandFlush on port 131 and 90 + wait until command completed
- disable the OMX_IndexParamPassBufferMarks for the decoder
- disable port 131 (blocking)
- disable port 90 (blocking)
- deallocate buffers for port 130 (input buffers)
- teardown the tunnel: OMX_SetupTunnel(decoder, 131, NULL, 0);
- teardown the tunnel: OMX_SetupTunnel(renderer, 90, NULL, 0);
- transition decoder to idle state <--- this one hangs sometimes
- transition renderer to idle state
- transition decoder to loaded state
- transitions renderer to loaded state
The port definition for port 130 looks like:
Code: Select all
OMX_PARAM_PORTDEFINITION_TYPE.eDir: OMX_DirInput OMX_PARAM_PORTDEFINITION_TYPE.nBufferCountActual: 20 OMX_PARAM_PORTDEFINITION_TYPE.nBufferCountMin: 1 OMX_PARAM_PORTDEFINITION_TYPE.nBufferSize: 81920 OMX_PARAM_PORTDEFINITION_TYPE.bEnabled: 0 OMX_PARAM_PORTDEFINITION_TYPE.bPopulated: 0 OMX_PARAM_PORTDEFINITION_TYPE.bBuffersContiguous: 0 OMX_PARAM_PORTDEFINITION_TYPE.nBufferAlignment: 16 OMX_PARAM_PORTDEFINITION_TYPE.eDomain: OMX_PortDomainVideo OMX_PARAM_PORTDEFINITION_TYPE.format.video.nFrameWidth: 0 OMX_PARAM_PORTDEFINITION_TYPE.format.video.nFrameHeight: 0 OMX_PARAM_PORTDEFINITION_TYPE.format.video.nStride: 0 OMX_PARAM_PORTDEFINITION_TYPE.format.video.nSliceHeight: 0 OMX_PARAM_PORTDEFINITION_TYPE.format.video.xFramerate: 0 OMX_PARAM_PORTDEFINITION_TYPE.format.video.bFlagErrorConcealment: 0 OMX_PARAM_PORTDEFINITION_TYPE.format.video.eCompressionFormat: OMX_VIDEO_CodingAVC OMX_PARAM_PORTDEFINITION_TYPE.format.video.eColorFormat: OMX_COLOR_FormatUnused
The port definition for port 131 looks like:
Because the ports are disabled, I don't understand why I receive an OMX_ErrorInsufficientResources error because there is nothing to allocate. I have pasted the logs from my experiment when shutdown fails here: https://gist.github.com/roxlu/6bdaee9ff ... 19321e18f3 and this is a log when is successfully shutdown: https://gist.github.com/roxlu/c76a218d5 ... d982a39a17
Code: Select all
OMX_PARAM_PORTDEFINITION_TYPE.eDir: OMX_DirOutput OMX_PARAM_PORTDEFINITION_TYPE.nBufferCountActual: 0 OMX_PARAM_PORTDEFINITION_TYPE.nBufferCountMin: 0 OMX_PARAM_PORTDEFINITION_TYPE.nBufferSize: 3133440 OMX_PARAM_PORTDEFINITION_TYPE.bEnabled: 0 OMX_PARAM_PORTDEFINITION_TYPE.bPopulated: 1 OMX_PARAM_PORTDEFINITION_TYPE.bBuffersContiguous: 0 OMX_PARAM_PORTDEFINITION_TYPE.nBufferAlignment: 16 OMX_PARAM_PORTDEFINITION_TYPE.eDomain: OMX_PortDomainVideo OMX_PARAM_PORTDEFINITION_TYPE.format.video.nFrameWidth: 1920 OMX_PARAM_PORTDEFINITION_TYPE.format.video.nFrameHeight: 1080 OMX_PARAM_PORTDEFINITION_TYPE.format.video.nStride: 1920 OMX_PARAM_PORTDEFINITION_TYPE.format.video.nSliceHeight: 1088 OMX_PARAM_PORTDEFINITION_TYPE.format.video.xFramerate: 1638400 OMX_PARAM_PORTDEFINITION_TYPE.format.video.bFlagErrorConcealment: 0 OMX_PARAM_PORTDEFINITION_TYPE.format.video.eCompressionFormat: OMX_VIDEO_CodingUnused OMX_PARAM_PORTDEFINITION_TYPE.format.video.eColorFormat: OMX_COLOR_FormatYUV420SemiPlanar
What might be causing this issue and what is the recommended shutdown procedure?
Is there a way to get more information about why OMX decides that I can't switch states?
This post viewtopic.php?t=48177#p424058 points towards a solution. It seems that tearing down a tunnel by using OMX_SetupTunnel(decoder, 131, NULL, 0); and OMX_SetupTunnel(renderer, 90, NULL, 0); can only be done when the state is OMX_StateLoaded or when the ports are disabled. So I disable the ports and then make those OMX_SetupTunnel() calls. This doesn't seem to fix the issue. I tested by waiting for the event complete on port disablement using an active loop and in another version using a condition variable that was notified when the complete event for the disablement was received. What did fix this issue was adding a call to usleep(10e3) right after making the calls to OMX_SetupTunnel(...). So it seems that there is an issue somewhere with this call. I suspect that it's an threading thing somewhere in this call where a state isn't set at the right time. This is just a guess but it definitely seems to be related to threading/timing..
I was going through some more posts and while looking at this one viewtopic.php?p=892432 I thought that I actually should remove my active waiting loop that checks if a component changed it's state. I'm talking about a loop like this: https://github.com/tjormola/rpi-openmax ... ode.c#L351 You can find this code everywhere as it's an quick 'n dirty way to get going with OpenMax w/o bothering multi threaded code. I got a long way with these active loops but I think this was the reason why I got the OMX_ErrorInsufficientResources error when trying to transition to the idle state. Maybe this error means the CPU is too busy? Or some mutex is being locked for too many retries (?!). Anyway when I changed my code in such a way that it uses a condition variable to detect state changes instead of this loop with a usleep in it everything started working as expected.
To be a bit more precise, the loop where I was calling OMX_FreeBuffer() on port 130 (input) of the video_decode component was implemented like this (this is the version that DID NOT WORK): send disable port command for port 130, in a loop for all the input buffers that I allocated I called OMX_FreeBuffer(), then I waited actively until the disablement completed, using a loop with a usleep(). When I changed this into a wait using a std::condition_variable my shutdown sequence worked as expected.