Android preview processing while video recording

2019-01-22 23:01发布

I am using Android development (SDK 2.2) and I would like to make a video recording with mediaRecorder and, at the same time, do some process on each preview frame.

I record video with MediaRecorder in a project, in an other I use the onPreviewFrame(byte[] data, Camera camera) (from PreviewCallback) for processing preview pictures.

I've tried to create a Camera and use it with mediaRecorder (setCamera function) but it doesn't work.

Is it possible to do both in the same time?

Actually I don't understand how to link two things?

My code :

package ch.fraise;

import java.io.IOException;
import android.app.Activity;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class CameraActivity extends Activity implements SurfaceHolder.Callback,
    Camera.AutoFocusCallback {

private SurfaceView preview;
private SurfaceHolder previewHolder;

private MediaRecorder mRecorder;
private Camera mCamera;
private boolean mPreviewRunning = false;
private boolean mCaptureFrame = false;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.e("", "Begin onCreate");
    setContentView(R.layout.main);

    preview = (SurfaceView) findViewById(R.id.surfaceView1);
    previewHolder = preview.getHolder();
    previewHolder.addCallback(this);
    previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

    mRecorder = new MediaRecorder();
}

@Override
public void onResume() {
    super.onResume();
}

@Override
public void onPause() {
    super.onPause();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.capture_menu, menu);
    return true;
}

public void startRecording() {
    Log.e("", "Begin StartRecording");
    mCaptureFrame = true;
    mRecorder.start();
}

public void stopRecording() {
    Log.e("", "Begin StopChange");
    mRecorder.stop();
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle item selection
    switch (item.getItemId()) {
    case R.id.startRecording:
        startRecording();
        return true;
    case R.id.stopRecording:
        stopRecording();
        return true;
    default:
        return super.onOptionsItemSelected(item);
    }
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    Log.e("", "Begin surfaceDestroy");
    mCamera = Camera.open();
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    mCamera.stopPreview();
    mPreviewRunning = false;
    mCamera.release();

    mRecorder.reset();
    mRecorder.release();
}

@Override
public void onAutoFocus(boolean success, Camera camera) {
    // TODO Auto-generated method stub

}

/*
 * PreviewCallback()
 * 
 * this callback captures the preview at every frame and puts it in a byte
 * buffer. we will evaluate if this is a frame that we want to process, and
 * if so, we will send it to an asynchronous thread that will process it to
 * an ARGB Bitmap and POST it to the server
 */
PreviewCallback previewCallback = new PreviewCallback() {
    public void onPreviewFrame(byte[] data, Camera camera) {
        Log.e("", "onPreviewFrame pass");
        if (mCaptureFrame) {
            mCaptureFrame = false;
            // new FrameHandler().execute(data);
        }
    }
};

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
    Log.e("", "Begin SurfaceChange");

    mRecorder.reset();
    mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
    mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
    mRecorder.setOutputFile("/sdcard/videotest2.mp4");
    mRecorder.setVideoFrameRate(30);

    mRecorder.setPreviewDisplay(previewHolder.getSurface());
    try {
        mRecorder.prepare();
    } catch (IllegalStateException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    if (mPreviewRunning)
        mCamera.stopPreview();

    Camera.Parameters p = mCamera.getParameters();
    // p.setPreviewSize(width, height);
    mCamera.setParameters(p);

    try {
        mCamera.setPreviewDisplay(holder);
    } catch (IOException e) {
        e.printStackTrace();
    }

    mCamera.setPreviewCallback(previewCallback);

    mCamera.startPreview();
    mPreviewRunning = true;

}

}

and the permissions in the XML file :

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

4条回答
手持菜刀,她持情操
2楼-- · 2019-01-22 23:17

You just add tag to your manifest file .Thus it will work.Sample code shown below.

eg:-

   </application>
    <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.RECORD_VIDEO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    ***<uses-feature android:name="android.hardware.camera" />***
</manifest>
查看更多
手持菜刀,她持情操
3楼-- · 2019-01-22 23:32

if you are using os 2.2 or higher then use this method your prepare failed and other exception will removed

 public boolean startRecording() {
    try {
        camera.unlock();

        mediaRecorder = new MediaRecorder();
        mediaRecorder.setCamera(camera);
        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
        mediaRecorder.setProfile(CamcorderProfile
                .get(CamcorderProfile.QUALITY_HIGH));

        File tempFile = new File(getOutputMediaFile(MEDIA_TYPE_VIDEO)
                .toString());

        mediaRecorder.setOutputFile(tempFile.getPath());
        mediaRecorder.setVideoFrameRate(videoFramesPerSecond);
        mediaRecorder.setVideoSize(surfaceView.getWidth(),
                surfaceView.getHeight());
        mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface());
        mediaRecorder.setMaxFileSize(maxFileSizeInBytes);
        mediaRecorder.prepare();
        mediaRecorder.start();

        return true;
    } catch (IllegalStateException e) {
        Log.e(TAG, e.getMessage());
        e.printStackTrace();
        return false;
    } catch (IOException e) {
        Log.e(TAG, e.getMessage());
        e.printStackTrace();
        return false;
    }
}
查看更多
啃猪蹄的小仙女
4楼-- · 2019-01-22 23:40

you cannot access the video stream while recording, onPreviewFrame will not get called once you start recording. Oddly, onPreviewFrame does not seem to get called after you record either...

查看更多
来,给爷笑一个
5楼-- · 2019-01-22 23:43

Eureka! The trick is to attach your PreviewCallback in the surfaceChanged(...) SurfaceHolder.Callback! After doing this, you'll continue to get preview frame data after a MediaRecorder is running!

For example:

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    mCamera.setPreviewCallback(new PreviewCallback() {
            public void onPreviewFrame(byte[] _data, Camera _camera) {
                Log.d("onPreviewFrame-surfaceChanged",String.format("Got %d bytes of camera data", _data.length));
            }
        });

}
查看更多
登录 后发表回答