在后台 Android 中使用相机

Posted

技术标签:

【中文标题】在后台 Android 中使用相机【英文标题】:Using the camera in Background Android 【发布时间】:2013-09-09 05:01:17 【问题描述】:

我正在尝试将照片从相机中投入使用。

@Override
public void onCreate() 
    super.onCreate();
    //android.os.Debug.waitForDebugger();

    myCamera=Camera.open();


      SurfaceView dummy=new SurfaceView(getApplicationContext());
    try 
        if(myCamera!=null)
        
            myCamera.setPreviewDisplay(dummy.getHolder());
            myCamera.setPreviewCallback(this);
            Log.i(TAG,"myCamera is not null");
        
            getFrames();

     catch (IOException e) 
        // TODO Auto-generated catch block
        e.printStackTrace();
        Log.e(TAG, "setPreviewDisplay " + e);
        
    myCamera.startPreview(); 



    public void getFrames() 

        new Thread(new Runnable() 

            public void run() 

                    while(flag)
                    
                        Log.i(TAG, "getFrames");
                        try

                            //method();
                        takePictureNoPreview();
                        Thread.sleep(54);

                         catch (Exception e) 
                            Log.e(TAG, "getFrames thread error: " + e);
                        
                    
                     myCamera.release();  

            
        ).start();
    


public void takePictureNoPreview()
            try
              Log.i(TAG,"takePictureNoPreview");
              myCamera.takePicture(null, null, getJpegCallback())
             catch (Exception e) 
                Log.e(TAG, "takePictureNoPreview " + e);
            


     private PictureCallback getJpegCallback()
                PictureCallback jpeg=new PictureCallback()    
                  @Override
                  public void onPictureTaken(byte[] data, Camera camera) 
                    try 
                      Log.i(TAG,"getJpegCallback");
                      FileOutputStream(String.format("/sdcard/RealSpeaker/%d.jpg", System.currentTimeMillis()));
                      FileOutputStream os = new FileOutputStream(String.format("/sdcard/Sample/%d.jpg", System.currentTimeMillis()));
                         os.write(data);
                         os.close();
                      catch (IOException e) 
                      //do something about it
                    
                  
                ;
                return jpeg;

              

问题是getJpegCallback周围的方法不正确:(文件夹中没有日志和图像)ю 当我调试应用程序时,TAG - getJpegCallback 不会显示在 LogCat 中,但 TAG takePictureNoPreview 会显示。关闭应用程序后,相机不允许(现在没问题)。怎么了?

【问题讨论】:

我的经验是,我需要在布局中使用实际的 SurfaceView 来拍照,所以我添加了一个高度=20dp 和 marginTop=-100dp 的 SurfaceView 或其他东西来“移动它”看不见”,但它仍然存在于布局中。也许你应该尝试这样的事情。另一个思路是:不应该在回调的surfaceCreated/Changed方法中调用setPreviewDisplay和startPreview吗? 好的。我正在尝试第一个变体 您是否要在后台录制视频 【参考方案1】:

我在开发EyeSpy 时遇到了这个问题。即使应用程序在背景或前景中,我也想捕捉图像。我尝试了几个星期,但没有运气。使用相机拍摄照片意味着显示其预览。

From Document(5. 和 6.) 你必须使用SurfaceView 来显示预览。

当您关闭应用程序或您的应用程序进入后台时,SurfaceView 的表面将被破坏。这就是为什么我认为这是不可能的。

如果您发现任何其他方式,请在此处发布。

希望对你有所帮助..

【讨论】:

你尝试过这样的事情吗? -> -> 显示自定义“警报窗口”,没有内容,只有一个表面视图(不可见或屏幕外某处),使用这个作为预览显示? -> ***.com/questions/7678356/… @damian 感谢您告诉我..我今天早上试了一下,它成功了...我会在我的应用程序上试一试。 你有没有机会扩展代码来完成这个?我弹出了“测试测试测试”语言,但没有 FCing 就无法让相机运行。【参考方案2】:

从 API 11 开始,您可以使用 SurfaceTexture,而不是使用 SurfaceViewSurfaceHolder。然后,您使用Camera.setPreviewTexture 而不是Camera.setPreviewDisplay 进行设置。

在不同设备上的服务对我来说效果很好。

This 回答以及this one 讨论这一点。

【讨论】:

【参考方案3】:
public class TakePicture extends Activity implements SurfaceHolder.Callback 
    // a variable to store a reference to the Image View at the main.xml file
    // private ImageView iv_image;
    // a variable to store a reference to the Surface View at the main.xml file
    private SurfaceView sv;

    // a bitmap to display the captured image
    private Bitmap bmp;
    FileOutputStream fo;

    // Camera variables
    // a surface holder
    private SurfaceHolder sHolder;
    // a variable to control the camera
    private Camera mCamera;
    // the camera parameters
    private Parameters parameters;
    private String FLASH_MODE;
    private boolean isFrontCamRequest = false;
    private Camera.Size pictureSize;

    /** Called when the activity is first created. */
    @SuppressWarnings("deprecation")
    @Override
    public void onCreate(Bundle savedInstanceState)
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // check if this device has a camera
        if (checkCameraHardware(getApplicationContext())) 
        
            // get the Image View at the main.xml file
            // iv_image = (ImageView) findViewById(R.id.imageView);

            // get the Surface View at the main.xml file
            Bundle extras = getIntent().getExtras();
            String flash_mode = extras.getString("FLASH");
            FLASH_MODE = flash_mode;
            boolean front_cam_req = extras.getBoolean("Front_Request");
            isFrontCamRequest = true;


            System.out.println("front_cam_req :"+front_cam_req);
            sv = (SurfaceView) findViewById(R.id.camera_preview);

            // Get a surface
            sHolder = sv.getHolder();

            // add the callback interface methods defined below as the Surface
            // View
            // callbacks
            sHolder.addCallback(this);

            // tells Android that this surface will have its data constantly
            // replaced
            if (Build.VERSION.SDK_INT < 11)
                sHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        
        else 
            // display in long period of time
            Toast.makeText(getApplicationContext(),
                    "Your Device dosen't have a Camera !", Toast.LENGTH_LONG)
                    .show();
        

    

    /** Check if this device has a camera */
    private boolean checkCameraHardware(Context context) 
        if (context.getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_CAMERA)) 
            // this device has a camera
            return true;
         else 
            // no camera on this device
            return false;
        
    

    /** Check if this device has front camera */
    private boolean checkFrontCamera(Context context) 
    
        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) 
        
            // this device has front camera
            return true;
         
        else
        
            // no front camera on this device
            return false;
        
    

    public static Camera getCameraInstance()
    
        Camera c = null;
        try 
            c = Camera.open(); // attempt to get a Camera instance
         catch (Exception e) 
            // Camera is not available (in use or does not exist)
        
        return c; // returns null if camera is unavailable
    

    @Override
    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) 
        // get camera parameters
        if (mCamera != null) 
            parameters = mCamera.getParameters();
            if (FLASH_MODE == null || FLASH_MODE.isEmpty()) 
                FLASH_MODE = "auto";
            
            parameters.setFlashMode(FLASH_MODE);
            pictureSize = getBiggesttPictureSize(parameters);
            if (pictureSize != null)
                parameters
                        .setPictureSize(pictureSize.width, pictureSize.height);
            // set camera parameters
            mCamera.setParameters(parameters);

            mCamera.startPreview();

            // sets what code should be executed after the picture is taken
            Camera.PictureCallback mCall = new Camera.PictureCallback() 
                @Override
                public void onPictureTaken(byte[] data, Camera camera) 
                    // decode the data obtained by the camera into a Bitmap
                    Log.d("ImageTakin", "Done");

                    bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
                    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
                    if (bmp != null)
                        bmp.compress(Bitmap.CompressFormat.JPEG, 100, bytes);

                    File imagesFolder = new File(
                            Environment.getExternalStorageDirectory(),
                            "OneSheeld");
                    if (!imagesFolder.exists())
                        imagesFolder.mkdirs(); // <----
                    File image = new File(imagesFolder,
                            System.currentTimeMillis() + ".jpg");

                    // write the bytes in file
                    try 
                        fo = new FileOutputStream(image);
                     catch (FileNotFoundException e) 
                        // TODO Auto-generated catch block
                    
                    try 
                        fo.write(bytes.toByteArray());
                     catch (IOException e) 
                        // TODO Auto-generated catch block
                    

                    // remember close de FileOutput
                    try 
                        fo.close();
                        sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
                                Uri.parse("file://"
                                        + Environment
                                                .getExternalStorageDirectory())));

                     catch (IOException e) 
                        // TODO Auto-generated catch block
                    
                    if (mCamera != null) 
                        mCamera.stopPreview();
                        // release the camera
                        mCamera.release();
                    
                    Toast.makeText(getApplicationContext(),
                            "Your Picture has been taken !", Toast.LENGTH_LONG)
                            .show();
                    if (bmp != null) 
                        bmp.recycle();
                        bmp = null;
                        System.gc();
                    
                    TakePicture.this.finish();

                
            ;

            mCamera.takePicture(null, null, mCall);
        
    

    @Override
    public void surfaceCreated(SurfaceHolder holder)
    
        // The Surface has been created, acquire the camera and tell it where
        // to draw the preview.
        if (isFrontCamRequest)
        

            //Toast.makeText(getApplicationContext()," isFrontCamRequest()",Toast.LENGTH_LONG).show();

            System.out.println("isFrontCamRequest 1");
            // set flash 0ff
            FLASH_MODE = "off";
            // only for gingerbread and newer versions
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD)
            
                System.out.println("isFrontCamRequest 2");
                mCamera = openFrontFacingCameraGingerbread();
                try 
                    mCamera.setPreviewDisplay(holder);

                 catch (IOException exception) 
                    mCamera = null;
                    Toast.makeText(getApplicationContext(),"API dosen't support front camera",Toast.LENGTH_LONG).show();
                    TakePicture.this.finish();
                
            
            else 
            
                System.out.println("isFrontCamRequest 3");
                if (checkFrontCamera(getApplicationContext()))
                
                    mCamera = openFrontFacingCameraGingerbread();
                    try
                    
                        mCamera.setPreviewDisplay(holder);

                    
                    catch (IOException exception)
                    
                        mCamera = null;
                        Toast.makeText(getApplicationContext(),
                                "API dosen't support front camera",
                                Toast.LENGTH_LONG).show();
                        TakePicture.this.finish();
                    
                /*
                 * else  // API dosen't support front camera or no front camera
                 * Log.d("Camera",
                 * "API dosen't support front camera or no front camera");
                 * Toast.makeText( getApplicationContext(),
                 * "API dosen't support front camera or no front camera",
                 * Toast.LENGTH_LONG).show();
                 * 
                 * finish(); 
                 */

            
         
        else
        
            System.out.println("isFrontCamRequest 4");
            mCamera = getCameraInstance();
            try
            
                mCamera.setPreviewDisplay(holder);

             
            catch (Exception exception) 
                mCamera = null;
            
        

    

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) 
        // stop the preview
        /*
         * mCamera.stopPreview(); // release the camera mCamera.release();
         */
        // unbind the camera from this object
        mCamera = null;
    

    private Camera openFrontFacingCameraGingerbread() 
        int cameraCount = 0;
        Camera cam = null;
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        cameraCount = Camera.getNumberOfCameras();
        for (int camIdx = 0; camIdx < cameraCount; camIdx++) 
            Camera.getCameraInfo(camIdx, cameraInfo);
            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) 
                try 
                    cam = Camera.open(camIdx);
                 catch (RuntimeException e) 
                    Log.e("Camera",
                            "Camera failed to open: " + e.getLocalizedMessage());
                    Toast.makeText(getApplicationContext(),
                            "Front Camera failed to open", Toast.LENGTH_LONG)
                            .show();
                
            
        
        return cam;
    

    @Override
    protected void onDestroy() 
        Intent intent = new Intent("custom-event-name");
        // You can also include some extra data.
        intent.putExtra("message", "This is my message!");
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

        super.onDestroy();
    

    private Camera.Size getBiggesttPictureSize(Camera.Parameters parameters) 
        Camera.Size result = null;

        for (Camera.Size size : parameters.getSupportedPictureSizes()) 
            if (result == null) 
                result = size;
             else 
                int resultArea = result.width * result.height;
                int newArea = size.width * size.height;

                if (newArea > resultArea) 
                    result = size;
                
            
        

        return (result);
    

【讨论】:

请提供一些细节。【参考方案4】:

似乎解决方案已经晚了,但仍然......实际上我们可以通过在 onCreate() 中使用 WindowManager 并膨胀布局......和 ​​setVisibility(View.INVISIBLE)

从服务中获得 UI
@Override public void onCreate() 
        super.onCreate();
        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
        recording = false;
        myview = inflater.inflate(R.layout.service_layout, null);
        layout = (FrameLayout) myview.findViewById(R.id.preview);
        minimize = (ImageButton) myview.findViewById(R.id.minimize);
        minimize.setVisibility(ImageButton.GONE);
        start = (Button) myview.findViewById(R.id.record);
        start.setVisibility(Button.GONE);
        start.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                if(!recording) 
                    if (prepareMediaRecorder()) 
                        try 
                            mediaRecorder.start();
                            Log.e("Camera------>", "working after");
                            recording = true;
                            start.setText("STOP");
                            handler.post(sendUpdates);
                        catch (Exception e)
                            Log.getStackTraceString(e);
                        
                    
                else
                    mediaRecorder.stop(); // stop the recording
                    releaseMediaRecorder();
                    recording = false;
                    Log.e("Camera1------>", "working");
                    start.setText("START");
                    handler.post(sendUpdates);
                

            
        );

您也可以参考示例应用程序https://github.com/gauravbspr/Research-Projects/tree/master/Camera%20Service 并在必要时提供帮助

【讨论】:

【参考方案5】:

不知道这是否晚了,但对于仍在搜索的任何人,请试试这个Android Background Camerahttps://github.com/YoboZorle/Android-Background-Camera

【讨论】:

【参考方案6】:

你可以试试这个

Intent translucent = new Intent(getApplication(),
                                TakePicture.class);
                        translucent.putExtra("FLASH", "on");
                        startActivity(translucent); 
                      Toast.makeText(getApplicationContext(), "Started Capture", 500).show();




 <SurfaceView
    android:id="@+id/camera_preview"
    android:layout_
    android:layout_ />

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

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


    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" />
 <uses-feature android:name="android.hardware.camera.autofocus" />

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



    <uses-feature android:name="android.hardware.camera.front" android:required="false" />

只要这样做对我有用。 希望对您有所帮助。

【讨论】:

以上是关于在后台 Android 中使用相机的主要内容,如果未能解决你的问题,请参考以下文章

在后台服务中拦截 Android 蓝牙相机快门

Android - 在后台杀死相机进程[重复]

在后台捕获相机帧(Android)

Android 相机 - 从服务在后台运行

Android在后台运行任务时关闭屏幕

相机打开时如何释放相机?