camera2 opengl实现滤镜效果录制视频 三 录音

本来是想用MediaRecorder直接录像的,可是好像参数设置错误总是报错就改用MediaCodec了

MediaCodec配合MediaMuxer进行录音,以后可以直接用来录像

public class AudioEncoder {
    private static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO; //音频通道(单声道)
    private static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT; //音频格式
    private static final int AUDIO_SOURCE = MediaRecorder.AudioSource.MIC; //音频源(麦克风)
    private static final String AUDIO_MIME_TYPE = "audio/mp4a-latm"; //音频类型
    private static final int SAMPLE_RATE = 44100; //采样率(CD音质)
    private static final int BIT_RATE = 128000; //比特率
    private static final int CHANNEL_COUNT = 1;//声道


    private MediaCodec mAudioCodec; //音频编解码器
    private MediaMuxer mMediaMuxer;

    //初始化
    public void initAudio() {
        String path = "/storage/emulated/0/360/" + System.currentTimeMillis() + ".mp4";
        MediaFormat mAudioFormat = new MediaFormat();
        mAudioFormat.setString(MediaFormat.KEY_MIME, AUDIO_MIME_TYPE);
        mAudioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
        mAudioFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, SAMPLE_RATE);
        mAudioFormat.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
        mAudioFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, CHANNEL_COUNT);
        try {
            mAudioCodec = MediaCodec.createEncoderByType(AUDIO_MIME_TYPE);
            mAudioCodec.configure(mAudioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
            mAudioCodec.start();
            mMediaMuxer = new MediaMuxer(path, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private long audioStartTime;
    //开始
    public void start() {
        //麦克风采集线程
        Thread thread = new Thread() {
            @Override
            public void run() {
                super.run();
                int bufferSizeInBytes = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT);
                AudioRecord audioRecord = new AudioRecord(
                        AUDIO_SOURCE,//音频源
                        SAMPLE_RATE,//采样率
                        CHANNEL_CONFIG,//音频通道
                        AUDIO_FORMAT,//音频格式
                        bufferSizeInBytes//缓冲区
                );
                if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
                    //麦克风被占用
                    return;
                }
                audioRecord.startRecording();
                byte[] buffer = new byte[bufferSizeInBytes];
                audioStartTime = System.nanoTime();
                while (stop) {
                    long audioPresentationTimeNs = System.nanoTime();
                    int bufferReadResult = audioRecord.read(buffer, 0, bufferSizeInBytes);
                    if (bufferReadResult == AudioRecord.ERROR_BAD_VALUE || bufferReadResult == AudioRecord.ERROR_INVALID_OPERATION) {

                    }
                    //向MediaCodec传数据
                    audioInputBuffer(buffer, audioPresentationTimeNs, false);
                }
                long audioPresentationTimeNs = System.nanoTime();
                int bufferReadResult = audioRecord.read(buffer, 0, bufferSizeInBytes);
                if (bufferReadResult == AudioRecord.ERROR_BAD_VALUE || bufferReadResult == AudioRecord.ERROR_INVALID_OPERATION) {

                }
                audioInputBuffer(buffer, audioPresentationTimeNs, true);
                audioRecord.stop();
                audioRecord.release();
            }
        };
        //编码线程
        Thread t = new Thread() {
            @Override
            public void run() {
                super.run();
                offerAudioEncoder();
            }
        };
        //相互独立的线程
        t.start();
        thread.start();
    }

    public void audioInputBuffer(byte[] buffer, long pts, boolean audioEnd) {
        int inputBufferIndex = mAudioCodec.dequeueInputBuffer(-1);
        if (inputBufferIndex >= 0) {
            ByteBuffer inputBuffer = mAudioCodec.getInputBuffer(inputBufferIndex);
            inputBuffer.clear();
            inputBuffer.put(buffer);
            long presentationTimeUs = (pts - audioStartTime) / 1000;
            //MediaCodec接收数据
            if (audioEnd) {
                mAudioCodec.queueInputBuffer(inputBufferIndex, 0, buffer.length, presentationTimeUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
            } else {
                mAudioCodec.queueInputBuffer(inputBufferIndex, 0, buffer.length, presentationTimeUs, 0);
            }
        }
    }

    private void offerAudioEncoder() {
        int mTrackIndex = -1;
        MediaCodec.BufferInfo mBufferInfo = new MediaCodec.BufferInfo();
        while (true) {
            //阻塞线程等待数据,时间100毫秒
            int encoderIndex = mAudioCodec.dequeueOutputBuffer(mBufferInfo, 100);
            if (encoderIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {

            } else if (encoderIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                //开启MediaMuxer,因为只有录音所以只调用一次
                MediaFormat mediaFormat = mAudioCodec.getOutputFormat();
                mTrackIndex = mMediaMuxer.addTrack(mediaFormat);
                mMediaMuxer.start();
            } else if (encoderIndex < 0) {

            } else {
                //有数据时进入这里取当前数据
                ByteBuffer encodedData = mAudioCodec.getOutputBuffer(encoderIndex);
                if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
                    mBufferInfo.size = 0;
                }
                //将数据写入mMediaMuxer,结束写入开始下次循环
                if (mBufferInfo.size != 0) {
                    encodedData.position(mBufferInfo.offset);
                    encodedData.limit(mBufferInfo.offset + mBufferInfo.size);
                    mMediaMuxer.writeSampleData(mTrackIndex, encodedData, mBufferInfo);
                    mAudioCodec.releaseOutputBuffer(encoderIndex, false);
                }
                //判断是否是关闭录音
                if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                    break;      // out of while
                }
            }
        }
        //释放
        release();

    }

    public void release() {
        if (mAudioCodec != null) {
            mAudioCodec.stop();
            mAudioCodec.release();
            mAudioCodec = null;
        }
        if (mMediaMuxer != null) {
            mMediaMuxer.release();
            mMediaMuxer = null;
        }
    }

    private boolean stop = true;
    //结束
    public void stop() {
        stop = false;
    }
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 安卓camera2拍照录制视频demo是基于安卓相机API的一个示例应用程序,用于演示如何使用安卓相机2 API来实现拍照和录制视频功能。 在此示例应用程序中,首先需要初始化相机设备并获取相机特性、参数等信息。然后,可以通过创建一个用于预览的SurfaceView或TextureView,并将其设置为相机的预览输出目标。 在拍照功能方面,可以通过设置拍照的一些参数,如图片格式、拍照模式、闪光灯模式等。然后,可以通过调用相机的拍照方法,触发相机拍照操作,并在拍照完成后保存图片。 在录制视频功能方面,需要创建一个用于录制视频的MediaRecorder对象,并设置视频的输出格式、编码格式、视频大小等参数。然后,可以通过设置相机的预览输出目标为MediaRecorder的Surface,并调用MediaRecorder的start方法开始录制视频,调用stop方法停止录制。 此外,在实际开发中,还需要处理相机权限的获取和申请,以及相机的生命周期管理,如在Activity的onResume和onPause方法中初始化和释放相机等。还可以根据需要添加其他功能,如自动对焦、曝光调节等。 总之,安卓camera2拍照录制视频demo提供了一个基本的框架和实现思路,供开发者参考和借鉴,在此基础上可以根据实际需求进行扩展和定制。 ### 回答2: 安卓Camera2是用于在安卓设备上进行相机操作的API。它提供了更多的功能和控制选项,可以实现更高级的相机操作,比如手动对焦、曝光控制、帧率控制等。 要编写一个拍照录制视频的Demo,首先需要获取相机的权限。在AndroidManifest.xml文件中添加相机权限的声明: <uses-permission android:name="android.permission.CAMERA" /> 然后,在布局文件中添加一个相机预览的SurfaceView: <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" /> 接下来,在Activity中获取相机实例并进行相关配置。首先创建一个CameraManager对象,通过它来获取相机ID和打开相机: CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); String cameraId = cameraManager.getCameraIdList()[0]; cameraManager.openCamera(cameraId, cameraStateCallback, null); 在相机状态回调中,可以配置相机预览的Surface和启动预览: CameraCaptureSession.StateCallback sessionStateCallback = new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { try { // 设置相机预览的Surface CaptureRequest.Builder requestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); requestBuilder.addTarget(surfaceView.getHolder().getSurface()); // 启动预览 session.setRepeatingRequest(requestBuilder.build(), null, null); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { // 配置失败处理 } }; 最后,编写点击拍照和录制视频的逻辑。点击拍照时,创建一个ImageReader对象,设置监听器来处理拍照结果: ImageReader imageReader = ImageReader.newInstance(imageWidth, imageHeight, ImageFormat.JPEG, 1); imageReader.setOnImageAvailableListener(onImageAvailableListener, null); ImageReader.OnImageAvailableListener onImageAvailableListener = new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { // 处理拍照结果 } }; 点击开始录制视频时,创建一个MediaRecorder对象,并配置输出文件、音频源、视频源等参数。然后使用CameraCaptureSession进行录制会话: MediaRecorder mediaRecorder = new MediaRecorder(); mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); // 配置输出文件,视频尺寸等参数 sessionStateCallback.onConfigured(cameraCaptureSession); // 启动预览 mediaRecorder.prepare(); mediaRecorder.start(); 以上是一个简单的安卓Camera2拍照录制视频Demo的实现。通过Camera2 API可以实现更多的相机功能和控制选项,可以根据实际需求进行更多的定制和扩展。 ### 回答3: 安卓的Camera2 API是一个强大的相机框架,可以实现高效的拍照和录制视频功能。 首先,我们需要在AndroidManifest.xml文件中声明相机和音频录制权限。例如: <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> 然后,我们需要在Activity或Fragment中创建一个CameraManager对象来管理相机设备。例如: private CameraManager mCameraManager; mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); 接下来,我们需要获取可用的相机列表,并选择一个需要使用的相机设备。例如: String cameraId = null; try { for (String id : mCameraManager.getCameraIdList()) { CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id); int facing = characteristics.get(CameraCharacteristics.LENS_FACING); if (facing == CameraCharacteristics.LENS_FACING_BACK) { cameraId = id; break; } } } catch (CameraAccessException e) { e.printStackTrace(); } 然后,我们可以打开相机设备并开始预览。例如: try { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { mCameraManager.openCamera(cameraId, mCameraStateCallback, null); } } catch (CameraAccessException e) { e.printStackTrace(); } 在相机预览过程中,我们可以设置一些相机参数,例如预览尺寸、拍照尺寸、闪光灯模式等。例如: CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); captureBuilder.addTarget(mPreviewSurface); captureBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO); 然后,我们可以通过调用CameraCaptureSession的capture方法来拍照。例如: mCameraCaptureSession.capture(captureBuilder.build(), mCaptureCallback, null); 如果要录制视频,可以通过MediaRecorder来实现。例如: private void startRecording() throws IOException { mMediaRecorder = new MediaRecorder(); mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mMediaRecorder.setOutputFile(mOutputFile.getAbsolutePath()); // 设置视频参数 mMediaRecorder.setVideoEncodingBitRate(10000000); mMediaRecorder.setVideoFrameRate(30); mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight()); mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); // 设置音频参数 mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); mMediaRecorder.setAudioChannels(1); mMediaRecorder.setAudioSamplingRate(16000); mMediaRecorder.setAudioEncodingBitRate(32000); mMediaRecorder.prepare(); mMediaRecorder.start(); } 最后,我们可以在相机的onClosed方法中释放相机资源和停止录制。例如: @Override public void onClosed(CameraDevice camera) { mCameraDevice.close(); mCameraDevice = null; if (mMediaRecorder != null) { mMediaRecorder.stop(); mMediaRecorder.reset(); mMediaRecorder.release(); mMediaRecorder = null; } } 通过上述步骤,我们可以实现一个简单的安卓Camera2拍照和录制视频的demo。希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值