Android: Asynctask della camera con Preview Callback

Sono riuscito a visualizzare l'anteprima della telecamera con il filter personalizzato (in scala di grigi, tonalità, ecc.). Questo filter personalizzato viene applicato con la richiamata in anteprima manipolando l'arrays di RGB e poi riportndolo a una canvas, quindi visualizzandolo alla vista di superficie.

Lo svantaggio da questo è che ottengo un FPS molto basso. Con questo FPS basso, sta facendo troppo lavoro nel thread UI se non lo faccio nel thread di background utilizzando Asynctask. Così ho cercato di utilizzare Asynctask per l'operazione della camera (il mio objective principale è quello di get l'UI ancora funzionante perfettamente anche con il lavoro pesante dalla chiamata in anteprima della camera).

  • Differenza tra add () e replace () con il ciclo di vita di Fragment
  • getClass () in class astratta dà una chiamata a methods ambigui
  • Che cosa è il carattere 0x1f?
  • Convalida del numero di telefono Android
  • Impostare lo background del menu per essere opaco
  • Geocodifica inversa in Android con evento touch
  • Ma anche dopo che ho usato Asynctask, non ha aiutato molto. Quindi mi chiedo se la mia implementazione è sbagliata o è perché anche con asynctask il thread dell'interface utente resterà ancora influenzato?

    Il frammento del mio codice è sotto:

    CameraActivity.java

    public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d("ACTIVITY_LIFECYCLE","CameraActivity: onCreate"); setContentView(R.layout.camera_layout); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) @Override protected void onResume() { Log.d("ACTIVITY_LIFECYCLE","CameraActivity: onResume"); if(preview == null){ preview = new CameraPreviewAsync(this,camera); preview.execute(); } super.onResume(); } @Override protected void onPause() { Log.d("ACTIVITY_LIFECYCLE","CameraActivity: onPause"); if(preview!=null){ preview.cancel(true); camera = preview.getCamera(); if(camera!=null){ camera.stopPreview(); camera.setPreviewCallback(null); camera.release(); camera = null; preview.setCamera(camera); } preview = null; } super.onPause(); } @Override public void onDestroy(){ Log.d("ACTIVITY_LIFECYCLE","CameraActivity: onDestroy"); super.onDestroy(); } 

    CameraPreviewAsync.java:

     private final String TAG = "CameraPreviewAsync"; private CameraActivity camAct; private Camera mCamera; private int cameraId; private SurfaceView mSurfaceView; private SurfaceHolder mHolder; private boolean isPreviewRunning = false; private int[] rgbints; private int width; private int height; private Bitmap mBitmap; public CameraPreviewAsync(CameraActivity act, Camera cam){ this.camAct = act; this.mCamera = cam; this.mSurfaceView = (SurfaceView) act.findViewById(R.id.surfaceView); } public void resetSurface(){ if(mCamera!=null){ mCamera.stopPreview(); mCamera.setPreviewCallback(null); mCamera.release(); mCamera = null; } int tempId = R.id.surfaceView; RelativeLayout buttonBar = (RelativeLayout) camAct.findViewById(R.id.buttonBar); ((RelativeLayout) camAct.findViewById(R.id.preview)).removeAllViews(); SurfaceView newSurface = new SurfaceView(camAct); newSurface.setId(tempId); RelativeLayout.LayoutParams layParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); layParams.alignWithParent = true; newSurface.setLayoutParams(layParams); ((RelativeLayout) camAct.findViewById(R.id.preview)).addView(newSurface); ((RelativeLayout) camAct.findViewById(R.id.preview)).addView(buttonBar); } @Override protected void onPreExecute() { //Things to do before doInBackground executed Log.d(TAG,"onPreExecute"); RelativeLayout.LayoutParams layParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); layParams.alignWithParent = true; mSurfaceView.setLayoutParams(layParams); //Check number of camera in the device, if less than 2 then remove swap button if (Camera.getNumberOfCameras() < 2) { ((RelativeLayout) camAct.findViewById(R.id.buttonBar)).removeViewAt(R.id.cameraSwap); } //Opening the camera cameraId = findBackFacingCamera(); if (cameraId < 0) { cameraId = findFrontFacingCamera(); if (cameraId < 0) Toast.makeText(camAct, "No camera found.", Toast.LENGTH_LONG).show(); else mCamera = Camera.open(cameraId); } else { mCamera = Camera.open(cameraId); } //invalidate the menu bar and show menu appropriately camAct.invalidateOptionsMenu(); // get Camera parameters and set it to Auto Focus if(mCamera!=null){ Camera.Parameters params = mCamera.getParameters(); List<String> focusModes = params.getSupportedFocusModes(); if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) { // set the focus mode params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); // set Camera parameters mCamera.setParameters(params); } } super.onPreExecute(); } @Override protected Void doInBackground(Void... params) { //Things to do in the background thread Log.d(TAG,"doInBackground"); mHolder = mSurfaceView.getHolder(); mHolder.addCallback(surfaceCallback); return null; } @Override protected void onPostExecute(Void values) { //Things to do after doInBackground Log.d(TAG,"onPostExecute"); } @Override protected void onCancelled(){ super.onCancelled(); } /* * ************************************************************************************ * SURFACEHOLDER CALLBACK * ************************************************************************************ */ SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { Log.d(TAG,"surfaceCreated!!"); if(CameraActivity.filterMode == CameraActivity.NORMAL_FILTER){ try { if (mCamera != null) { mCamera.startPreview(); mCamera.setPreviewDisplay(holder); }else{ Log.d(TAG,"CAMERA IS NULL in surfaceCreated!!"); } } catch (IOException exception) { Log.e(TAG, "IOException caused by setPreviewDisplay()", exception); } }else{ synchronized(mSurfaceView){ if(isPreviewRunning){ return; }else{ mSurfaceView.setWillNotDraw(false); if(mCamera!=null){ isPreviewRunning = true; Camera.Parameters p = mCamera.getParameters(); List<Size> sizes = p.getSupportedPreviewSizes(); Size size = p.getPreviewSize(); width = size.width; height = size.height; p.setPreviewFormat(ImageFormat.NV21); showSupportedCameraFormats(p); mCamera.setParameters(p); rgbints = new int[width * height]; mCamera.startPreview(); mCamera.setPreviewCallback(previewCallback); } } } } } @Override public void surfaceDestroyed(SurfaceHolder holder) { Log.d(TAG,"surfaceDestroyed!"); if(CameraActivity.filterMode == CameraActivity.NORMAL_FILTER){ if (mCamera != null) { mCamera.stopPreview(); isPreviewRunning = false; } }else{ synchronized(mSurfaceView){ if(mCamera!=null){ mCamera.setPreviewCallback(null); mCamera.stopPreview(); isPreviewRunning = false; } } } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Log.d(TAG,"surfaceChanged!"); } }; /* * ************************************************************************************ * CAMERA PREVIEW CALLBACK * ************************************************************************************ */ Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() { @Override public void onPreviewFrame(byte[] data, Camera camera) { if (!isPreviewRunning) return; Canvas resCanvas = null; if (mHolder == null) { return; } try { synchronized (mHolder) { resCanvas = mHolder.lockCanvas(null); int resCanvasW = resCanvas.getWidth(); int resCanvasH = resCanvas.getHeight(); if(mBitmap == null){ mBitmap = Bitmap.createBitmap (width, height, Bitmap.Config.ARGB_8888); } decodeYUV(rgbints, data, width, height); Canvas canvas = new Canvas(mBitmap); //Setting the filter if(camAct.getCustomFilter().equalsIgnoreCase("NORMAL")) ;//don't change the rgb value if(camAct.getCustomFilter().equalsIgnoreCase("GRAYSCALE")) rgbints = grayscale(rgbints); if(camAct.getCustomFilter().equalsIgnoreCase("INVERT")) rgbints = invert(rgbints); if(camAct.getCustomFilter().equalsIgnoreCase("BOOSTRED")) rgbints = boostColor(rgbints,1); if(camAct.getCustomFilter().equalsIgnoreCase("BOOSTGREEN")) rgbints = boostColor(rgbints,2); if(camAct.getCustomFilter().equalsIgnoreCase("BOOSTBLUE")) rgbints = boostColor(rgbints,3); if(camAct.getCustomFilter().equalsIgnoreCase("NOISE")) rgbints = noise(rgbints); if(camAct.getCustomFilter().equalsIgnoreCase("HUE")) rgbints = hue(rgbints); if(camAct.getCustomFilter().equalsIgnoreCase("SATURATION")) rgbints = saturation(rgbints); if(camAct.getCustomFilter().equalsIgnoreCase("ENGRAVE")) rgbints = engrave(rgbints); if(camAct.getCustomFilter().equalsIgnoreCase("EMBOSS")) rgbints = emboss(rgbints); // draw the decoded image, centered on canvas canvas.drawBitmap(rgbints, 0, width, 0,0, width, height, false, null); resCanvas.drawBitmap (mBitmap, resCanvasW-((width+resCanvasW)>>1), resCanvasH-((height+resCanvasH)>>1),null); } } catch (Exception e){ e.printStackTrace(); } finally { // do this in a finally so that if an exception is thrown // during the above, we don't leave the Surface in an // inconsistent state if (resCanvas != null) { mHolder.unlockCanvasAndPost(resCanvas); } } } }; 

    Ogni aiuto è molto apprezzato! 🙂 Grazie in anticipo ragazzi!

  • Come posso aggiungere file .so a un progetto della libreria Android utilizzando gradle 0.7+
  • Come mantenere la posizione di scorrimento Android ListView quando si torna ad un'attività?
  • FB login Android
  • Condividere le credenziali Wifi tramite il tag NFC senza applicazioni speciali
  • Streaming da M3U su Android
  • C'è un modo per aggiungere parametro di query a each richiesta con Retrofit 2?
  • 3 Solutions collect form web for “Android: Asynctask della camera con Preview Callback”

    Le richiami da altri methods vengono consegnati al ciclo dell'evento del thread che si chiama open (). Se questo thread non ha un ciclo di events, i richiami vengono consegnati al ciclo di events principale dell'applicazione. Se non esiste un ciclo di events di applicazione principale, i richiami non vengono consegnati. fonte

    Forse la mia risposta è troppo tardi per te, ma stavo studiando lo stesso argomento in modo da pensare di condividere le mie scoperte comunque …

    Prima di tutto, se l'apertura di Camera viene chiamata sull'AsyncTask e poi quel thread esiste e si blocca per esistere – non possiamo realmente aspettarci che le chiamate da esso provengano, possiamo. Quindi, se vogliamo callbacks – allora dobbiamo avere un thread che vivi per alless fino a quando vogliamo i nostri callback.

    Ma aspetta, c'è più … Documentazione per Camera.PreviewCallback non è la più chiara, ma uno dei cattivi suggerimenti è che questo "richiamata viene richiamato sul thread di evento aperto (int) è stato chiamato da". Cosa significa per thread di "evento"? Beh, non è molto chiaro – ma guardando il codice Android e sperimentando – quello di cui hanno bisogno è un thread che contiene un Looper. Probabilmente troppi dettagli, ma nel constructor della camera (chiamato dal metodo aperto) c'è il codice che cerca di get un Looper del thread corrente, se non esiste – cerca di get looper del thread principale – che vive Thread UI. La camera utilizza un gestore per submit chiamate e altri methods tramite il looper che inizializza così. Ora puoi probabilmente capire perché stavi ricevendo la tua chiamata sul thread principale anche se hai aperto la camera da un thread diverso – il tuo thread di lavoratore non aveva un looper – quindi la camera ha preso in considerazione l'utilizzo di quello principale.

    Ho ricevuto richiami che lavorano dal mio thread di lavoro per il quale ho usato HandlerThread in un metodo lungo queste righe:

     private void startCamera() { if (mCameraThread == null) { mCameraThread = new HandlerThread(CAMERA_THREAD_NAME); mCameraThread.start(); mCameraHandler = new Handler(mCameraThread.getLooper()); } mCameraHandler.post(new Runnable() { @Override public void run() { try { mCamera = Camera.open(); 

    Ho usato il debugger per confermare che il mio onPreviewFrame ha funzionato sul thread del lavoratore. Ho anche avuto animation in esecuzione su thread UI, che era scantovy prima che ho passato elaborazione canvasio lontano dal thread principale, ma ora è liscia come il burro.

    Prendi nota, che se uccidi il tuo thread di lavoratore, allora naturalmente le tue richieste si fermeranno e la camera (meglio di Handler) si lamenterà di cercare di utilizzare il thread morto.

    BTW, come soluzione alternativa, naturalmente potrebbe avere richiamate il callback sul thread principale, ma l'elaborazione dei dati frame potrebbe essere delegata a un thread separato.

    Suppongo che la tua implementazione utilizzando AsyncTask è errata:

    Secondo la documentazione , le chiamate della Camera vengono richiamate sul thread chiamato open() . E così è la callback onPreviewFrame . (Quindi non è vero che onPreviewFrame sia sempre eseguito sul thread principale.)

    Si apre la camera nel metodo onPreExecute () di AsyncTask, che viene richiamato sul thread UI e non sul thread di background come probabilmente si prevede e quindi il richiamo della camera viene eseguito sul thread principale.

    Suppongo che si dovrebbe aprire la camera nel metodo doInBackground() di doInBackground() .

    L'Android è un fan Android di Google, tutto su telefoni Android, Android Wear, Android Dev e applicazioni Android Games e così via.