如何修复视频和视频使用Camera api 2在Android Video Recording上出现音频不同步问题? [英] How to fix video & audio out of sync issue on android Video Recording using Camera api 2?

查看:162
本文介绍了如何修复视频和视频使用Camera api 2在Android Video Recording上出现音频不同步问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Camera2 API实现视频录制应用程序.我用过 Google示例用于视频录制.但是,某些设备(例如Samsung J5,J6)上存在音频,视频不同步的问题.我已经更改了MediaRecorder.AudioEncoder, MediaRecorder.VideoEncoder, VideoEncodingBitrate,但是它无济于事.如何处理音频,视频同步问题?

I am implementing video recording application using Camera2 api. I've used Google samples for video recording. However, there's an audio, video out of sync issue on some devices, such as Samsung J5, J6. I have changed MediaRecorder.AudioEncoder, MediaRecorder.VideoEncoder, VideoEncodingBitrate, but it could not help me. How to handle audio, video sync issue?

推荐答案

我从 mp4parser 库.首先,视频录制工作流程与普通视频录制相同,但是对于有问题的设备,还有一个额外的步骤.我将在下面提供我的答案. 录像的第一步是准备MediaRecorder,为缩短答案,我将省略一些步骤.

I've found a solution from this article. It mightn't be the best solution but it works. To solve the out of sync issue, mp4parserlibrary is utilized. First, video recording workflow is the same as just normal video recording, but , there's an extra step for the problematic devices. I will below provide my answer. First step of video recording is to prepare MediaRecorder, to shorten my answer I'll omit some steps.

 private void setupMediaRecorder(){
    mMediaRecorder = new MediaRecorder();

    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
    mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);

    mMediaRecorder.setOutputFile(mVideoFilePath);
    mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());

    CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_480P);
    mMediaRecorder.setVideoFrameRate(profile.videoFrameRate);
    mMediaRecorder.setVideoSize(profile.videoFrameWidth, profile.videoFrameHeight);
    mMediaRecorder.setVideoEncodingBitRate(profile.videoBitRate);
    mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
    mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);

    mMediaRecorder.setAudioChannels(2);
    mMediaRecorder.setAudioEncodingBitRate(profile.audioBitRate);
    mMediaRecorder.setAudioSamplingRate(profile.audioSampleRate);

    int rotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();

    switch (getRotation()) {
        case SENSOR_ORIENTATION_DEFAULT_DEGREES:

            mMediaRecorder.setOrientationHint(ORIENTATIONS.get(rotation));
            break;
        case SENSOR_ORIENTATION_INVERSE_DEGREES:

            mMediaRecorder.setOrientationHint(INVERSE_ORIENTATIONS.get(rotation));
            break;
        case SENSOR_ORIENTATION_DEFAULT_LAND_DEGREES:

            mMediaRecorder.setOrientationHint((ORIENTATIONS.get(rotation)+270)%360);
            break;
        case SENSOR_ORIENTATION_INVERSE_LAND_DEGREES:

            mMediaRecorder.setOrientationHint((INVERSE_ORIENTATIONS.get(rotation)+270)%360);
            break;
    }
    try{
        mMediaRecorder.prepare();
    }catch (IllegalStateException | IOException exc){
        exc.printStackTrace();
    }
}

停止录制视频

public void stopVideo(){
    //Stop recording
    try {
       mMediaRecorder.stop();
       mMediaRecorder.release();
       parseVideo(mVideoFilePath);
    }catch (RuntimeException e){
    e.printStackTrace();
   }
   closePreviewSession();
   createCameraPreviewSession();
   if (mListener!=null){
    mListener.onPrepareRecorder();
   }
}

最后也是重要的一步是调用parseVideo函数

The last and important step is to call parseVideo function

 private String parseVideo(String mFilePath) {
    try {
        DataSource channel = new FileDataSourceImpl(mFilePath);
        IsoFile isoFile = new IsoFile(channel);
        List<TrackBox> trackBoxes = isoFile.getMovieBox().getBoxes(TrackBox.class);
        boolean isError = false;
        for (TrackBox trackBox : trackBoxes) {
            TimeToSampleBox.Entry firstEntry = trackBox.getMediaBox().getMediaInformationBox().getSampleTableBox().getTimeToSampleBox().getEntries().get(0);
            // Detect if first sample is a problem and fix it in isoFile
            // This is a hack. The audio deltas are 1024 for my files, and video deltas about 3000
            // 10000 seems sufficient since for 30 fps the normal delta is about 3000
            if (firstEntry.getDelta() > 10000) {
                isError = true;
                firstEntry.setDelta(3000);
            }
        }

        if (isError) {
            Movie movie = new Movie();
            for (TrackBox trackBox : trackBoxes) {
                movie.addTrack(new Mp4TrackImpl(channel.toString() + "[" + trackBox.getTrackHeaderBox().getTrackId() + "]", trackBox));
            }
            movie.setMatrix(isoFile.getMovieBox().getMovieHeaderBox().getMatrix());
            Container out = new DefaultMp4Builder().build(movie);

            //delete file first!
            FileChannel fc = new RandomAccessFile(mPostProcessingFilePath, "rw").getChannel();
            out.writeContainer(fc);
            fc.close();
            deleteFile(mVideoFilePath);
            mListener.onVideoStop(mPostProcessingFilePath);
            return mPostProcessingFilePath;
        }
        mListener.onVideoStop(mVideoFilePath);
        return mFilePath;
    }catch (IOException e){
        mListener.onVideoError("");
        return mPostProcessingFilePath;
    }
}

在解析器函数中,它检查增量值,如果该值大于10000,它将处理录制的视频并返回结果.如果增量值小于10000,则仅返回视频而不进行处理.有关更多详细信息,请参阅链接.希望对您有帮助.

In the parser function it checks the delta value, if it's bigger than 10000, it processes the recorded video and returns the result. In case if the delta value is less than 10000, it just returns video without processing. For more details, please refer to the link. Hope it helps you.

这篇关于如何修复视频和视频使用Camera api 2在Android Video Recording上出现音频不同步问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆