Java Question Need to understand some Java Code

XverhelstX

Well-Known Member
Licensed User
Longtime User
Actually, I don't think it calls onPreviewFrame.

When I do this code:

B4X:
public synchronized byte[] getPicture(int Width, int Height) throws InterruptedException {
      FrameWidth = Width;
      FrameHeight = Height;
      try {

         Log.i("B4A", "Try Mode.");
         // while (!isPreviewOn) wait();
         Log.i("B4A", "IsPreviewOn is True");
         isDecoding = true;

         Log.i("B4A", "Decoding is true.");

         c.setOneShotPreviewCallback(this);

         Log.i("B4A", "Callback Done.");
         wait(5000);
         Log.i("B4A", "Outside isDecoding.");
      } catch (Exception e) {
         Log.i("B4A", "An error occured.");
         return null;
      }
      
      return mCurrentFrame;

   }

I get this in B4A log:

** Activity (main) Create, isFirst = true **


** Activity (main) Resume **


Try Mode.


IsPreviewOn is True
Decoding is true.
Callback Done.
i is : 0
Outside isDecoding.

<<<--------------- Waits 5 seconds here. (this text is not displayed in B4A)
main_mnufocusmode_click (java line: 287)



java.lang.NullPointerException
at anywheresoftware.b4a.agraham.byteconverter.ByteConverter.HexFromBytes(ByteConverter.java:237)
at com.rootsoft.streamnationstudio.main._mnufocusmode_click(main.java:287)
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.BA.raiseEvent(BA.java:88)
at com.rootsoft.streamnationstudio.main$B4AMenuItemsClickListener.onMenuItemClick(main.java:117)
at com.android.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:137)
at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:855)
at com.android.internal.view.menu.IconMenuView.invokeItem(IconMenuView.java:532)
at com.android.internal.view.menu.IconMenuItemView.performClick(IconMenuItemView.java:122)
at android.view.View$PerformClick.run(View.java:9210)
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.

I will clean up library first and upload it.
Thank you very much for looking into it Agraham!

XverhelstX
 

agraham

Expert
Licensed User
Longtime User
I may have found the problem. It is a sort of deadlock. From the documentation for Camera.PreviewCallback onPreviewFrame.

Called as preview frames are displayed. This callback is invoked on the event thread open(int) was called from.

The callback can't run because the thread it wants to run on is blocked in getPicture. The application you took that code from presumably calls getPicture from a different thread than the one that opened the camera. Your best bet is probably to let getPicture return and raise an event at the end of onPreviewFrame. As it runs on the main thread it looks like you can use raiseEvent rather than raiseEventFromDifferentThread.
 

XverhelstX

Well-Known Member
Licensed User
Longtime User
I may have found the problem. It is a sort of deadlock. From the documentation for Camera.PreviewCallback onPreviewFrame.



The callback can't run because the thread it wants to run on is blocked in getPicture. The application you took that code from presumably calls getPicture from a different thread than the one that opened the camera.

Yes, Main.java calls currentJPEG = cameraFrame.getPicture(); from CameraView.java.

Your best bet is probably to let getPicture return and raise an event at the end of onPreviewFrame. As it runs on the main thread it looks like you can use raiseEvent rather than raiseEventFromDifferentThread.

Is there any documentation on ba.raiseEvent(null, eventName + "_ready", true);? As I don't know what all these things mean: "readyCount.addAndGet(1) == 2" etc.

And how I should retrieve the data with camera_ready2.

I really appreciate your effort in this.

XverhelstX
 

agraham

Expert
Licensed User
Longtime User
Is there any documentation on ba.raiseEvent(null, eventName + "_ready", true);?
No but
public Object raiseEvent(Object sender, String event, Object[] params)
The first parameter is the object returned by Sender in the event Sub. The second is the lowercase name of the Sub to invoke, the third is an array of Objects corresponding to the parameters the event Sub requires, if any. The return Object is the return value of the Sub

So I'd do something like
raiseEvent(this, eventName + "_somename", Object[] = { mCurrentFrame });

for the event Sub
Sub camera_somename(picture as Byte())

As I don't know what all these things mean: "readyCount.addAndGet(1) == 2" etc
I don't know what that means either. Where is it from?
 
Last edited:

XverhelstX

Well-Known Member
Licensed User
Longtime User
Oh, Ok.
So I don't have to raise the event in Basic4Android?
It's in Eclipse itself(?)

B4X:
@SuppressWarnings("static-access")
   public void Initialize(final BA ba, ViewGroup Panel, String EventName) {
      this.ba = ba;
      readyCount.set(0);
      this.eventName = EventName.toLowerCase(BA.cul);
      sv = new SurfaceView(ba.context);
      anywheresoftware.b4a.BALayout.LayoutParams lp = new anywheresoftware.b4a.BALayout.LayoutParams(
            0, 0, Panel.getLayoutParams().width,
            Panel.getLayoutParams().height);
      Panel.addView(sv, lp);
      if (c != null) {
         readyCount.set(1);
      }

      sv.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
      sv.getHolder().setFixedSize(Panel.getLayoutParams().width,
            Panel.getLayoutParams().height);

      sv.getHolder().addCallback(new SurfaceHolder.Callback() {

         @Override
         public void surfaceChanged(SurfaceHolder holder, int format,
               int width, int height) {

         }

         @Override
         public void surfaceCreated(SurfaceHolder holder) {

            if (readyCount.addAndGet(1) == 2) {
               ba.raiseEvent(null, eventName + "_ready", true);

            }
         }

This is from readyCount.addAndGet(1) == 2" etc

and raiseEvent(this, eventName + "_somename", Object[] = { mCurrentFrame });

doesn't seem to work but

raiseEvent(this, eventName + "_somename", mCurrentFrame );

does.

Any other thing I should do/ know?

So I now have something like this:

B4X:
public void getPicture(int Width, int Height){
      FrameWidth = Width;
      FrameHeight = Height;
      try {

         Log.i("B4A", "Try Mode.");
         
         Log.i("B4A", "IsPreviewOn is True");
         isDecoding = true;

         Log.i("B4A", "Decoding is true.");

         c.setOneShotPreviewCallback(this);

         Log.i("B4A", "Callback Done.");
         
         
         
         Log.i("B4A", "Outside isDecoding.");
      } catch (Exception e) {
               Log.i("B4A", "An error occured.");
         return;
      }
      
      return;

   }

   @Override
   public void onPreviewFrame(byte[] data, Camera camera) {
      
         Log.i("B4A", "In onPreviewFrame");
      int width = FrameWidth;
      int height = FrameHeight;

      int[] temp = new int[width * height];
      OutputStream out = new ByteArrayOutputStream();
      Bitmap bm = null;
         Log.i("B4A", "Initialize raw2jpg");
      raw2jpg(temp, data, width, height);
      bm = Bitmap.createBitmap(temp, width, height, Bitmap.Config.RGB_565);
      bm.compress(CompressFormat.JPEG, 100, out);
      mCurrentFrame = ((ByteArrayOutputStream) out).toByteArray();

      isDecoding = false;
         Log.i("B4A", "isDecoding false");
         
         ba.raiseEvent(null, eventName + "_previewtaken", mCurrentFrame);
        
}

XverhelstX
 

agraham

Expert
Licensed User
Longtime User
Sorry but I don't understand what your problem is with "This is from readyCount.addAndGet(1) == 2" etc" but it has nothing to do with events.


and raiseEvent(this, eventName + "_somename", Object[] = { mCurrentFrame });

doesn't seem to work but

raiseEvent(this, eventName + "_somename", mCurrentFrame );
If that's working its because your event Sub takes no parameters so mCurrentFrame is being ignored. Parameters have to be passed in an Object array as I stated.
 

XverhelstX

Well-Known Member
Licensed User
Longtime User
Don't worry at the readycount, I thought it had to do something with it.
I showed it because you asked where I saw that.

I have this error:
"Syntax error on tokens, EnumHeader expected instead"
here:
ba.raiseEvent(this, eventName + "_previewtaken", Object[] = { mCurrentFrame });



Also in B4A, My sub is:
Sub Camera1_PreviewTaken (Picture As Byte(), Byte As String)
but I cannot seem to execute it.
byte is not a valid identifier.
Occurred on line: 81
Sub Camera1_PreviewTaken (Picture As Byte(), Byte As String)

Note that I added this:

B4X:
@Events(values = { "Ready (Success As Boolean)",
      "PictureTaken (Data() As Byte)","PreviewTaken (Picture as Byte())" })
 

XverhelstX

Well-Known Member
Licensed User
Longtime User
probably this:
B4X:
ba.raiseEvent(null, eventName + "_previewtaken", new Object[] { mCurrentFrame });

This is probably correct, Although, Everything seems to work except Camera1_PreviewTaken (Data() As Byte) is not called.

B4X:
@Events(values = { "Ready (Success As Boolean)","PictureTaken (Data() As Byte)","PreviewTaken (Data() As Byte)" })


public void getPicture(int Width, int Height){
      FrameWidth = Width;
      FrameHeight = Height;
      try {

         Log.i("B4A", "Try Mode.");
         
         Log.i("B4A", "IsPreviewOn is True");
         isDecoding = true;

         Log.i("B4A", "Decoding is true.");

         c.setOneShotPreviewCallback(this);

         Log.i("B4A", "Callback Done.");
         
         
         
         Log.i("B4A", "Outside isDecoding.");
      } catch (Exception e) {
               Log.i("B4A", "An error occured.");
         return;
      }
      
      return;

   }

   @Override
   public void onPreviewFrame(byte[] data, Camera camera) {
      
         Log.i("B4A", "In onPreviewFrame");
      int width = FrameWidth;
      int height = FrameHeight;

      int[] temp = new int[width * height];
      OutputStream out = new ByteArrayOutputStream();
      Bitmap bm = null;
         Log.i("B4A", "Initialize raw2jpg");
      raw2jpg(temp, data, width, height);
      bm = Bitmap.createBitmap(temp, width, height, Bitmap.Config.RGB_565);
      bm.compress(CompressFormat.JPEG, 100, out);
      mCurrentFrame = ((ByteArrayOutputStream) out).toByteArray();

      isDecoding = false;
         Log.i("B4A", "isDecoding false");
         
         ba.raiseEvent(null, eventName + "_previewtaken", data);
        
}

B4A
B4X:
Sub mnuFocusMode_Click

Msgbox("Getting Picture.","")

camera1.getPicture(480,320)
's = b.HexFromBytes(camera1.getPicture(480,320))

Msgbox("s","")
   
End Sub

Sub Camera1_PreviewTaken (Data() As Byte)

Msgbox("on Preview Taken","")   

s = b.HexFromBytes(Data)

Msgbox(s,"")
   
End Sub
 

Attachments

  • StreamNation.zip
    30.1 KB · Views: 351
Last edited:

XverhelstX

Well-Known Member
Licensed User
Longtime User
Hey,

Is it the .jar and .xml?
Could you upload the java file to?
As I don't see what I have to enter exactly:

sub Camera1_Preview

end sub

As I want something like this:

B4X:
Sub Camera1_PreviewTaken (Success As Boolean, Data() as Byte, PictureFrame as Byte)
' As I want something to play with the success and Data bytes too.
End Sub

XverhelstX



XverhelstX
 

XverhelstX

Well-Known Member
Licensed User
Longtime User
Isn't it another file?

At the events tag shouldn't be some more things added there?
@Events(values = { "Ready (Success As Boolean)",
"PictureTaken (Data() As Byte)" })

and how can I add more things like Succes boolean, data in that array?

XverhelstX
 

agraham

Expert
Licensed User
Longtime User
Why should there be another file? That Java file as it stands will compile to a library and raise an event. The rest is up to you.

The @Events attribute is only needed for IDE Intellisense support, I assumed you could do that.

To add parameters to the event just include them in the parameter Object array.

B4X:
ba.raiseEvent(this, eventName + "_previewtaken", new Object[] { success, mCurrentFrame, pictureFrame } );
}
Sigh! I really don't know why I bother at times :(
 

XverhelstX

Well-Known Member
Licensed User
Longtime User
Why should there be another file? That Java file as it stands will compile to a library and raise an event. The rest is up to you.

The @Events attribute is only needed for IDE Intellisense support, I assumed you could do that.

To add parameters to the event just include them in the parameter Object array.

B4X:
ba.raiseEvent(this, eventName + "_previewtaken", new Object[] { success, mCurrentFrame, pictureFrame } );
}
Sigh! I really don't know why I bother at times :(


Ok, I didn't know that that was for the IDE Intellisense support.
So I copied your java file, pasted it on my library, compiled it into .jar and .xml, putted it in my library folder, refreshed the tab: did the following code:

B4X:
Sub mnuFocusMode_Click

Msgbox("Getting Picture.","")

camera1.getPicture(480,320)
's = b.HexFromBytes(camera1.getPicture(480,320))

Msgbox("s","")
   
End Sub

Sub Camera1_PreviewTaken(mCurrentFrame() As Byte)

Msgbox("on Preview Taken","")   

s = b.HexFromBytes(mCurrentFrame)

Msgbox(s,"")
   
End Sub

getting Picture and S appear
but Camera1_PreviewTaken is not called...

XverhelstX
 
Last edited:
Top