You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于Camera2与MediaCodec API实现视频录制与保存?

嘿,我明白你的困扰——MediaRecorder确实在灵活度上有局限,尤其是需要后期编辑或者要避免丢帧的场景,Camera2+MediaCodec确实是更合适的方案。下面我就针对你要的部分给出具体示例:

使用Camera2 API + MediaCodec实现视频录制(核心片段)

一、Camera2需传递给MediaCodec的关键参数示例

首先,你需要从Camera2的特性中获取适配的视频尺寸和格式,再以此配置MediaCodec的输入参数。核心代码如下:

// 1. 从相机特性中获取支持的视频输出尺寸
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
StreamConfigurationMap configMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Size[] videoSizes = configMap.getOutputSizes(MediaCodec.class);
// 自定义方法:挑选最接近需求的尺寸(比如优先1080P,匹配宽高比)
Size targetSize = chooseOptimalSize(videoSizes, 1920, 1080);

// 2. 配置MediaCodec的视频格式参数
MediaFormat videoFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, targetSize.getWidth(), targetSize.getHeight());
videoFormat.setInteger(MediaFormat.KEY_BIT_RATE, 10 * 1024 * 1024); // 10Mbps码率
videoFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30); // 30帧每秒
videoFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5); // 每5秒生成一个关键帧
videoFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);

// 3. 创建MediaCodec并获取输入Surface,这个Surface会传给Camera2作为录制输出目标
MediaCodec videoCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
videoCodec.configure(videoFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
Surface codecSurface = videoCodec.createInputSurface();

// 4. 配置Camera2的录制请求,绑定codecSurface
CaptureRequest.Builder recordRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
recordRequestBuilder.addTarget(codecSurface);
// 强制锁定帧率为30fps,避免丢帧
recordRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, new Range<>(30, 30));
recordRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);

注:chooseOptimalSize是自定义工具方法,逻辑可以是优先匹配目标宽高比,再选取最接近目标分辨率的尺寸,你可以根据需求调整。

二、MediaCodec的编码实现(核心逻辑)

接下来是处理编码数据并写入文件的核心线程逻辑,这里结合MediaMuxer完成MP4封装:

private String outputFilePath = getExternalFilesDir(null) + "/recorded_video.mp4";
private MediaMuxer muxer;
private int videoTrackIndex = -1;
private boolean isRecordingStopped = false;
private long frameCount = 0;

// 初始化MediaMuxer用于封装MP4
muxer = new MediaMuxer(outputFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);

// 启动MediaCodec编码
videoCodec.start();

// 开启编码处理线程
new Thread(() -> {
    MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
    while (!isRecordingStopped) {
        int outputBufferId = videoCodec.dequeueOutputBuffer(bufferInfo, 10000);
        if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            // 编码格式就绪后,添加轨道并启动Muxer
            MediaFormat encodedFormat = videoCodec.getOutputFormat();
            videoTrackIndex = muxer.addTrack(encodedFormat);
            muxer.start();
        } else if (outputBufferId >= 0) {
            ByteBuffer outputBuffer = videoCodec.getOutputBuffer(outputBufferId);
            if (bufferInfo.size > 0 && videoTrackIndex != -1) {
                // 修正时间戳,保证视频播放时序正确
                bufferInfo.presentationTimeUs = calculatePresentationTime(frameCount++);
                muxer.writeSampleData(videoTrackIndex, outputBuffer, bufferInfo);
            }
            videoCodec.releaseOutputBuffer(outputBufferId, false);
        }
    }

    // 停止录制后释放资源
    videoCodec.stop();
    videoCodec.release();
    if (videoTrackIndex != -1) {
        muxer.stop();
        muxer.release();
    }
}).start();

辅助方法:计算正确的帧时间戳(以30fps为例)

private long calculatePresentationTime(long frameIndex) {
    return frameIndex * 1000000 / 30; // 每帧间隔约33333微秒
}

三、视频保存的关键注意点

  • 必须等待MediaCodec.INFO_OUTPUT_FORMAT_CHANGED回调后再启动MediaMuxer,否则会触发格式错误
  • 时间戳计算要精准,否则视频播放会出现跳帧、卡顿或音画不同步(如果后续加音频的话)
  • 停止录制时要按顺序释放资源:先标记isRecordingStopped为true,再停止MediaCodec,最后停止并释放MediaMuxer

如果后续需要添加音频录制,只需要再初始化一个音频MediaCodec,将音频编码数据同样写入MediaMuxer即可,逻辑和视频部分一致。

内容的提问来源于stack exchange,提问作者WebDiva

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 18:37:39