簡體   English   中英

Android-在后台錄制視頻

[英]Android - Recording Video in the Background

我正在嘗試在Android中開發具有以下功能的應用程序:無縫錄制視頻和音頻,即使用戶前台有其他應用程序也是如此。 常見的情況是:用戶打開應用程序,開始錄制,然后打開導航應用程序或接聽電話。 我希望我的應用程序繼續記錄

我整理了一些代碼,主要是受本教程的啟發,下面將對此進行引用。 但是,我遇到了兩個問題:

1.當我按“主頁”鍵時,錄像凍結,但是聲音很好

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; } } 
對文本牆感到抱歉,我非常感謝您的幫助!

我的解決方案很好,請嘗試:

服務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;
}

}

事實證明,Android不喜歡預覽被破壞 (例如,當用戶單擊“主頁”按鈕時),因此它會切斷視頻錄制。

解決方法是使用WindowManager設置覆蓋,並在用戶單擊“主頁”按鈕時將其調整為1x1。 我在這里找到了解決方案。 非常感謝cman

它可以完成,但是從API級別23開始,您需要詢問相機權限,您可以參考以下答案https://stackoverflow.com/a/49919386/4604234

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM