Java Question Need to understand some Java Code

XverhelstX

Well-Known Member
Licensed User
Longtime User
This is to let you now that I actually don't have an error but a bunch of hexadecimal sh*t that shows it works (on a cumbersome manner) but that I don't have any error on the catch event. Only when the Timer ticked.

So as you can see:
Try Mode.
IsPreviewOn is True
Decoding is true.
Callback Done.
An error occured.
main_ti_tick (java line: 319)
java.lang.NullPointerException
at anywheresoftware.b4a.agraham.byteconverter.ByteConverter.HexFromBytes(ByteConverter.java:237)
at com.rootsoft.streamnationstudio.main._ti_tick(main.java:319)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:104)
at anywheresoftware.b4a.objects.Timer$TickTack.run(Timer.java:101)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:3652)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:862)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
at dalvik.system.NativeStart.main(Native Method)
java.lang.NullPointerException
In onPreviewFrame
Initialize raw2jpg
In raw2jpg.
Done with raw2jpg
Decoding is false.

the decoding is finished at the bottom. Now I added the following:

B4X:
isDecoding = false;
                      notify();
                      Log.i("B4A","Decoding is false.");
                      currentFrame();
              }
       };
       
       public byte[] currentFrame() {
          
          return mCurrentFrame;
          
       }

and this in B4A:

B4X:
Sub mnuFocusMode_Click

   s = b.HexFromBytes(camera1.currentFrame)
   Msgbox(s,"")
   
End Sub

Sub TI_Tick
Timer1.Enabled = False
Msgbox("camera1.Picture.Length","")




'Dim out1 As OutputStream
'out1.WriteBytes(camera1.Picture, 0, camera1.Picture.Length)

's = BytesToString(camera1.Picture, 0, camera1.Picture.Length, "UTF-8")

s = b.HexFromBytes(camera1.Picture)


Msgbox("s","")

End Sub

b is byteconverter.
So when the timer ticks, I receive an error because the jpeg is in productionand is "made" at the end of the "log".
but when I show msgbox(s,"") it gives an output of my mCurrentFrame, what means I don't have an error! :D

The only problem is the Wait/notify feature

XverhelstX
 

XverhelstX

Well-Known Member
Licensed User
Longtime User
How does it come now that:

B4X:
public byte[] getPicture()

does call:

B4X:
c.setOneShotPreviewCallback(mPreviewCallback);

and

B4X:
public synchronized byte[] getPicture()

doesn't call it?

Please help me at this
I'm getting really frustrated and confused

XverhelstX
 

agraham

Expert
Licensed User
Longtime User
Are you really sure that is what is happening? Remember you need to make no assumptions whatsoever and use cold clear logic in analysing problems like this. I find it most unlikely that if the Sub is being entered some of the statements in it are executed while others are not. I suspect that using synchronised is causing a deadlock.

When synchronised getPicture() is called, while it is executing no other thread can call a synchronised method on that instance. While getPicture() is waiting for isDecoding it is holding a lock on the instance. I suspect setOneShotPreviewCallback() is executing and that the camera is trying to call onPreviewFrame() on its own thread but as that is also a synchronised method it blocks waiting for getPicture() to terminate which it can't as it needs the callback to clear isDecoding. It looks like a classic deadlock situation.

If I am correct, and I can't see why I might not be :cool: (although there may be some Java sublety that I am ignorant of as I am more comfortable with C#) then I have no idea how that original code ever worked. :confused:
 

XverhelstX

Well-Known Member
Licensed User
Longtime User
Ok, You will probably be right that OnPreviewFrame is called.

B4X:
that the camera [B]is trying[/B] to call onPreviewFrame() on its own thread but as that is also a synchronised method it blocks waiting

So here you mean that it is trying, but it doesn't call it?

How do I fix it then? I tried everything I know and I cannot seem to fix it.

XverhelstX
 

agraham

Expert
Licensed User
Longtime User
I've read up a bit more on how synchronised, wait and notify work in Java and now understand that the original structure of the code should be OK. What I didn't realise was that wait() releases the object lock set on entry to a synchronised method. You should be doing this so you understand what's going on. So it may not be a classic deadlock at all but possibly something is stopping onPreviewFrame() being called which will have the same effect.

I've looked in the jar you posted earlier and can't see any notify() calls in startPreview(), stopPreview() or onPreviewFrame(). You have reinstated them haven't you?
 

agraham

Expert
Licensed User
Longtime User
What have I been saying about cold hard logic and careful analysis? :BangHead:

I just wrote
I've looked in the jar you posted earlier and can't see any notify() calls in startPreview(), stopPreview() or onPreviewFrame(). You have reinstated them haven't you?
You replied "Yes" but looking in the jar you just posted they are NOT present in startPreview() and stopPreview() :(
getPicture() is probably stuck on "while (!isPreviewOn) wait();"

It won't work anyway as you have messed up the original interlock structure by trying to use a separate monitor object which won't work with wait() and notify() as they use the monitor associated with the instance.

You don't need a Camera.PreviewCallback instance, remove it.
You don't need myMonitor, remove it.
Add "implements PreviewCallback" to your ACL class declaration.
Reinstate notify() in the three methods I stated above.
Make onPreviewFrame() a normal method of your class.
Pass "this" in c.setOneShotPreviewCallback(this);
Make sure you understand what synchronized, wait() and notify() really do.
 

XverhelstX

Well-Known Member
Licensed User
Longtime User
It was an edit, i was trying to do several things. including with the myMonitor that they explained to me here:

It won't work anyway as you have messed up the original interlock structure by trying to use a separate monitor object which won't work with wait() and notify() as they use the monitor associated with the instance.

java - Need help with Synchronized - Stack Overflow

Anyway, now we are back at page 1 of this topic. And what says: still doesn't work.

getPicture() is probably stuck on "while (!isPreviewOn) wait();"
It is unlikely that it is stuck there as isPreviewOn is true and doesn't have to wait.

Attached is the zip file with the updated library.
 

Attachments

  • ACL.zip
    17.7 KB · Views: 368

agraham

Expert
Licensed User
Longtime User
That latest jar looks OK to me, as far as my understanding of Java synchronisation goes, so I'm afraid that I have no suggestions as to why it doesn't work.

To absolutely check that it is a synchronisation/dealock problem make isDecoding and mCurrentFrame available to your B4A program and comment out "while (isDecoding) wait();" in getPicture(). In your B4A program loop on isDecoding being true and see what happens.
 

XverhelstX

Well-Known Member
Licensed User
Longtime User
Ok, but could it have something to do with the surface(holder) or something.
As that seems completely different than used in B4A.

What do you mean with this?
comment out "while (isDecoding) wait();" in getPicture().


Just to let u know that this is in the main.java of the project camDroid where getPicture is used.:
B4X:
 @Override
        public void run()
        {
                isMainRunning(true);
                double deltaT0=0;
                boolean recState=true;
                double deltaT1=0;
                double fps_cnt=0;
                
                setText(osdState, " R E C ");
                setText(osdFps, " 0 fps ");
                
                while (isMainRunning())
                {
                        final double dateT1 = new Date().getTime();
                        currentJPEG = cameraFrame.getPicture();
                        final double dateT2 = new Date().getTime();
                        
                        fps_cnt += 1;
                        deltaT1 += dateT2 - dateT1;
                        deltaT0 += dateT2 - dateT1;
                        
                        if (deltaT0 >= 1000)
                        {
                                if (!recState)
                                {
                                        recState = true;
                                        setText(osdState, " R E C ");
                                }
                                else
                                {
                                        recState = false;
                                        setText(osdState, "       ");
                                }
                                deltaT0 = 0;                            
                        }
                        
                        if (deltaT1 >= 250)
                        {
                                final String fps =
                                        Integer.toString((int)(1000 * fps_cnt / deltaT1));
                                
                                setText(osdFps, " " + fps + " fps ");
                                                                
                                fps_cnt=0;
                                deltaT1 = 0;
                        }
                }
                setText(osdState, "");
                setText(osdFps, "");
        }

XverhelstX
 

XverhelstX

Well-Known Member
Licensed User
Longtime User
Could it have to do with the holders?

B4X:
public CameraView ( Context context,
                                        Camera camera,
                                        Display display,
                                        FrameLayout osd,
                                        FrameLayout border,
                                        Settings settings       )
    { 
        super(context);
        mCamera = camera;
        mDisplay = display;
        mOSD = osd;
        mBorder = border;
        mSettings = settings;
        
        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

It's the only likely thing to cause.

XverhelstX
 
Top