Вопрос

Я пишу приложение для Android 1.5, которое запускается сразу после загрузки.Это настоящий Service и должен сделать снимок без предварительного просмотра.Это приложение будет регистрировать плотность освещенности в любых областях.Мне удалось сделать снимок, но снимок был черным.

После долгих поисков я наткнулся на сообщение об ошибке по этому поводу.Если вы не создадите предварительный просмотр, изображение будет черным, поскольку Android camera нуждается в предварительном просмотре для настройки экспозиции и фокусировки.Я создал SurfaceView и слушатель, но тот, кто onSurfaceCreated() событие никогда не запускается.

Я предполагаю, что причина в том, что поверхность не создается визуально.Я также видел несколько примеров статического вызова камеры с помощью MediaStore.CAPTURE_OR_SOMETHING который делает снимок и сохраняет в нужной папке с двумя строками кода, но сам снимок тоже не делает.

Нужно ли мне использовать IPC и bindService() как вызвать эту функцию?Или есть альтернативный метод для достижения этой цели?

Это было полезно?

Решение

действительно странно, что камера на платформе Android не может транслировать видео до тех пор, пока ей не будет предоставлена допустимая поверхность предварительного просмотра.похоже, что архитекторы платформы вообще не думали о сторонних приложениях для потокового видео.даже в случае дополненной реальности изображение может быть представлено как своего рода визуальная замена, а не поток камеры в реальном времени.

в любом случае, вы можете просто измените размер поверхности предварительного просмотра до 1x1 пикселя и поместите его где-нибудь в углу виджета (визуальный элемент).пожалуйста, обратите внимание - измените размер поверхности предварительного просмотра, а не кадра камеры.

конечно, такой трюк не устраняет нежелательную потоковую передачу данных (для предварительного просмотра), которая потребляет некоторые системные ресурсы и батарею.

Другие советы

Я нашел ответ на это в Документы камеры Android.

Примечание: можно использовать MediaRecorder Не создавая предварительный просмотр камеры сначала и пропустите первые несколько шагов этого процесса. Однако, поскольку пользователи обычно предпочитают видеть предварительный просмотр перед записью записи, этот процесс здесь не обсуждается.

Вы можете найти пошаговые инструкции по ссылке выше. После инструкции он будет указывать цитату, которую я предоставил выше.

На самом деле это возможно, но вы должны подделать предварительный просмотр с пустой поверхности

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

Обновление 9/21/11: Видимо, это не работает для каждого устройства Android.

Принимать фото

Получите эту работу сначала, прежде чем пытаться скрыть предварительный просмотр.

  • Правильно настроить предварительный просмотр
    • Использовать SurfaceView (совместимость до Android-4.0) или SurfaceTexture (Android 4+, может быть сделан прозрачным)
    • Установите и инициализируйте его, прежде чем принимать фото
    • Ждать SurfaceViewС. SurfaceHolder (через getHolder()) сообщить surfaceCreated() или TextureView сообщить onSurfaceTextureAvailable его SurfaceTextureListener перед настройкой и инициализацией предварительного просмотра.
  • Убедитесь, что предварительный просмотр виден:
    • Добавьте его в WindowManager
    • Убедитесь, что его размер макета составляет не менее 1x1 пикселей (вы можете начать, сделав его MATCH_PARENT Икс MATCH_PARENT для тестирования)
    • Убедитесь, что его видимость View.VISIBLE (который, кажется, по умолчанию, если вы не укажете его)
    • Убедитесь, что вы используете FLAG_HARDWARE_ACCELERATED в LayoutParams Если это TextureView.
  • Использовать takePictureJPEG Callback После документации говорит, что другие обратные вызовы не поддерживаются на всех устройствах

Поиск проблемы

  • Если surfaceCreated/onSurfaceTextureAvailable не звонит, SurfaceView/TextureView вероятно, не отображается.
  • Если takePicture Не удается, сначала убедитесь, что предварительный просмотр работает правильно. Вы можете удалить свой takePicture Вызовите и позволяйте предварительному просмотру, чтобы увидеть, отображается ли он на экране.
  • Если картинка темнее, чем должна быть, вам может потребоваться отложить около секунды до вызова takePicture Так что у камеры есть время, чтобы настроить его воздействие после начала предварительного просмотра.

Скрытие предварительного просмотра

  • Сделать предварительный просмотр View Размер 1x1, чтобы минимизировать его видимость (или попробуйте 8x16 для возможно больше надежности)

    new WindowManager.LayoutParams(1, 1, /*...*/)
    
  • Переместите предварительный просмотр из центра, чтобы уменьшить его заметность:

    new WindowManager.LayoutParams(width, height,
        Integer.MIN_VALUE, Integer.MIN_VALUE, /*...*/)
    
  • Сделать предварительный просмотр прозрачным (работает только для TextureView)

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

Рабочий пример (проверено на 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; }
}

На Android 4.0 и выше (уровень API> = 14) вы можете использовать TextureView. Для предварительного просмотра потока камеры и сделайте его невидимым, чтобы не показать его пользователю. Вот как:

Сначала создайте класс для реализации SORFACETTEXTURELISTENER, который получит обратные вызовы Create / Update для поверхности предварительного просмотра. Этот класс также принимает объект камеры в качестве ввода, так что он может вызвать функцию запуска камеры, как только поверхность создана:

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!
  }
}

Вам также необходимо будет реализовать класс обратного вызова для обработки данных предварительного просмотра:

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

Используйте вышеупомянутые классы CampreView и Camcallback для настройки камеры в функции OnCreate () или аналогичного запуска ():

// 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);

Есть способ сделать это, но это несколько сложно. Что должно быть сделано, прикрепите запястье для оконного менеджера от службы

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);

а потом установить

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

где Mollerer - это держатель, который вы получаете от поверхности.

Таким образом, вы можете играть с альфа SurfaceView, сделайте его полностью прозрачным, но камера все равно получит кадры.

Вот как я это делаю. Надеюсь, поможет :)

Мы решали эту проблему, используя пустышку поверхности (не добавляемые к фактическому графическому интерфейсу) в версиях ниже 3.0 (или скажем, 4.0 в качестве службы камеры на планшете на самом деле не имеет смысла). В версиях> = 4.0 это работало только в эмуляторе; (использование SurfaceTexture (и setsurFaceture (и setsurfaceTexture ()) вместо SurveyView (и setsurfaceView ()) работало здесь. По крайней мере, это работает на Nexus S.

Я думаю, что это действительно недолго о структуре Android.

В «Работом примере Сэма» (спасибо Сэм ...)

Если на Istruction "wm.addview (предварительный просмотр, параметры);"

Получить исключение «Невозможно добавить окно Android.View.Viewroot - разрешение запрещено для этого типа окна»

Разрешите с помощью этого разрешения в AndroidManifest:

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

Вы можете попробовать этот рабочий код, этот сервис нажимает на переднюю картинку, если вы хотите захватить картинку задней камеры, то безответная обратная кровать в коде и комментарии FrontCamera.

ПРИМЕЧАНИЕ. - Разрешить разрешение камеры и хранения на приложение и запуск услуг из активности или где угодно.

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();
            }
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top