-
Notifications
You must be signed in to change notification settings - Fork 176
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CommandProcessor.process() never ends (race condition and EGL error: 0x3003) #69
Comments
@sjvc Hi,do you know how to improve the output video quality when compress video? |
I don't know, sorry @gzgang |
@gzgang same problem |
This didn't work for me. It causes 0kb videos to be generated. The other solution (commenting out I've modified the m4m source to allow exporting videos larger than 1280 resolution. The timeout issues seem to happen more frequently for larger videos. Thanks for the attempt though. |
I'm using
GLCapture
to record a video. But I noticed that sometimes (about 50% percent of the times) generated video is not readable.Navigating through source code and debugging, I noticed that sometimes,
commandProcessor.process()
insideCapturePipeline.java
never ends, becausecommandProcessor.stop()
has not been called. IfcommandProcessor.process()
never ends, thenpipeline.release()
is not called. Insidepipeline.release()
is where sources and sinks are closed (where file writing is finished). So the result is thatcommandProcessor.process()
is stuck inwhile (!stopped)
doing nothing, and files are not readable.So, where is
commandProcessor.stop()
called? InPipeline.java
, when the sink is set (setSink
), a stop listener is assigned to it, andcommandProcessor.stop()
is called when sink is stopped. The sink is an instance ofMuxRender
, and I saw thatonStopListener.onStop()
is executed whenMuxRender.drain
method is executed exactly the same number of times that plugins are connected to it. In our case, these are 2 (for video and audio). To sum up,commandProcessor.stop()
is not called becauseMuxRender.drain
method is only called 1 time.Who have to call
MuxRender.drain
method? It'sPullDataCommandHandler.handle
(command handlers are executed inCommandProcessor.process()
).PullDataCommandHandler.handle
callsoutput.getFrame()
, and if result isFrame.EOF
, theninput.drain
is called. The input is alwaysMuxRender
, and outputs areAudioEncoder
andVideoEncoder
. I can advance that the problem is with video, so I will focus on video.When all works correctly, it's like that:
To stop video capturing, we call
GLCapture.stop()
, who callsCapturePipeline.stop()
, who callsPipeline.stop()
, who callsCaptureSource.stop()
(mediaSource.stop()
), who addsCommand.EndOfFile
to itscommandQueue
, and it's processed and it makes thatDrainCommandHandler
is executed, soVideoEncoder.drain()
is executed. So, the next time thatPullDataCommandHandler
is executed to pass data fromVideoEncoder
toMuxRender
, it will callgetFrame()
onVideoEncoder
, who responds withFrame.EOF()
(because it's drained), so such command handler will callMuxRender.drain()
. And this is all we need: thatMuxRender.drain()
is called, soonStopListener
is called, andcommandProcessor.stop()
is called, andpipeline.release()
is a called, and all the work is stopped and files are finished correctly.So, when is not working correctly? Let's see:
To stop video capturing, we call
GLCapture.stop()
, who callsCapturePipeline.stop()
, who callsPipeline.stop()
, who callsCaptureSource.stop()
(mediaSource.stop()
), who addsCommand.EndOfFile
to itscommandQueue
. But before it's processed, this time the queue will processPushSurfaceCommandHandler
(to pass data from CaptureSource to VideoEncoder), who callsCaptureSource.getFrame()
, who returnsFrame.EOF()
and clears thecommandQueue
. AscommandQueue
has been cleared,Command.EndOfFile
never is processed, soVideoEncoder
is not drained, andPullDataCommandHandler
won't callMuxRender.drain()
, so it'sonStopListener
won't be called, andcommandProcessor
will be processing forever... and video file is not readable.How to solve it? @jhognon suggests removing
commandQueue.clear()
method call fromCaptureSource.java
in Issue #41 to solve this race condition. It worked, because thenCommand.EndOfFile
is processed, and everything goes fine. Is it the correct solution? Well, we don't know. But it works.I executed it several times, it seemed it was working, but it happened again: commandProcessor never ends, and file is unreadable. But this time the generated file is 0KB. Debugging the project again, I found that an error is generated after calling
EGL14.eglCreateContext
inInputSurface.java
. So no video data is processed, and of course,MuxRender.drain
method is never called.The generated error was
EGL error: 0x3003 (BAD_ALLOC)
, which is generated if there are not enough resources to allocate the new context.So, now the problem is that there are no enough resources to call
EGL14.eglCreateContext
. This lead to question: isEGL14.eglDestroyContext
being called to free resources? I found it's called insideInputSurface.release()
. InputSurface is instantiated inSurface.java
. And... guess what?Surface
never callsInputSurface.release()
, soEGL14.eglDestroyContext
is never called... I added a call toinputSurface.release()
(andoutputSurface.release()
) insideSurface.release()
, and now everything is working like a charm!But, what if there is another error that makes
commandProcessor()
run forever? To ensure it won't happen again, I'm stoping pipeline'scommandProcessor
insideCapturePipeline.stop()
method. With this call, I'll be sure that all the processing stops, and file is readable (so I reverted deletingcommandQueue.clear()
insideCaptureSource.java
, because such modification is not needed).I know it's not the correct solution, but a workaround until someone finds the correct one.
I pushed these modifications to my github: https://github.com/sjvc/media-for-mobile
Is anyone maintaining this library? Please, take a look at this issue. Let me know if I can help.
The text was updated successfully, but these errors were encountered: