我写安卓1.5应用程序开始后启动。这是一个 Service 应该采取一个画预览。这个程序将日志的光密度在某些领域无论。我能拍张照片但是黑人。

研究后很长一段时间,我遇到了一个错误的线。如果你不产生预览的图像将会是黑色的,因为安卓摄像机的需求的预设置曝光和重点。我已经创建了一个 SurfaceView 以及监听器,但是 onSurfaceCreated() 事件永远不会被解雇。

我猜测的原因是,表面上是不是正在创建的。我也看到一些实例的呼吁相机的静态 MediaStore.CAPTURE_OR_SOMETHING 这需要一个照片并保存在所需的文件夹,带有两个线的代码,但它并不需要一张图片。

我需要使用IPC和 bindService() 以这个叫功能?或者是否有替代方法来实现这一目标?

有帮助吗?

解决方案

这是非常奇怪的是,直到它给出有效的预览水面摄像机Android平台上不能流视频。看来,平台的设计者并没有考虑过第三方视频流的所有应用程序。甚至用于增强现实情况下,图象可以被呈现为某种视觉取代,不实时相机流的

反正,可以简单的调整大小预览表面以1x1像素的并把它在某处微件(可视元素)的拐角处。请注意 - 大小调整预览表面,而不是照相机帧大小

当然,这种特技的不能消除不需要的数据流(预览)消耗一些系统资源和电池。

其他提示

我发现这个问题的答案在 Android相机文档

  

请注意:可以使用MediaRecorder而不创建相机   预览第一,跳过此过程的前几个步骤。然而,   因为用户通常更喜欢在开始之前看到的预览   记录,这里不讨论该过程。

可以找到在上面的链接的分步说明。指令后,它会指出我在上面提供的报价。

其实这是可能的,但你必须假以虚拟SurfaceView

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

<强>更新11年9月21日:显然,这并不对每个Android装置工作

把照片

得到这个工作之前,首先试图隐藏的预览。

  • 正确地设立了预览
    • 使用 SurfaceView (pre-安卓-4.0兼容性)或 SurfaceTexture (安卓4+的,可以作出透明)
    • 设置和初始化它之前的照片
    • 等待 SurfaceView's SurfaceHolder (通过 getHolder())报告 surfaceCreated()TextureView 报告 onSurfaceTextureAvailable 它的 SurfaceTextureListener 以前设置和初始化的预览。
  • 确保预览是可见的:
    • 它添加到 WindowManager
    • 确保其布局的尺寸至少为1×1素(你可能会想要开始通过使它 MATCH_PARENT x MATCH_PARENT 用于测试)
    • 确保它的可见性 View.VISIBLE (这似乎是默认,如果你不指定)
    • 确保你使用 FLAG_HARDWARE_ACCELERATEDLayoutParams 如果它是一个 TextureView.
  • 使用 takePicture's JPEG回,因为该文件说的其他回不支持在所有的设备

排除故障

  • 如果 surfaceCreated/onSurfaceTextureAvailable 没有得到所谓的 SurfaceView/TextureView 可能不是正在显示出来。
  • 如果 takePicture 失败时,首先确保预览的正常工作。你可以去除你的 takePicture 打电话,让预览运行以看到,如果它显示在屏幕上。
  • 如果图片暗比它应该是,可能需要延迟大约一秒钟之前的呼叫 takePicture 因此,该照相机有时间调整其暴露后的预览已经开始。

隐藏的预览

  • 使预览 View 1×1大小,以尽量减少其可见性(或者试试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;
    

工作实例(上测试无M,机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 预览相机流,使其不可见,从而它不能显示给用户。方法如下:

首先,创建一个类来实现一个SurfaceTextureListener将获得创建/更新回调预览表面。该类还需要一个相机对象作为输入,使得它可以调用相机的startPreview功能一旦创建了表面:

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

有是这样做的方式,但它是有点棘手。 什么应该做的,是从服务附加surfaceholder窗口管理

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

其中mHolder是您从表面视图得到的持有人。

这种方式,你可以用surfaceview的alpha发挥,使之完全地透明,但相机仍然会得到帧。

这就是我要做的事。希望它有助于:)

我们用下3.0版本的虚拟SurfaceView(不添加到实际GUI)解决了这个问题(或假设4.0的平板电脑上摄像头的服务并没有真正意义)。 在版本> = 4.0这个工作只在模拟器;( 使用表面纹理(和setSurfaceTexture()),而不是SurfaceView(和setSurfaceView())的在这里工作。至少这个作品在Nexus S上。

我认为这真的是Android框架的一个缺点。

在 “山姆工作实施例”(谢谢你萨姆...)

如果在istruction “wm.addView(预览,则params);”

获得异常“无法添加窗口android.view.ViewRoot - 许可被拒绝此窗口类型”

通过在AndroidManifest使用该权限决心:

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

您可以试试这个工作的代码,该服务单击前面的画面,如果你想捕捉背部摄像头的画面,然后在代码和注释frontCamera取消注释backCamera。

请注意: - 允许从活动或任何相机和存储权限APP和startService。

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