0

How can I create an overrided method where the method is forced to be single-threaded (not async) when originally it was multi-threaded? Specifically I am trying to avoid a "dequeueOutputBuffer can't be used in async mode" error in Grafika's ScreenRecordActivity. "info" variable needs to be volatile not final.

@Override
public void onOutputBufferAvailable(...) {
    ...
    int outputBufIndex = codec.dequeueOutputBuffer(info, kTimeOutUs);

Update #1
Stacktrack of error: pastebin.com/sgJpyTnP

E/MediaCodec: dequeueOutputBuffer can't be used in async mode
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
                 Process: com.google.grafika, PID: 4469
                 java.lang.IllegalStateException
                     at android.media.MediaCodec.native_dequeueOutputBuffer(Native Method)
                     at android.media.MediaCodec.dequeueOutputBuffer(MediaCodec.java:2632)
                     at com.android.grafika.ScreenRecordActivity$3$1.run(ScreenRecordActivity.java:283)
                     at java.lang.Thread.run(Thread.java:764)
                     at com.android.grafika.ScreenRecordActivity$3.onOutputBufferAvailable(ScreenRecordActivity.java:312)
                     at android.media.MediaCodec$EventHandler.handleCallback(MediaCodec.java:1682)
                     at android.media.MediaCodec$EventHandler.handleMessage(MediaCodec.java:1629)
                     at android.os.Handler.dispatchMessage(Handler.java:106)
                     at android.os.Looper.loop(Looper.java:164)
                     at android.app.ActivityThread.main(ActivityThread.java:6494)
                     at java.lang.reflect.Method.invoke(Native Method)
                     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
  • would it be enough to execute this pice of code within the main thread ? Like getActivity.runOnUiThread(() -> { /*your code*/ }); – Gerrit Sedlaczek May 05 '18 at 20:30
  • @Mett Thanks, but still same error if I try: `runOnUiThread(new Runnable() {` `@Override` `public void run()` `{ encoderCallback = new MediaCodec.Callback() {` `...` `int outputBufIndex = codec.dequeueOutputBuffer(info, kTimeOutUs);` – CompNeuroDev May 05 '18 at 21:36
  • how about something like: `encoderCallback = new MediaCodec.Callback() {getActivity().runOnUiThread() -> { ... int outputBufIndex = codec.dequeueOutputBuffer(info, kTimeOutUs);}}` to ensure that whatever happens inside of the callback gets executed by the main Thread – Gerrit Sedlaczek May 05 '18 at 22:06
  • @Mett Thanks again but that generates the error `"Variable 'info' is accessed from within inner class, needs to be declared final"` I can not declare info as final however because it needs to be volatile – CompNeuroDev May 05 '18 at 22:49
  • 1
    @Mett I think I got it! To fix the error I created global variables for 'info' and other needed and copied the local variables to global upon use [post about the error](https://stackoverflow.com/questions/14425826/variable-is-accessed-within-inner-class-needs-to-be-declared-final). runOnUiThread() still causes the async error unfortunately. I made the small change of `runOnUiThread()` to `Thread t1=new Thread` and it ran successfully! Thanks SO much!! If you post this as an answer I will give you credit for solving it because it was your general idea. – CompNeuroDev May 05 '18 at 23:32
  • Thanks but theres no need for that. Im glad you found a solution :) – Gerrit Sedlaczek May 06 '18 at 11:09
  • @Mett Yes, I appreciate your help a lot! In that case I am going to write up the answer and post it myself so that anyone with a similar issue will have a solution. I will make sure to acknowledge you in it; if there is an official way to acknowledge you let me know, otherwise I will just add a mention to you in the post. – CompNeuroDev May 06 '18 at 17:09
  • @Mett Actually unfortunately I found out that the reason the error was not coming back when I created `new Thread` is I never _ran_ the thread. After running it I am getting the same error again. I am puzzled because it would seem the code is running not in async due to either being assigned a single thread or runOnUiThread() yet the error states otherwise. I will continue to investigate. – CompNeuroDev May 06 '18 at 23:56
  • Could you please provide additional information such as the stacktrace you mentioned? – Gerrit Sedlaczek May 07 '18 at 13:42
  • @Mett Thanks for looking into this more. I have provided the stacktrace as update #1, any other info I can provide? – CompNeuroDev May 07 '18 at 18:26
  • Your Exception is kinda weird. It states `onOutputBufferAvailable(ScreenRecordActivity.java:312)` but ScreenRecordActivity only has 307 lines of code (as your github reference clearly shows). Does your local copy of the class differ from the one on github ? And please add the stacktrace itself to your question. – Gerrit Sedlaczek May 08 '18 at 17:52
  • @Mett Yes, my local copy included dequeueOutputBuffer and other methods not in the Google linked code for grabbing frames of screen captures. I discovered that Google advises writing the code much differently for synchronous mode as seen [in this link](https://developer.android.com/reference/android/media/MediaCodec) under 'synchronous mode'. I will rewrite Grafika's code using code in the link to enable dequeueOutputBuffer. This hopefully will be the road to success and I will post if I can get it to work. Thanks again for working with me here, hopefully it will help others with similar cases – CompNeuroDev May 09 '18 at 02:44

0 Answers0