Frage

Ich schreibe eine Android 1.5-Anwendung, die gerade nach dem Start-up beginnt. Dies ist ein Service und soll ein Bild ohne Vorschau nehmen. Diese App wird die Lichtdichte in einigen Bereichen log was auch immer. Ich war in der Lage ein Bild zu machen, aber das Bild war schwarz.

Nach langer Zeit erforscht, stieß ich auf einen Bug-Thread darüber. Wenn Sie nicht über eine Vorschau erzeugen, wird das Bild schwarz sein, da Android Kameravorschau einrichten Belichtung und Fokus muss. Ich habe ein SurfaceView und den Hörer geschaffen, aber das onSurfaceCreated() Ereignis wird nie ausgelöst.

Ich denke, der Grund ist, wird die Oberfläche optisch nicht erstellt werden. Ich habe auch einige Beispiele für den Aufruf der Kamera statisch mit MediaStore.CAPTURE_OR_SOMETHING gesehen, die ein Bild aufnimmt und speichert in den gewünschten Ordner mit zwei Zeilen Code, aber es ist nicht ein Bild machen zu.

Benötige ich IPC und bindService() verwenden, um diese Funktion aufzurufen? Oder gibt es eine alternative Methode, um dies zu erreichen?

War es hilfreich?

Lösung

Es ist wirklich seltsam, dass die Kamera auf Android-Plattform nicht Video streamen kann, bis sie gültige Vorschau Oberfläche gegeben. es scheint, dass die Architekten der Plattform nicht über 3rd-Party-Video-Anwendungen an allen Streaming dachten. auch für Augmented Reality Fall kann das Bild als eine Art visueller Substitution präsentiert wird, nicht in Echtzeit Kamera-Stream.

Wie auch immer, können Sie einfach Resize-Vorschau Oberfläche zu 1x1 Pixeln und legen es irgendwo in der Ecke des Widgets (visuellen Elements). Beachten -. Resize-Vorschau Oberfläche, nicht Kamerarahmengröße

natürlich solchen Trick nicht beseitigt unerwünschte Daten-Streaming (für Vorschau), die einige Systemressourcen und Batterie verbraucht.

Andere Tipps

fand ich die Antwort auf diese Frage in der Android Kamera Docs .

  

Hinweis: Es ist möglich, MediaRecorder zu verwenden, ohne eine Kamera zu schaffen   Vorschau erste und überspringen die ersten Schritte dieses Prozesses. Jedoch,   da die Nutzer bevorzugen normalerweise eine Vorschau zu sehen, bevor ein Start   Aufzeichnung, dieser Prozess wird hier nicht diskutiert.

Sie können die Anweisungen Schritt für Schritt auf den Link oben finden. Nach den Anweisungen, wird es das Zitat sagen, dass ich oben zur Verfügung gestellt habe.

Eigentlich ist es möglich, aber Sie haben zu fälschen die Vorschau mit einem Dummy Surface

SurfaceView view = new SurfaceView(this);
c.setPreviewDisplay(view.getHolder());
c.startPreview();
c.takePicture(shutterCallback, rawPictureCallback, jpegPictureCallback);

Update 9/21/11:. Offenbar dies nicht funktioniert für jedes Android-Gerät

Unter dem Photo

Erhalten Sie diese Arbeit zuerst, bevor Sie die Vorschau zu verbergen.

  • korrekt konfiguriert die Vorschau
    • Verwenden Sie ein SurfaceView (Pre-Android-4.0-Kompatibilität) oder SurfaceTexture (Android 4+ kann transparent gemacht werden)
    • Set und initialisieren, bevor Sie das Foto aufnehmen
    • Warten Sie auf die SurfaceView des SurfaceHolder (via getHolder()) zu berichten surfaceCreated() oder die TextureView zu Bericht onSurfaceTextureAvailable seiner SurfaceTextureListener vor der Einstellung und die Vorschau initialisiert.
  • die Vorschau Stellen Sie sicher, ist sichtbar:
    • Fügen Sie es dem WindowManager
    • Stellen Sie sicher, das Layout Größe mindestens 1x1 Pixel (möglicherweise, indem es beginnen soll MATCH_PARENT x MATCH_PARENT zum Testen)
    • Stellen Sie sicher, seine Sichtbarkeit ist View.VISIBLE (was die Standardeinstellung zu sein scheint, wenn Sie es nicht angeben)
    • Stellen Sie sicher, Sie FLAG_HARDWARE_ACCELERATED im LayoutParams verwenden, wenn es sich um eine TextureView ist.
  • Verwenden Sie takePicture die JPEG Rückruf, da die Dokumentation sagt die anderen Rückrufe werden nicht von allen Geräten unterstützt

Fehlerbehebung

  • Wenn surfaceCreated / onSurfaceTextureAvailable nicht genannt bekommt, die SurfaceView / TextureView wahrscheinlich nicht angezeigt wird.
  • Wenn takePicture ausfällt, zunächst sicherstellen, dass die Vorschau korrekt funktioniert. Sie können Ihren takePicture Anruf zu entfernen und lassen Sie die Vorschau läuft, um zu sehen, ob es auf dem Bildschirm angezeigt werden.
  • Wenn das Bild dunkler ist als es sein sollte, könnte man etwa eine Sekunde verzögern, müssen vor dem Aufruf takePicture, so dass die Kamera eine gewisse Zeit seine Belichtung einzustellen hat, sobald die Vorschau begonnen hat.

Ausblenden der Vorschau

  • Machen Sie die Vorschau View 1x1 Größe ihre Sichtbarkeit zu minimieren ( oder versuchen 8x16 für möglicherweise mehr Zuverlässigkeit )

    new WindowManager.LayoutParams(1, 1, /*...*/)
    
  • Bewegen Sie die Vorschau aus dem Zentrum seiner Wahrnehmbarkeit zu reduzieren:

    new WindowManager.LayoutParams(width, height,
        Integer.MIN_VALUE, Integer.MIN_VALUE, /*...*/)
    
  • Machen Sie die Vorschau transparent (nur für TextureView)

    WindowManager.LayoutParams params = new WindowManager.LayoutParams(
        width, height, /*...*/
        PixelFormat.TRANSPARENT);
    params.alpha = 0;
    

Arbeitsbeispiel (getestet auf Sony Xperia M, Android 4.3)

/** Takes a single photo on service start. */
public class PhotoTakingService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();
        takePhoto(this);
    }

    @SuppressWarnings("deprecation")
    private static void takePhoto(final Context context) {
        final SurfaceView preview = new SurfaceView(context);
        SurfaceHolder holder = preview.getHolder();
        // deprecated setting, but required on Android versions prior to 3.0
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        holder.addCallback(new Callback() {
            @Override
            //The preview must happen at or after this point or takePicture fails
            public void surfaceCreated(SurfaceHolder holder) {
                showMessage("Surface created");

                Camera camera = null;

                try {
                    camera = Camera.open();
                    showMessage("Opened camera");

                    try {
                        camera.setPreviewDisplay(holder);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }

                    camera.startPreview();
                    showMessage("Started preview");

                    camera.takePicture(null, null, new PictureCallback() {

                        @Override
                        public void onPictureTaken(byte[] data, Camera camera) {
                            showMessage("Took picture");
                            camera.release();
                        }
                    });
                } catch (Exception e) {
                    if (camera != null)
                        camera.release();
                    throw new RuntimeException(e);
                }
            }

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

        WindowManager wm = (WindowManager)context
            .getSystemService(Context.WINDOW_SERVICE);
        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                1, 1, //Must be at least 1x1
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                0,
                //Don't know if this is a safe default
                PixelFormat.UNKNOWN);

        //Don't set the preview visibility to GONE or INVISIBLE
        wm.addView(preview, params);
    }

    private static void showMessage(String message) {
        Log.i("Camera", message);
    }

    @Override public IBinder onBind(Intent intent) { return null; }
}

Auf Android 4.0 und höher (API-Ebene> = 14), können Sie TextureView zur Vorschau des Kamerastrom und unsichtbar so machen, wie um zu zeigen, es nicht an den Benutzer. Hier ist, wie:

Zuerst eine Klasse erstellen, um eine SurfaceTextureListener zu implementieren, die erstellen / aktualisieren Rückrufe für die Vorschau Oberfläche erhalten. Diese Klasse nimmt auch eine Kameraobjekt als Eingabe, so dass es die startPreview Funktion, sobald die Kamera aufrufen können, da die Oberfläche erstellt wird:

public class CamPreview extends TextureView implements SurfaceTextureListener {

  private Camera mCamera;

  public CamPreview(Context context, Camera camera) {
    super(context);
    mCamera = camera;
   }

  @Override
  public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
    Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
    setLayoutParams(new FrameLayout.LayoutParams(
        previewSize.width, previewSize.height, Gravity.CENTER));

    try{
      mCamera.setPreviewTexture(surface);
     } catch (IOException t) {}

    mCamera.startPreview();
    this.setVisibility(INVISIBLE); // Make the surface invisible as soon as it is created
  }

  @Override
  public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
      // Put code here to handle texture size change if you want to
  }

  @Override
  public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
    return true;
  }

  @Override
  public void onSurfaceTextureUpdated(SurfaceTexture surface) {
      // Update your view here!
  }
}

Sie finden auch eine Callback-Klasse implementieren, müssen die Vorschaudaten zu verarbeiten:

public class CamCallback implements Camera.PreviewCallback{
  public void onPreviewFrame(byte[] data, Camera camera){
     // Process the camera data here
  }
}

Verwenden Sie die oben CamPreview und CamCallback Klassen-Setup der Kamera in der Tätigkeit des onCreate () oder ähnliche Startfunktion:

// Setup the camera and the preview object
Camera mCamera = Camera.open(0);
CamPreview camPreview = new CamPreview(Context,mCamera);
camPreview.setSurfaceTextureListener(camPreview);

// Connect the preview object to a FrameLayout in your UI
// You'll have to create a FrameLayout object in your UI to place this preview in
FrameLayout preview = (FrameLayout) findViewById(R.id.cameraView); 
preview.addView(camPreview);

// Attach a callback for preview
CamCallback camCallback = new CamCallback();
mCamera.setPreviewCallback(camCallback);

Es gibt einen Weg, dies zu tun, aber es ist etwas schwierig. was getan werden sollte, ist ein surfaceholder an den Fenstermanager aus dem Dienst anhängen

WindowManager wm = (WindowManager) mCtx.getSystemService(Context.WINDOW_SERVICE);
params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
            WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
            PixelFormat.TRANSLUCENT);        
wm.addView(surfaceview, params);

und setzen

surfaceview.setZOrderOnTop(true);
mHolder.setFormat(PixelFormat.TRANSPARENT);

wo mHolder ist der Halter Sie von der Oberfläche Ansicht zu erhalten.

Auf diese Weise können Sie mit der Surfacealpha spielen, ist es völlig transparent machen, aber die Kamera noch Frames erhalten.

das ist, wie ich es tun. hoffe, es hilft:)

Wir lösen dieses Problem, indem ein Dummy-Surface (nicht zu tatsächlichen GUI hinzugefügt) in Versionen vor 3.0 (oder sagen wir mal 4.0 als Kamera-Dienst auf einem Tablet nicht wirklich Sinn macht). In Versionen> = 4.0 dies nur im Emulator gearbeitet; ( Die Verwendung von SurfaceTexture (und setSurfaceTexture ()) anstelle von Surface (und setSurfaceView ()) arbeitete hier. Mindestens diese Werke auf dem Nexus S.

Ich denke, das ist wirklich ein Manko des Android-Framework ist.

In der "Arbeitsbeispiel von Sam" (Danke Sam ...)

Wenn bei istruction "wm.addView (Vorschau, params);"

erhält Ausnahme „Können Fenster android.view.ViewRoot hinzufügen - Erlaubnis für diesen Fenstertyp verweigert“

lösen, indem diese Berechtigung in AndroidManifest mit:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

Sie können versuchen, diese Arbeit an, und dieser Service Front Bild klicken, wenn Sie Capture zurück Kamerabild wollen, dann uncomment backCamera in Code und Kommentar frontCamera.

Hinweis: - Lassen Sie die Kamera und Speicher Erlaubnis App und den Start von Aktivität oder überall.

public class MyService extends Service {

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        CapturePhoto();
    }

    private void CapturePhoto() {

        Log.d("kkkk","Preparing to take photo");
        Camera camera = null;

        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();

            int frontCamera = 1;
            //int backCamera=0;

            Camera.getCameraInfo(frontCamera, cameraInfo);

            try {
                camera = Camera.open(frontCamera);
            } catch (RuntimeException e) {
                Log.d("kkkk","Camera not available: " + 1);
                camera = null;
                //e.printStackTrace();
            }
            try {
                if (null == camera) {
                    Log.d("kkkk","Could not get camera instance");
                } else {
                    Log.d("kkkk","Got the camera, creating the dummy surface texture");
                     try {
                         camera.setPreviewTexture(new SurfaceTexture(0));
                        camera.startPreview();
                    } catch (Exception e) {
                        Log.d("kkkk","Could not set the surface preview texture");
                        e.printStackTrace();
                    }
                    camera.takePicture(null, null, new Camera.PictureCallback() {

                        @Override
                        public void onPictureTaken(byte[] data, Camera camera) {
                            File pictureFileDir=new File("/sdcard/CaptureByService");

                            if (!pictureFileDir.exists() && !pictureFileDir.mkdirs()) {
                                pictureFileDir.mkdirs();
                            }
                            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyymmddhhmmss");
                            String date = dateFormat.format(new Date());
                            String photoFile = "ServiceClickedPic_" + "_" + date + ".jpg";
                            String filename = pictureFileDir.getPath() + File.separator + photoFile;
                            File mainPicture = new File(filename);

                            try {
                                FileOutputStream fos = new FileOutputStream(mainPicture);
                                fos.write(data);
                                fos.close();
                                Log.d("kkkk","image saved");
                            } catch (Exception error) {
                                Log.d("kkkk","Image could not be saved");
                            }
                            camera.release();
                        }
                    });
                }
            } catch (Exception e) {
                camera.release();
            }
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top