saki4510t / ScreenRecordingSample

Simultaneous audio and screen recording sample using MediaCodec/MediaMuxer/VirtualDisplay
Apache License 2.0
189 stars 89 forks source link

ScreenRecordingSample takes too much time to record video to disk #2

Closed RazorPT closed 9 years ago

RazorPT commented 9 years ago

I am using a FileObserver which looks for new files on my app folder it seems ScreenRecordingSample takes so long to write the Video to the disk after stoped recording that FileObserver sometimes fails to load the the video to my app then i have to refresh the directory using a File Explorer and then load my app again for the video to appear in my list and load it correctly.

If i don´t do this sometimes the video preview which i show the first frame shows black and cant play video.

I tried debugging this my self all this afternoon but dind´t understood what is the case of the problem. If i use MediaRecorder class (which doesnt support pause) i don´t have this problem.

saki4510t commented 9 years ago

Hi, MediaCodec encoder asynchronously encode frame and it will take several hundred milliseconds after stop queuing frame data. And MediaMuxer also asynchronously write encoded movie data to file and it will take several hundred milliseconds to several seconds after stop writing sampling data and can not know when it will actually finish. This is normal behavior and not a issue.
I'm not sure how you implement your app and why you need to use FileObserver but I assume you may create FileObserver on wrong context like Activity.

RazorPT commented 9 years ago

I am developing an app that records the screen and i am using a ListView with an AsyncTaskLoader to load all videos present on my app folder. I use a FileObserver inside the AsynctaskLoader to listen for any events inside my app folder (Create/Modify/Delete of any video file) to refresh my listview with new Recordings. Using MediaRecorder works perfectly with my code since the video is ready as soon i stop recording.

But i would like to implement your code the strange thing is this problem only happens sometimes so maybe i am thinking to record the file to a separate folder wait for the mMediaMuxer to be stopped and released by the encoders and send a broadcast back to my app so i can move the file from the private App folder to the public folder where the FileObserver will trigger.

Would that work? I mean after mMediaMuxer inside MediaMuxerWrapper has been released the video is supposed to be ready correct?

RazorPT commented 9 years ago

Okay i just found out that mMediaMuxer never gets released i turned on debug mode on MediaMuxerWrapper this is what my console gives me:

D/MediaMuxerWrapper﹕ path=/storage/emulated/0/Movies/ScreenRecSample I/MediaMuxerWrapper﹕ addTrack:trackNum=2,trackIx=0,format={what=1869968451, mime=audio/mp4a-latm, csd-0=java.nio.ByteArrayBuffer[position=0,limit=2,capacity=2], channel-count=1, sample-rate=44100} V/MediaMuxerWrapper﹕ start: I/MediaMuxerWrapper﹕ addTrack:trackNum=2,trackIx=1,format={height=1776, width=1080, csd-1=java.nio.ByteArrayBuffer[position=0,limit=8,capacity=8], what=1869968451, mime=video/avc, csd-0=java.nio.ByteArrayBuffer[position=0,limit=19,capacity=19]} V/MediaMuxerWrapper﹕ start: V/MediaMuxerWrapper﹕ MediaMuxer started: V/MediaMuxerWrapper﹕ stop:mStatredCount=2

It doesn´t enter in the if inside the release method where it should stop and release the mMediaMuxer

What i found was the MediaScreenEncoder doesn´t seem to be releasing after i stop recording i tried setting a breakpoint inside the release method of MediaScreenEncoder but it never gets called

@Override
protected void release() {
    mHandler.getLooper().quit();
    super.release();
}

Edit: Just confirmed this onRelease of AudioEncoder is called but the onRelease of MediaScreenEncoder is never called wonder why the code seems bug free and you set mRequestStop to true when you call stopRecording for both MediaEncoders.

RazorPT commented 9 years ago

Okay just fixed the problem!

The problem was that the code set mIsCapturing = false; inside stopRecording method on MediaScreenEncoder class and then call super.stopRecording but since the mIsCapturing is already false it will return before setting mRequestStop = true; which made MediaScreenEncoder not releasing as expected.

I had to remove the override method stopRecording on MediaScreenEncoder and add mIsCapturing = false; to stopRecorindg method on MediaEncoder and now it works great!

MediaMuxer is now stopped and release as it should and the initial problem went away :D

saki4510t commented 9 years ago

Thank you for providing information. Well, removing MediaScreenEncoder#stopRecording is OK, but I assume adding mRequestStop flag check in screen capturing loop(as in MediaAudioEncoder) will be better instead of adding mIsCapturing = false in MediaEncoder#stopRecording.