Android 如何从onPreviewFrame()接收的字节数组制作视频

Android 如何从onPreviewFrame()接收的字节数组制作视频,android,android-camera,android-mediarecorder,Android,Android Camera,Android Mediarecorder,我能够从onPreviewFrame()获取字节数组形式的视频帧数据。我需要用这个字节数组制作一个视频。 下面是我的代码片段: @Override public void onPreviewFrame(byte[] data, Camera camera) { try { File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(

我能够从onPreviewFrame()获取字节数组形式的视频帧数据。我需要用这个字节数组制作一个视频。 下面是我的代码片段:

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {

    try {
        File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_PICTURES), "MyCameraApp");

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

        FileOutputStream out = new FileOutputStream(mediaStorageDir.getAbsolutePath() + "video.mp4");
        out.write(data);
        out.close();
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
生成的文件“video.mp4”不可播放

我们将非常感谢您为解决此问题提供的任何帮助或指导

注意
我的应用程序将支持Android 4+版本。

以下是用于拍照和视频的代码

    // Add listener to video capture button
    VideoCapture = (Button)findViewById(R.id.buttonVideo);
    VideoCapture.setOnClickListener(new View.OnClickListener(){

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
                captureButton.setVisibility(View.GONE);
            if(isRecording){
                VideoCapture.setBackgroundResource(R.drawable.ic_action_videoplay); 
                   // stop recording and release camera
                mMediaRecorder.stop();  // stop the recording
                releaseMediaRecorder(); // release the MediaRecorder object
                mCamera.lock();         // take camera access back from MediaRecorder

                // inform the user that recording has stopped
                
                isRecording = false;
            }
            else{
                releaseCamera();
                 // initialize video camera
                if (prepareVideoRecorder()) {
                    // Camera is available and unlocked, MediaRecorder is prepared,
                    // now you can start recording
                    mMediaRecorder.start();

                    // inform the user that recording has started
                    
                    isRecording = true;
                } else {
                    // prepare didn't work, release the camera
                    releaseMediaRecorder();
                    // inform user
                }

                VideoCapture.setBackgroundResource(R.drawable.ic_launcher_videopause);
                isRecording = true;
            }
            
        }
        
    });

    private PictureCallback mPicture = new PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {

        File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
        if (pictureFile == null){
            Log.d(TAG, "Error creating media file, check storage permissions: ");
            return;
        }

        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.close();

            /* set image preview in imageview */
            previewImage = (ImageView)findViewById(R.id.imageViewPrieview);
            previewImage.setImageURI(Uri.fromFile(pictureFile));

            /* release camera & removeallview from preview */
            relaese();
        } catch (FileNotFoundException e) {
            Log.d(TAG, "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d(TAG, "Error accessing file: " + e.getMessage());
        }
    }
};



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

/** Create a File for saving an image or video */
private File getOutputMediaFile(int type){
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.

    File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), "MyCameraApp");
    // This location works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    if (! mediaStorageDir.exists()){
        if (! mediaStorageDir.mkdirs()){
            Log.d("MyCameraApp", "failed to create directory");
            return null;
        }
    }

    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());

    if (type == MEDIA_TYPE_IMAGE){
        //                  mediaFile = new File(mediaStorageDir.getPath() + File.separator +
        //                  "IMG_"+ timeStamp + ".jpg");
        mediaFile = new File("/sdcard/"+ "IMG_"+ timeStamp + ".jpg");
        Log.i("Image","Image is captured");

    } else if(type == MEDIA_TYPE_VIDEO) {
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
                "VID_"+ timeStamp + ".mp4");
    } else {
        return null;
    }

    return mediaFile;
}
这些代码是为录像机准备的

 private boolean prepareVideoRecorder(){
    
    mCamera = getCameraInstance();
    mMediaRecorder = new MediaRecorder();
    
    
    // step 1: Unlock camera & Set camera to MediaRecorder
    mCamera.unlock();
    mMediaRecorder.setCamera(mCamera);
    
    // step 2: set Audio & Video Source
    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
    
    // step 3: set camcorder profile , it required Api Level 8
    mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
    
    // step 4: set output file
    mMediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());
    
    // step 5: set preview output
    mMediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface());
    
    // step 6: prepare Configured Media recorder
    try {
        mMediaRecorder.prepare();
    } catch (IllegalStateException e) {
        Log.d("TAG","IllegalStateException preparing MediaRecorder" + e.getMessage());
        return false;
    }catch (IOException e) {
        Log.d("TAG","IO Exception preparing MediaRecorde" + e.getMessage());
        return false;
        
    }
    return true;
}
private void releaseMediaRecorder(){
    if (mMediaRecorder != null) {
        mMediaRecorder.reset();   // clear recorder configuration
        mMediaRecorder.release(); // release the recorder object
        mMediaRecorder = null;
        mCamera.lock();           // lock camera for later use
    }
我想这对你有帮助。因为它对我有用

Android API目前不提供暂停方法 这有点技术性,但是征求意见的

从API级别1开始使用的没有暂停功能,从MediaRecorder状态图可以看出:

录制时,API允许我们使用
reset()
stop()
公共方法:

reset()
->将MediaRecorder重新启动到空闲状态

stop()
->停止录制


现在检查代码,我为视频捕获添加按钮点击事件Hi DreamCoder,谢谢回复。我需要根据从onPreviewFrame()接收到的帧数据(字节数组)制作视频,因为我需要在录制MediaRecorder支持的视频时实现暂停/恢复功能。这并不像您想象的那么简单。您正在创建文件名后缀为“.mp4”的一些字节的文件。了解更多关于MP4容器的信息。嗨,天墙,谢谢你的建议。我会朝这个方向看。也许MediaCodec会做你想做的事。请参阅Grafika()中的各种示例,例如“显示+捕获照相机”活动。API 18+。