Android - 在后台录制视频

时间:2014-10-13 23:07:59

标签: java android video

我正在尝试使用以下功能在Android中开发应用程序:无缝录制视频和音频,即使用户在前台有另一个应用程序。常见的情况是:用户打开应用程序,开始录制,然后打开导航应用程序或接听电话。 我希望我的应用继续录制

我已经汇总了一些代码,主要受到这个tutorial的启发,将在下面引用。然而,我遇到了两个问题:

1。当我按下" home"键,视频录制冻结,但声音很好

2。当我导航回应用程序时,预览为黑色

我的问题是:

  • 我的目标是否可以在Android上使用?
  • 我做错了什么?

我的代码:



public class GlobalState extends Application {
	private boolean recording = false;
	private boolean loggingEnabled = true;

	private Camera serviceCamera = null;
	private CameraPreview cameraPreview = null;

	@Override
	public void onCreate() {
		try {
			serviceCamera = Camera.open();
		} catch (Exception e) {

		}

		super.onCreate();
	}

	public boolean isRecording() {
		return recording;
	}

	public boolean isLoggingEnabled() {
		return loggingEnabled;
	}

	public void setRecording(boolean recording) {
		this.recording = recording;
	}

	public void setCamera(Camera serviceCamera) {
		this.serviceCamera = serviceCamera;
	}

	public Camera getCamera() {
		return serviceCamera;
	}

	public void setCameraPreview(CameraPreview cameraPreview) {
		this.cameraPreview = cameraPreview;
	}

	public CameraPreview getCameraPreview() {
		return this.cameraPreview;
	}

}






public class CameraPreview extends SurfaceView implements
		SurfaceHolder.Callback {
	private SurfaceHolder mHolder;
	private Camera mCamera;

	private static final String TAG = "CameraPreview";

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

		mHolder = getHolder();
		mHolder.addCallback(this);
		mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
	}

	public void surfaceCreated(SurfaceHolder holder) {
		try {
			mCamera.setPreviewDisplay(holder);
			mCamera.startPreview();
		} catch (IOException e) {
			Log.d(TAG, "Error setting camera preview: " + e.getMessage());
		}
	}

	public void surfaceDestroyed(SurfaceHolder holder) {
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {

		if (mHolder.getSurface() == null) {
			return;
		}

		try {
			mCamera.stopPreview();
		} catch (Exception e) {
		}

		try {
			mCamera.setPreviewDisplay(mHolder);
			mCamera.startPreview();
		} catch (Exception e) {
			Log.d(TAG, "Error starting camera preview: " + e.getMessage());
		}
	}
}






public class MainActivity extends Activity {
	public String TAG = "DE-MainActivity";

	ImageView mRecordView;
	ImageView mMenuButtonView;
	LinearLayout mMenuView;
	TextView mVideosTextView;
	TextView mSettingsTextView;

	private Camera mCamera;
	private CameraPreview mPreview;

	GlobalState mAppState = null;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		mAppState = (GlobalState) getApplicationContext();

		if (mAppState.isLoggingEnabled()) {
			Log.v(TAG, "Activity: onCreate");
		}

		mCamera = mAppState.getCamera();
		if (mAppState.getCameraPreview() == null) {
			mPreview = new CameraPreview(this, mCamera);
			mAppState.setCameraPreview(mPreview);
		}
		FrameLayout preview = (FrameLayout) findViewById(R.id.fl_camera);
		preview.addView(mPreview);

		mMenuView = (LinearLayout) findViewById(R.id.ll_menu_list);
		mVideosTextView = (TextView) findViewById(R.id.tv_menu_item_videos);
		mSettingsTextView = (TextView) findViewById(R.id.tv_menu_item_settings);

		mRecordView = (ImageView) findViewById(R.id.iv_record);
		mRecordView.setImageResource(R.drawable.btn_not_recording);
		mRecordView.setAlpha((float) 0.5);
		mRecordView.bringToFront();
		mRecordView.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {

				if (!mAppState.isRecording()) {

					mRecordView.setImageResource(R.drawable.btn_recording);
					mRecordView.setAlpha((float) 0.3);

					startService(new Intent(MainActivity.this,
							RecorderService.class));

				} else {

					mRecordView.setImageResource(R.drawable.btn_not_recording);
					mRecordView.setAlpha((float) 0.5);

					stopService(new Intent(MainActivity.this,
							RecorderService.class));

				}
			}
		});

		mMenuButtonView = (ImageView) findViewById(R.id.iv_menu);
		mMenuButtonView.setImageResource(R.drawable.btn_menu);
		mMenuButtonView.setAlpha((float) 0.5);
		mMenuButtonView.bringToFront();
		mMenuButtonView.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				if (mMenuView.getVisibility() == View.VISIBLE) {
					mMenuView.setVisibility(View.INVISIBLE);
				} else {
					mMenuView.setVisibility(View.VISIBLE);
				}
			}
		});

		mSettingsTextView.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				if (mAppState.isLoggingEnabled())
					Log.v(TAG, "settings clicked!");
			}
		});

		mVideosTextView.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				if (mAppState.isLoggingEnabled())
					Log.v(TAG, "videos clicked!");
			}
		});
	}

	@Override
	protected void onDestroy() {
		if (mAppState.isLoggingEnabled())
			Log.v(TAG, "APPLICATION EXIT!");

		if (mCamera != null) {
			mCamera.release(); // release the camera for other applications
			mCamera = null;
		}

		super.onDestroy();
	}

	public boolean onCreateOptionsMenu(Menu menu) {

		if (mMenuView.getVisibility() == View.VISIBLE) {
			mMenuView.setVisibility(View.INVISIBLE);
		} else {
			mMenuView.setVisibility(View.VISIBLE);
		}
		return false;
	}
}






public class RecorderService extends Service {

	private static final String TAG = "RecorderService";

	private static Camera mServiceCamera;
	private MediaRecorder mMediaRecorder;

	private GlobalState mAppState;

	public static final int MEDIA_TYPE_IMAGE = 1;
	public static final int MEDIA_TYPE_VIDEO = 2;

	@Override
	public void onCreate() {
		mAppState = (GlobalState) getApplicationContext();
		mServiceCamera = mAppState.getCamera();

		if (mAppState.isLoggingEnabled())
			Log.v(TAG, "onCreate");

	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		super.onStartCommand(intent, flags, startId);

		if (!mAppState.isRecording()) {
			if (prepareVideoRecorder()) {
				mMediaRecorder.start();
				mAppState.setRecording(true);
			} else {
				releaseMediaRecorder();
			}
		}

		return 5;
	}

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

	@Override
	public void onDestroy() {
		if (mAppState.isLoggingEnabled())
			Log.v(TAG, "onDestroy");

		// stop recording and release camera
		mMediaRecorder.stop(); // stop the recording
		releaseMediaRecorder(); // release the MediaRecorder object
		mServiceCamera.lock(); // take camera access back from MediaRecorder

		mAppState.setRecording(false);

		super.onDestroy();
	}

	private void releaseMediaRecorder() {
		if (mMediaRecorder != null) {
			mMediaRecorder.reset(); // clear recorder configuration
			mMediaRecorder.release(); // release the recorder object
			mMediaRecorder = null;
		}
	}

	/** Create a file Uri for saving an image or video */
	private static Uri getOutputMediaFileUri(int type) {
		return Uri.fromFile(getOutputMediaFile(type));
	}

	/** Create a File for saving an image or video */
	private static File getOutputMediaFile(int type) {
		File mediaStorageDir = new File(
				Environment.getExternalStorageDirectory(), "DashEyeApp");

		if (!mediaStorageDir.exists()) {
			if (!mediaStorageDir.mkdirs()) {
				Log.d("MyCameraApp", "failed to create directory");
				return null;
			}
		}

		String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
				.format(new Date());
		File mediaFile;
		if (type == MEDIA_TYPE_IMAGE) {
			mediaFile = new File(mediaStorageDir.getPath() + File.separator
					+ "IMG_" + timeStamp + ".jpg");
		} else if (type == MEDIA_TYPE_VIDEO) {
			mediaFile = new File(mediaStorageDir.getPath() + File.separator
					+ "VID_" + timeStamp + ".mp4");
		} else {
			return null;
		}

		return mediaFile;
	}

	private boolean prepareVideoRecorder() {

		mMediaRecorder = new MediaRecorder();

		mServiceCamera.unlock();
		mMediaRecorder.setCamera(mServiceCamera);

		mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
		mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

		mMediaRecorder.setProfile(CamcorderProfile
				.get(CamcorderProfile.QUALITY_HIGH));

		mMediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO)
				.toString());

		// Step 5: Set the preview output
		// mMediaRecorder.setPreviewDisplay(mAppState.getCameraPreview().getHolder().getSurface());

		try {
			mMediaRecorder.prepare();
		} catch (IllegalStateException e) {
			Log.d(TAG,
					"IllegalStateException preparing MediaRecorder: "
							+ e.getMessage());
			releaseMediaRecorder();
			return false;
		} catch (IOException e) {
			Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
			releaseMediaRecorder();
			return false;
		}
		return true;
	}
}



  我很抱歉文字的墙壁,我非常感谢任何帮助!

3 个答案:

答案 0 :(得分:1)

我的解决方案很好,试一试:

服务android:

import java.util.Calendar;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.view.Gravity;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;

public class BackgroundVideoRecorder extends Service implements
    SurfaceHolder.Callback {

private WindowManager windowManager;
private SurfaceView surfaceView;
private Camera camera = null;
private MediaRecorder mediaRecorder = null;



int contTime = 0, duracaoGravacao = 30; //interval  in seconds to record video

private class thread implements Runnable {
    public void run() {

        contTime++;

        if (contTime >= duracaoGravacao) {
            StopService();
        }

        tick_Handler.postDelayed(tick_thread, 1000);
    }
}

Handler tick_Handler;
thread tick_thread;

Preferences pref;

@Override
public void onCreate() {

    windowManager = (WindowManager) this
            .getSystemService(Context.WINDOW_SERVICE);
    surfaceView = new SurfaceView(this);
    LayoutParams layoutParams = new WindowManager.LayoutParams(1, 1,
            WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
            WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
            PixelFormat.TRANSLUCENT);
    layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
    windowManager.addView(surfaceView, layoutParams);

    surfaceView.getHolder().addCallback(this);

    tick_Handler = new Handler();
    tick_thread = new thread();

    VIDEO_RECORDER_FOLDER = new _Path().getPathVideo();

}

@Override
public void onStart(Intent intent, int startId) {

    tick_Handler.post(tick_thread);

}

// Method called right after Surface created (initializing and starting
// MediaRecorder)
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {

    boolean found = false;

    int i = 0;

    try {
        for (i = 0; i < Camera.getNumberOfCameras(); i++) {

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

            Camera.getCameraInfo(i, newInfo);

            if (newInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {
                found = true;
                break;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

    if (found) {
        camera = Camera.open(i);
    } else {
        camera = Camera.open();
    }

    Calendar lCDateTime = Calendar.getInstance();

    String t = String.valueOf(lCDateTime.getTimeInMillis());

    nomeArquivo = "hire_me_now_" + t + ".mp4";

    nomeArquivo = nomeArquivo.replace(" ", "_").replace(":", "_")
            .replace("-", "_");

    String caminhoArquivo = VIDEO_RECORDER_FOLDER + "/" + nomeArquivo;

    mediaRecorder = new MediaRecorder();
    camera.unlock();

    mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface());
    mediaRecorder.setCamera(camera);
    mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
    mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
    mediaRecorder.setProfile(CamcorderProfile
            .get(CamcorderProfile.QUALITY_QVGA));
    mediaRecorder.setVideoFrameRate(15);

    mediaRecorder.setOutputFile(caminhoArquivo);

    try {
        mediaRecorder.prepare();

    } catch (Exception e) {
        e.printStackTrace();
    }

    mediaRecorder.start();
}

// Stop recording and remove SurfaceView
@Override
public void onDestroy() {

    mediaRecorder.stop();
    mediaRecorder.reset();
    mediaRecorder.release();

    camera.lock();
    camera.release();

    windowManager.removeView(surfaceView);

}

protected void StopService() {
    try {
        this.stopSelf();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format,
        int width, int height) {
}

@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
}

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

}

答案 1 :(得分:0)

事实证明,Android不喜欢预览被破坏(例如,当用户点击“主页”按钮时),因此它会切断视频录制。

解决方法是使用WindowManager设置叠加层,当用户点击“主页”按钮时,将其调整为1x1。我找到了解决方案here。非常感谢 cman

答案 2 :(得分:-1)

可以这样做但是从API级别23开始你需要询问相机权限,你可以参考这个答案https://stackoverflow.com/a/49919386/4604234