Recording Live OpenCV Processing on Android

后端 未结 4 1384
栀梦
栀梦 2020-12-05 08:00

My goal is to do a couple things:

  1. Use OpenCV and the JavaCameraView to process frames from the phone\'s camera feed
  2. Enable recording of that processed
4条回答
  •  暖寄归人
    2020-12-05 08:34

    I've solved a similar problem by creating a MediaRecorder and passing it to a OpenCV CameraBridgeViewBase, which I've modified as follows.

    protected MediaRecorder mRecorder;
    protected Surface mSurface = null;
    
    public void setRecorder(MediaRecorder rec) {
        mRecorder = rec;
        if (mRecorder != null) {
            mSurface = mRecorder.getSurface();
        }
    

    and

    protected void deliverAndDrawFrame(CvCameraViewFrame frame) {
        Mat modified;
    
        if (mListener != null) {
            modified = mListener.onCameraFrame(frame);
        } else {
            modified = frame.rgba();
        }
    
        boolean bmpValid = true;
        if (modified != null) {
            try {
                Utils.matToBitmap(modified, mCacheBitmap);
            } catch(Exception e) {
                Log.e(TAG, "Mat type: " + modified);
                Log.e(TAG, "Bitmap type: " + mCacheBitmap.getWidth() + "*" + mCacheBitmap.getHeight());
                Log.e(TAG, "Utils.matToBitmap() throws an exception: " + e.getMessage());
                bmpValid = false;
            }
        }
    
        if (bmpValid && mCacheBitmap != null) {
            Canvas canvas;
    
            if (mRecorder != null) {
                canvas = mSurface.lockCanvas(null);
    
                canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
                Log.d(TAG, "mStretch value: " + mScale);
    
                if (mScale != 0) {
                    canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
                         new Rect((int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2),
                         (int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2),
                         (int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2 + mScale*mCacheBitmap.getWidth()),
                         (int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2 + mScale*mCacheBitmap.getHeight())), null);
                } else {
                     canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
                         new Rect((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,
                         (canvas.getHeight() - mCacheBitmap.getHeight()) / 2,
                         (canvas.getWidth() - mCacheBitmap.getWidth()) / 2 + mCacheBitmap.getWidth(),
                         (canvas.getHeight() - mCacheBitmap.getHeight()) / 2 + mCacheBitmap.getHeight()), null);
                }
    
                if (mFpsMeter != null) {
                    mFpsMeter.measure();
                    mFpsMeter.draw(canvas, 20, 30);
                }
                mSurface.unlockCanvasAndPost(canvas);
            } 
    
        }
    
        ...
    
    }
    

    I've left the original part of deliverAndDrawFrame as is, so that it keeps displaying the output to the original surface. This way I can process images from a camera by implementing onCameraFrame in MainActivity and save the resulting images to a video, without the need for ffmpeg.

    EDIT I've set up the MediaRecorder as follows

    recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    recorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
    
    CamcorderProfile cpHigh = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
    recorder.setProfile(cpHigh);
    recorder.setOutputFile("out.mp4");
    recorder.setVideoSize(mOpenCvCameraView.mFrameWidth, mOpenCvCameraView.mFrameHeight);
    
    recorder.setOnInfoListener(this);
    recorder.setOnErrorListener(this);
    recorder.prepare();
    

    register it with the OpenCvCameraView

    mOpenCvCameraView.setRecorder(recorder);
    

    and start recording

    recorder.start();
    

提交回复
热议问题