【问题标题】:Can I use Android Camera in service without preview?我可以在没有预览的情况下使用 Android 相机吗?
【发布时间】:2015-03-16 15:44:32
【问题描述】:

我在 Android 中创建了一个应用程序,它使用相机可以测量用户面部与手机屏幕之间的距离。

问题描述:

现在我想让它在后台运行,以便在我使用其他应用程序时该功能可用。这意味着 我应该在服务中打开相机而不预览,并在服务中处理它.

我做了什么:

我在这里提到了一些问题

How to record video from background of application : Android

How to use Android Camera in Background?

Taking picture from camera without preview

API 级别 16

我的服务文件

import android.app.Service;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.Size;
import android.media.MediaRecorder;
import android.os.IBinder;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import java.util.List;

public class RecorderService extends Service {
private static final String TAG = "RecorderService";
private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
private static Camera mServiceCamera;
private boolean mRecordingStatus;
private MediaRecorder mMediaRecorder;
File path = android.os.Environment.getExternalStorageDirectory();


@Override
public void onCreate() {
    Log.i(TAG,"onCreate");
    mRecordingStatus = false;
    //mServiceCamera = CameraRecorder.mCamera;
    mServiceCamera = Camera.open(1);
    mSurfaceView = MainActivity.mSurfaceView;
    mSurfaceHolder = MainActivity.mSurfaceHolder;

    super.onCreate();
    if (mRecordingStatus == false)
        startRecording();
}

@Override
public IBinder onBind(Intent intent) {
    // TODO Auto-generated method stub
    return null;
}

@Override
public void onDestroy() {
    Log.i(TAG,"onDestroy");

    stopRecording();
    mRecordingStatus = false;

    super.onDestroy();
}

public boolean startRecording(){
    Log.i(TAG,"startRecording");

    try {
        Toast.makeText(getBaseContext(), "Recording Started", Toast.LENGTH_SHORT).show();

        //mServiceCamera = Camera.open();
        Camera.Parameters params = mServiceCamera.getParameters();
        mServiceCamera.setParameters(params);
        Camera.Parameters p = mServiceCamera.getParameters();

        final List<Size> listSize = p.getSupportedPreviewSizes();
        Size mPreviewSize = listSize.get(2);
        Log.v(TAG, "use: width = " + mPreviewSize.width
                + " height = " + mPreviewSize.height);
        p.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
        p.setPreviewFormat(PixelFormat.YCbCr_420_SP);
        mServiceCamera.setParameters(p);

        try {
            mServiceCamera.setPreviewDisplay(mSurfaceHolder);
            mServiceCamera.startPreview();
        }
        catch (IOException e) {
            Log.e(TAG, e.getMessage());
            e.printStackTrace();
        }

        mServiceCamera.unlock();

        mMediaRecorder = new MediaRecorder();
        mMediaRecorder.setCamera(mServiceCamera);
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
        mMediaRecorder.setOutputFile(path+"/outputVideo.mp4");
        mMediaRecorder.setVideoFrameRate(30);
        mMediaRecorder.setVideoSize(mPreviewSize.width, mPreviewSize.height);
        mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());

        mMediaRecorder.prepare();
        mMediaRecorder.start();

        mRecordingStatus = true;

        return true;
    } catch (IllegalStateException e) {
        Log.d(TAG, e.getMessage());
        e.printStackTrace();
        return false;
    } catch (IOException e) {
        Log.d(TAG, e.getMessage());
        e.printStackTrace();
        return false;
    }
}

public void stopRecording() {
    Log.i(TAG,"stopRecording");

    Toast.makeText(getBaseContext(), "Recording Stopped", Toast.LENGTH_SHORT).show();
    try {
        mServiceCamera.reconnect();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    try{
        mMediaRecorder.stop();
    }catch (Exception ignored)
    {

    }
    mMediaRecorder.reset();
    mMediaRecorder.release();
    mServiceCamera.stopPreview();
    mServiceCamera.release();
    mServiceCamera = null;
}
}

【问题讨论】:

  • 你的 API 级别是多少?您是否尝试过从 Android 5.0 开始支持的 Camera2 API?
  • 我的API等级是21,Camera2还可以,但是不知道怎么用。能给我解释一下吗?
  • 查看Android Sdk提供的示例项目“Camera2Basic”。
  • @Chatea 但是如果我使用 Camera2 API ,那么我无法在 API 级别为 16 或 19 的设备上运行该应用程序?你有什么想法吗?
  • 不,你不能。所以你必须先决定用途。我问这个问题是为了澄清您使用的 API。

标签: android android-service


【解决方案1】:

您可以参考这个Question,它讨论了如何在服务中进行视频录制。抓图步骤同上。

要达到您的要求,您可能需要:

  1. 在您的服务中获取相机实例。检查此Official Guideline
  2. 设置您的相机参数。使用 Camera.getParameters()Camera.setParameters()Camera.Parameters.setPictureSize(int with, int height)Camera.Parameters.setPictureFormat(int format) 等 API 来执行此操作。
  3. 准备一个用于存储图像的文件。为此,您需要实现 Camera.PictureCallback
  4. 拍照前致电Camera.startPreview()。如果在拍照前没有调用这个函数,就会出现异常。 (注意:不需要先Camera.setPreviewdisplay(SurfaceHolder display)。)
  5. 请致电camera.takePicture() 为您服务。然后您可以将捕获的图像存储在您指定的文件中。

它工作后,不要忘记在生命周期中维护资源以正确获取/释放相机。

这是我的sample code on Github,评论里也提到了。

【讨论】:

  • 是的,我完全尝试了您今天给出的代码Question。但是,当我描述一个问题时,我遇到了一个问题,如果我在录制时切换到另一个应用程序。然后我切换回来。相机似乎停止了。
  • 我没有你描述的问题。我认为您可能会在 Activity 或 Service 的生命周期中错过一些资源处理。顺便说一句,如果您不停止并释放服务中的相机,则无法再次获得。
  • 你的意思是当你切换到另一个应用程序时你的程序仍然运行良好?
  • 真的真的太棒了!!
  • 一般来说,如果您没有事先调用 setPreviewDisplay 或 setPreviewTexture,camera API 不保证 startPreview 会正常工作。这适用于某些设备子集(在技术上违反了 API 规范),但不适用于许多设备。如果您想在所有 Android 设备上运行,请不要依赖此行为。
猜你喜欢
  • 1970-01-01
  • 2011-06-22
  • 2017-12-31
  • 2019-01-31
  • 2016-08-11
  • 2021-08-10
  • 2021-07-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多