Android Programming with Camera framework API - android

New to android programming, writing an application that continuously streams image from camera and do some operation on and post the result on screen. My camera class is separate from the main activity class. I have a queue for captured images, two threads that reads and writes to the queue. I am having problems possibly with the initializations. I am not sure if I am using the CameraPreview correctly.
Here is my code.
public class Goggle extends Activity{
ImageQueue imageQueue = new ImageQueue();
ImageCapture capture;
private ThreadProcess thread;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.video);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
......
capture = new ImageCapture(this,imageQueue);
capture.start();
thread = new ThreadProcess();
thread.start();
}
private class ThreadProcess extends Thread {
...
}
}
public class ImageCapture extends Thread implements Camera.PreviewCallback{
private ImageQueue imageQueue;
private ImageUInt8 image;
private Activity parent;
private CameraPreview mPreview;
private Camera mCamera;
public ImageCapture (Activity parnt, ImageQueue queue) {
this.parent = parnt;
this.imageQueue = queue;
mPreview = new CameraPreview(parent,this,true);
FrameLayout preview = (FrameLayout) parent.findViewById(R.id.camera_preview);
preview.addView(mPreview);
setUpAndConfigureCamera();
}
/**
* Called each time a new image arrives in the data stream.
*/
#Override
public void onPreviewFrame(byte[] bytes, Camera camera) {
// convert from NV21 format into gray scale
synchronized (lockImage) {
ConvertNV21.nv21ToGray(bytes,image.width,image.height,image);
}
}
#Override
public void run() {
while (true) {
synchronized (lockImage) {
ImageData imageData = new ImageData(image);
imageQueue.pushImage(imageData);
}
notifyAll();
}
}
}

Related

Getting thread result in another activity for Android

My Main Activity invokes ResultActivity and at the same time invokes a Runnable thread. I want that Result activity doesn't wait for some part of result processing (Image) which may be provided later by thread and UI may be updated accordingly.
What I've tried to do is given below.
MainActivity (below method is actually a callback from another thread):
#Override
public void onCreate(Context context) {
resultImageProcessor = new ResultImageProcessor();
resImgProThread = new Thread(resultImageProcessor);
}
#Override
public void onBarcodeDetected(final Barcode barcode) {
resultImageProcessor.setCameraBarcode(mCameraSource,barcode);
resImgProThread.start();
Intent intent = new Intent(this, ResultActivity.class);
intent.putExtra(BarcodeObject, barcode);
intent.putExtra(ResultCode, CommonStatusCodes.SUCCESS);
intent.putExtra(ResImgProcObject, resultImageProcessor);
startActivity(intent);
}
Result Image Processor:
public class ResultImageProcessor implements Serializable, Runnable {
private ResultActivity resultActivityContext;
ResultImageProcessor(){
this.resultActivityContext = null;
}
public void setResultActivity(ResultActivity resultActivity) {
this.resultActivityContext = resultActivity;
}
public void setCameraBarcode(CameraSource cameraSource, Barcode barCode){
mCameraSource = cameraSource;
barcode = barCode;
}
#Override
public void run() {
String picPath = ProcessImage(Obj..Attributes);
//wait until result activity context is not set
while(resultActivityContext == null){
try {
sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
resultActivityContext.onImageSaved(picPath);
}
}
Result Activity:
protected void onCreate(Bundle savedInstanceState) {
//...
data = getIntent();
Barcode barcode = data.getParcelableExtra(MainActivity.BarcodeObject);
ResultImageProcessor resultImageProcessor = data.getParcelableExtra(MainActivity.ResImgProcObject);
resultImageProcessor.setResultActivity(this);
}
//called from Result image processor
public void onImageSaved(String imagePath){
ImageView barImgView = findViewById(R.id.barcode_image);
Bitmap barcodeImage = BitmapFactory.decodeFile(imagePath);
barImgView.setImageBitmap(barcodeImage);
barImgView.invalidate();
}
With the above code, after invoking resultImageProcessor.startProcessing(), result activity is not launched nor runnable's run() method keeps busy in while loop. I traced them using logger. When I skip threading and pass image path to activity, everything goes fine beside being slow for activity switching.
Please indicate the problem or suggest better solution.
i think you are missing run in your runnable like this
new Runnable() {
#Override
public void run() {
String picPath = ProcessImage(Obj..Attributes);
//wait until result activity context is not set
while(resultActivityContext == null){}
resultActivityContext.onImageSaved(picPath);
}
}.run();
It turned out that the problem was in passing ResultImageProcessor object to ResultActivity intent as Parcelable. I followed a simple path of declaring resultActivityContext as static in ResultImageProcessor.
public class ResultImageProcessor implements Runnable {
public static ResultActivity resultActivityContext;
...
#Override
public void run() {
...
resultActivityContext.onImageSaved(picPath);
resultActivityContext = null;
}
}
and in ResultActivity:
ResultImageProcessor.resultActivityContext = this;

Adapt camera view with Surfaceview dimension

I'm developing an application where I read some barcode. In a first step I had a big SurfaceView where I can see well the camera preview, but now I would set the dimensions of Surfaceview like the dimensions of barcode but I have bad camera visualization (it is too small). Can someone help me to stretch camera preview? Thanks
Here manage detector and surfaceview:
public class LettoreBarcode extends Fragment {
View view;
SurfaceView surfaceView;
Handler handler;
private BarcodeDetector detector;
private CameraSource cameraSource;
private TextView code;
SparseArray<Barcode> items;
private static Button btnBack;
String barcode = "" ;
SparseArray<Articoli> groups = new SparseArray<Articoli>();
Context _context = null;
ProductsAdapter.ViewHolder _ViewHolder = null;
public LettoreBarcode(){
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_barcode_scanner, container, false);
surfaceView = (SurfaceView) view.findViewById(R.id.surfaceView);
detector = new BarcodeDetector.Builder(getActivity()).setBarcodeFormats(Barcode.ALL_FORMATS).build();
final Dialog d = new Dialog(getActivity());
btnBack = (Button) view.findViewById(R.id.btnBack);
handler = new Handler();
if(!detector.isOperational()){
Toast.makeText(getActivity(), "Detector non attivabile", Toast.LENGTH_LONG).show();
}
cameraSource = new CameraSource.Builder(getActivity(), detector).setAutoFocusEnabled(true).build();
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
AttivaCamera();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
});
detector.setProcessor(new Detector.Processor<Barcode>() {
#Override
public void release() {
}
#Override
public void receiveDetections(Detector.Detections<Barcode> detections) {
items = detections.getDetectedItems();
if (items.size() > 0){
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
if (items.valueAt(0) != null){
//do something
handler.postDelayed(new Runnable() {
#Override
public void run() {
DisattivaCamera();
}
},10); //1000
}else
{
d.setContentView(R.layout.dialog_barcode_assente);
d.setTitle("Scanner");
d.setCancelable(true);
d.show();
DisattivaCamera();
}
}
});
}
}
});
btnBack.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
getActivity().onBackPressed();
}
});
return view;
}
private void AttivaCamera()
{
try{
cameraSource.start(surfaceView.getHolder());
}catch(IOException e){
Toast.makeText(getActivity(), "Errore nell'avvio della fotocamera", Toast.LENGTH_LONG).show();
}
}
private void DisattivaCamera()
{
cameraSource.stop();
}
}
It is how I visualize camera with small surfaceview:
https://i.stack.imgur.com/TMunJ.png
I'm new in android development so I'm sorry if could be a lot of mistake in the code.
Sorry for my english also..
Thanks you guys!
In order to display only part of the camera input, i.e. to crop it on the screen, you need a surface view that has dimensions that fit the camera frame aspect ratio, and overlay it with some nontransparent views to leave only part of it visible. Don't put the SurfaeView inside scrolling layout:
So, instead of
<SurfaceView width: match_parent height: 400dp />
you need e.g. FrameLayout as explained here: Is it possible to crop camera preview?
This will not change the frame that arrives to the barcode detector. But this should not worry you; the detector will handle the uncropped image correctly.

All threads get suspended

I am building an app which will continuously get screenshots of my laptop screen and transfer it to my android app but there is some problem within the while loop, when I put a for loop to a limit then my program runs but as it goes till infinity or I replace it with infinite while loop my code suspends all the threads and app crash dueto memory allocation problem, please suggest me to execute my code infinite times so that there are continuous screenshots displayed.
Thank You.
Here is my code
public class ScreenActivity extends AppCompatActivity {
ImageView img;
int width,height;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screen);
img=(ImageView)findViewById(R.id.imageView);
Display display = getWindowManager().getDefaultDisplay();
width = display.getWidth();
height = display.getHeight();
// while (true)
for (int i=0;i<100;i++)
new GetImg().execute();
}
Bitmap imgscr;
public class GetImg extends AsyncTask<Object,Void,Bitmap> {
#Override
protected Bitmap doInBackground(Object[] params) {
Socket client= null;
try {
client = new Socket("192.168.1.5",6767);
InputStream in=client.getInputStream();
imgscr=Bitmap.createScaledBitmap(BitmapFactory.decodeStream(in), width, height, false);
} catch (Exception e) {
e.printStackTrace();
}
return imgscr;
}
#Override
protected void onPostExecute(Bitmap bm)
{
img.setImageBitmap(bm);
}
}
}
#m0skit0 commented the actual reason of getting the ANR. You're out of your run-time memory when you're creating threads in an infinite loop. I'm pretty confused about your purpose though. I think you need to get the screenshots one after one and if this is the case, you can simply add a listener to the AsyncTask and get the callback when the screenshot is downloaded fully.
So if I've understood correctly, you need to declare an interface like this.
public interface DownloadCompletedListener {
public void onDownloadComplete(String result);
}
Now you need to implement the interface in your Activity like this
public class ScreenActivity extends AppCompatActivity implements DownloadCompletedListener {
private GetImg getImageTask;
private Bitmap imageBitmap;
#Override
public void onDownloadComplete(String result) {
if(result.equals("SUCCESS")) {
// Set the image now
img.setImageBitmap(imageBitmap);
// Start next download here
getImageTask = new GetImg();
getImageTask.mListener = this;
getImageTask.execute();
} else {
// Do something
}
}
}
You need to modify your AsyncTask a bit. You need to declare the DownloadCompletedListener.
public class GetImg extends AsyncTask<Object,Void,Bitmap> {
private DownloadCompletedListener mListener;
#Override
protected Bitmap doInBackground(Object[] params) {
Socket client= null;
try {
client = new Socket("192.168.1.5",6767);
InputStream in=client.getInputStream();
imgscr=Bitmap.createScaledBitmap(BitmapFactory.decodeStream(in), width, height, false);
} catch (Exception e) {
e.printStackTrace();
}
return imgscr;
}
#Override
protected String onPostExecute(Bitmap bm)
{
imageBitmap = bm;
mListener.onDownloadComplete("SUCCESS");
}
}
So your onCreate function will look like this now
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screen);
img=(ImageView)findViewById(R.id.imageView);
Display display = getWindowManager().getDefaultDisplay();
width = display.getWidth();
height = display.getHeight();
// Start downloading image here. Remove the loop
getImageTask = new GetImg();
getImageTask.mListener = this;
getImageTask.execute();
}

Android: Why do I have to use runOnUIThread() Here?

I am working on a simple game with graphics using Open GL. I want it so that when a certain event happens, the player gets a point, and this updates a textview overlaying the GLSurfaceView on the game activity.
Thanks in advance!
Here are the relevant parts of my code:
The Activity:
public class playActivity extends Activity {
private GLSurfaceView myGLView;
private Handler mGameHandler;
private TextView mScoreView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mScoreView = new TextView(this);
mScoreView.setTextColor(0xFF00FF00); // Green
string myZeroString = "0";
mScoreView.setText(myZeroString); //Starting score will always be 0
mGameHandler = new Handler(){
public void handleMessage(Message msg){
if (msg.what == MyGLRenderer.GAME_SCORE_FLAG) {
int score = msg.arg1;
mScoreView.setText(Integer.toString(score));
}
}
};
myGLView = new MyGLSurfaceView(this);
setContentView(myGLView);
addContentView(mScoreView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
private void updateScoreBoard(int score){
mScoreView.setText(Integer.toString(score));
}
class MyGLSurfaceView extends GLSurfaceView{
private final MyGLRenderer myRenderer;
public MyGLSurfaceView(Context context){
super(context);
// Create an OpenGL ES 2.0 context
setEGLContextClientVersion(2);
myRenderer = new MyGLRenderer(context);
myRenderer.initiateHandler(mGameHandler);
// Set the Renderer for drawing on the GLSurfaceView
setRenderer(myRenderer);
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
}
}
}
And the GlSurfaceView.Renderer:
public class MyGLRenderer implements GLSurfaceView.Renderer{
public static final int GAME_SCORE_FLAG = 1;
private Handler mGameHandler = null;
private int mScore = 0;
public void initiateHandler(Handler handler){
mGameHandler = handler;
}
...
#Override
public void onDrawFrame(GL10 unused){
if (scoreCondition){
mScore += 1;
if (mGameHandler != null) {
int flag = MyGLRenderer.GAME_SCORE_FLAG;
mGameHandler.dispatchMessage(Message.obtain(mGameHandler, flag, 2));
}
}
}
}
When I run this, it gives me the error:
"android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views."
However, in the top chunk of code, when I replace
int score = msg.arg1;
mScoreView.setText(Integer.toString(score));
with
final int score = 3;
runOnUiThread(new Runnable() {
#Override
public void run() {
mScoreView.setText(Integer.toString(score));
}
});
I no longer get the error and it works. I thought that in the first construction that when I called setText that it would have to be performed on the UI thread, but Android Studio thinks differently. Can anyone explain this to me? Thanks!
Change:
mGameHandler.dispatchMessage(Message.obtain(mGameHandler, flag, 2));
to:
mGameHandler.sendMessage(Message.obtain(mGameHandler, flag, 2));
Calling dispatchMessage() will cause the message to be delivered on the current thread (which is the GL thread in your case.)

showNoCameraAlert error

I am creating a flashlight app. In my code, if camera(hardware) is there, it should show an alert, but it does not show the alert. My code is as below:
if (!isCameraFlash) {
showNoCameraAlert();
} else {
camera = Camera.open();
params = camera.getParameters();
}
but i get an error on
showNoCameraAlert();
Is this an invalid tag? or the tutorial i am using is old? I am using android studio. Here is my full Java code:
public class MainActivity extends ActionBarActivity {
private Camera camera;
ImageButton flashlightSwitchImg;
private boolean isFlashlightOn;
Parameters params;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
flashlightSwitchImg = (ImageButton) findViewById(R.id.flashlightSwitch);
boolean isCameraFlash = getApplicationContext().getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
if (!isCameraFlash) {
showNoCameraAlert();
} else {
camera = Camera.open();
params = camera.getParameters();
}
}
}
Any help will be appreciated. Thanks :)
You are calling the showNoCameraAlert() method. You need to add it to your MainActivity (that is the file where you put the code in.) So add it like this:
private void showNoCameraAlert(){
Toast.makeText(getApplicationContext(), "Camera flashlight not available in this Android device!", Toast.LENGTH_SHORT).show();
}
The full code for your MainActivity:
package com.example.administrator.flashlight;
import ...;
public class MainActivity extends ActionBarActivity {
private Camera camera;
ImageButton flashlightSwitchImg;
private boolean isFlashlightOn;
Parameters params;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
flashlightSwitchImg = (ImageButton) findViewById(R.id.flashlightSwitch);
//check if phone has a flashlight
boolean isCameraFlash = getApplicationContext().getPackageManager() .hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)
if (!isCameraFlash) {
//show error ( showNoCamereAlert() is below)
showNoCameraAlert();
} else {
//open the camera
camera = Camera.open();
params = camera.getParameters();
}
}
private void showNoCameraAlert(){
//Show Error toast
Toast.makeText(getApplicationContext(), "Camera flashlight not available in this Android device!", Toast.LENGTH_SHORT).show();
}
}
I'm starting to think that you didn't implement the showNoCameraAlert() method.
Try adding something like this to your MainActivity class:
private void showNoCameraAlert(){
Toast.makeText(getApplicationContext(), "There's no camera on the device or it doesn't have a flash", Toast.LENGTH_SHORT).show();
}

Categories

Resources