java - 如果调用得太快,MediaRecorder start() 会失败

标签 java android file-descriptor mediarecorder

我正在尝试构建一个基本的摄像机,允许用户通过触摸屏幕快速拍摄视频,这看起来很简单,但我遇到的主要问题是 Android MediaRecorder 不允许快速启动和重新启动,而无需崩溃,如果用户拍摄然后停止然后再次快速恢复拍摄它总是崩溃我不确定是否有办法直接解决这个问题所以我还设计了另一种方法来实现这个通过尝试录制单个视频但试图获得对 mediaRecorder 实际写入文件的时间进行一些控制。但是我无法使用 FileDescriptor 使其完全运行,下面我将粘贴我的原始代码和我在第二次尝试控制写入时使用的方法,是否有任何方法可以调整任何代码以实现我之后的暂停功能?任何帮助都会有很长的路要走谢谢

我第一次尝试使用将文件设置为 setOutPutFile() 的常用方法:

public class MainActivity extends Activity implements SurfaceHolder.Callback {

public static final String LOGTAG = "VIDEOCAPTURE";

private MediaRecorder recorder;
private SurfaceHolder holder;
private CamcorderProfile camcorderProfile;
private Camera camera;

boolean recording = false;
boolean usecamera = true;
boolean previewRunning = false;

double timer = 0;
ProgressBar pb;
boolean neverEnd;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

    camcorderProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_LOW);

    setContentView(R.layout.activity_main);

    pb = (ProgressBar) findViewById(R.id.progressBar1);
    pb.setProgress(0);

    SurfaceView cameraView = (SurfaceView) findViewById(R.id.CameraView);
    holder = cameraView.getHolder();
    holder.addCallback(this);
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

    cameraView.setClickable(true);
    cameraView.setOnTouchListener(new OnTouchListener() {
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_DOWN) {

                recording = true;
                new recordVideo().execute();
                Log.v(LOGTAG, "Recording Started");

                return true;
            } else if (event.getAction() == MotionEvent.ACTION_UP) {

                recording = false;

                return true;
            }
            return false;
        }
    });
}

private void prepareRecorder() {
    recorder = new MediaRecorder();
    recorder.setPreviewDisplay(holder.getSurface());

    if (usecamera) {
        camera.unlock();
        recorder.setCamera(camera);
    }

    recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
    recorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);

    recorder.setProfile(camcorderProfile);


    Calendar calendarTime = Calendar.getInstance();

//initial attempt using a file path with setoutputfile 

    File file = new File(Environment.getExternalStorageDirectory(),
            String.valueOf(calendarTime.getTimeInMillis()) + ".mp4");

    if (camcorderProfile.fileFormat == MediaRecorder.OutputFormat.THREE_GPP) {

        recorder.setOutputFile(file.getAbsolutePath());
    } else if (camcorderProfile.fileFormat == MediaRecorder.OutputFormat.MPEG_4) {

        recorder.setOutputFile(file.getAbsolutePath());
    } else {

        recorder.setOutputFile(file.getAbsolutePath());

    }
    // recorder.setMaxDuration(50000); // 50 seconds
    // recorder.setMaxFileSize(5000000); // Approximately 5 megabytes

    boolean initialized = false;

    while (!initialized) {
        try {
            recorder.prepare();
            initialized = true;
        } catch (IllegalStateException e) {
            e.printStackTrace();
            // finish();
            initialized = false;
        } catch (IOException e) {
            e.printStackTrace();
            // finish();
            initialized = false;
        }
    }

}

public void surfaceCreated(SurfaceHolder holder) {
    Log.v(LOGTAG, "surfaceCreated");

    if (usecamera) {
        camera = Camera.open();

        try {
            camera.setPreviewDisplay(holder);
            camera.startPreview();
            previewRunning = true;
        } catch (IOException e) {
            Log.e(LOGTAG, e.getMessage());
            e.printStackTrace();
        }
    }

}

public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
    Log.v(LOGTAG, "surfaceChanged");

    if (!recording && usecamera) {
        if (previewRunning) {
            camera.stopPreview();
        }

        try {
            Camera.Parameters p = camera.getParameters();

            p.setPreviewSize(camcorderProfile.videoFrameWidth,
                    camcorderProfile.videoFrameHeight);
            p.setPreviewFrameRate(camcorderProfile.videoFrameRate);

            camera.setParameters(p);

            camera.setPreviewDisplay(holder);
            camera.startPreview();
            previewRunning = true;
        } catch (IOException e) {
            Log.e(LOGTAG, e.getMessage());
            e.printStackTrace();
        }

        prepareRecorder();
    }
}

public void surfaceDestroyed(SurfaceHolder holder) {
    Log.v(LOGTAG, "surfaceDestroyed");
    if (recording) {
        recorder.stop();
        recording = false;
    }
    recorder.release();
    if (usecamera) {
        previewRunning = false;
        // camera.lock();
        camera.release();
    }
    finish();
}

private class recordVideo extends AsyncTask<Void, Integer, Void> {

    @Override
    protected Void doInBackground(Void... params) {
        // TODO Auto-generated method stub

        try {

            recorder.start();
            while (recording) {

                Thread.sleep(100);

                publishProgress();
            }
            recorder.stop();
            recorder.release();
            recorder = null;

            // recorder.release();

            Log.v(LOGTAG, "Recording Stopped");
            // Let's prepareRecorder so we can record again
            prepareRecorder();

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return null;
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        // TODO Auto-generated method stub
        super.onProgressUpdate(values);

        if (recording) {
            timer += 0.1;
            pb.setProgress((int) (timer * 10));
        }

    }

}
}

这是我使用 FileDescriptor 的方法,这没有用,只创建了一个文件但没有写入:

//Pass it into setOutputFile() like this
recorder.setOutputFile(getStreamFd());

    private FileDescriptor getStreamFd() {
    ParcelFileDescriptor pipe = null;
    try {

        Calendar calendarTime = Calendar.getInstance();

        File file = new File(Environment.getExternalStorageDirectory(),
                String.valueOf(calendarTime.getTimeInMillis()) + ".mp4");

        pipe = ParcelFileDescriptor.open(file,
                ParcelFileDescriptor.MODE_CREATE
                        | ParcelFileDescriptor.MODE_APPEND
                        | ParcelFileDescriptor.MODE_WORLD_WRITEABLE);

        byte[] buf = new byte[1024];
        int len;

        FileOutputStream out = new FileOutputStream(FileDescriptor.out);

        InputStream is = new FileInputStream(FileDescriptor.in);

        while (usecamera) {
                      if(recordng){
                        out.write(buf, 0, len);
                      }

        }

        is.close();
        out.close();

    } catch (IOException e) {
        Log.e(getClass().getSimpleName(), "Exception opening pipe", e);
    }

    return pipe.getFileDescriptor();
}

最佳答案

在 AsynkTask 上调用 prepareRecorder() 之后调用 cameraView.setClickable(true) 并在调用 prepareRecorder() 之前调用 cameraView.setClickable(false)

关于java - 如果调用得太快,MediaRecorder start() 会失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17025663/

相关文章:

java - 在具有 Web 安全性的 HTTPS 上调用 SOAP 服务时出现异常

android - FFmpeg:无法在 Android Q 上使用文件描述符进行搜索

java - Android 网络服务访问

android - TextInputLayout endIcon 背景颜色

c - recvmsg() 不支持操作

linux - 一些 linux 程序中奇怪的描述符关闭

java - 尝试读取时找不到文件

java - 解析其中包含冒号的 JSON 键

java - 使用 stream() 在特定条件下将 Set<String> 转换为 List<Set<String>>

android - 如何获得联系人的最大可用内存