如何实现横竖屏录制均输出固定横屏分辨率的视频?
问题需求
我需要实现:无论以竖屏还是横屏模式录制视频,输出的视频都保持固定的横屏分辨率(例如640×480)。
我尝试调用mediaRecorder.setVideoSize(640, 480)来设置固定分辨率,但竖屏录制时,输出视频的分辨率仍然是480×640,使用的代码如下:
mediaRecorder.setOutputFormat(camcorderProfile.fileFormat); if (enableAudio) { mediaRecorder.setAudioEncoder(camcorderProfile.audioCodec); mediaRecorder.setAudioEncodingBitRate(camcorderProfile.audioBitRate); mediaRecorder.setAudioSamplingRate(camcorderProfile.audioSampleRate); } mediaRecorder.setVideoEncoder(camcorderProfile.videoCodec); mediaRecorder.setVideoEncodingBitRate(camcorderProfile.videoBitRate); mediaRecorder.setVideoFrameRate(camcorderProfile.videoFrameRate); mediaRecorder.setVideoSize(640, 480);
我的预期是竖屏录制时,输出视频也能保持固定的横屏分辨率。此前在Stack Overflow找到过类似问题,但没有得到满意的解决方案。
在iOS端,我通过AVMutableVideoComposition在录制完成后对视频进行转换,实现了需求,代码如下:
let vComp = AVMutableVideoComposition() vComp.renderSize = CGSize(width: CustomConsts.SAVE_WIDTH, height: CustomConsts.SAVE_HEIGHT) vComp.frameDuration = CMTimeMake(value: 1, timescale: Int32(CustomConsts.SAVE_FRAME_RATE)) // fps let instruction = AVMutableVideoCompositionInstruction() instruction.timeRange = CMTimeRangeMake(start: CMTime.zero, duration: vTrack.timeRange.duration) let transformer = AVMutableVideoCompositionLayerInstruction(assetTrack: vTrack) var videoSize = vTrack.naturalSize videoSize = CGSize(width: videoSize.height, height: videoSize.width) let ratio = CGFloat(CustomConsts.SAVE_WIDTH) / videoSize.width let resizedVideoSize = CGSize(width: videoSize.width * ratio, height: videoSize.height * ratio) let t1 = CGAffineTransform(rotationAngle: 90 * CGFloat.pi / 180) let t2 = CGAffineTransform(scaleX: ratio, y: ratio) let t3 = CGAffineTransform(translationX: resizedVideoSize.width, y: -(resizedVideoSize.height - CGFloat(CustomConsts.SAVE_HEIGHT)) / 2) transformer.setTransform(t1.concatenating(t2).concatenating(t3), at: CMTime.zero) instruction.layerInstructions = [transformer] vComp.instructions = [instruction]
请问Android端有没有类似的实现方式?
解决方案
Android端可以通过原生API或第三方库实现类似iOS的视频后期转码处理,以下是三种常用方案:
方案一:原生MediaCodec+MediaMuxer手动处理
通过提取原始视频帧,进行旋转、缩放变换后重新编码封装,核心步骤:
- 用
MediaExtractor读取原始视频的轨道信息,获取宽高、旋转角度等参数。 - 初始化
MediaCodec解码原始视频,得到可编辑的视频帧。 - 根据原始视频的旋转角度(竖屏录制通常为90/270度),将帧旋转为横屏方向,再缩放至目标分辨率(640×480)。
- 用另一个
MediaCodec编码变换后的帧,最后通过MediaMuxer封装成最终视频文件。
核心代码片段:
// 提取视频基础信息 MediaExtractor extractor = new MediaExtractor(); extractor.setDataSource(inputPath); int videoTrackIndex = -1; MediaFormat videoFormat = null; for (int i = 0; i < extractor.getTrackCount(); i++) { MediaFormat format = extractor.getTrackFormat(i); String mime = format.getString(MediaFormat.KEY_MIME); if (mime.startsWith("video/")) { videoTrackIndex = i; videoFormat = format; break; } } extractor.selectTrack(videoTrackIndex); int originalWidth = videoFormat.getInteger(MediaFormat.KEY_WIDTH); int originalHeight = videoFormat.getInteger(MediaFormat.KEY_HEIGHT); int rotation = videoFormat.containsKey(MediaFormat.KEY_ROTATION) ? videoFormat.getInteger(MediaFormat.KEY_ROTATION) : 0; // 后续解码、帧变换、编码、封装逻辑需补充,可结合OpenGL ES实现高效的帧旋转缩放
方案二:AndroidX VideoEditor(Android 10+)
Android 10及以上版本提供的官方视频编辑库,可快速实现旋转、缩放、输出固定分辨率:
- 添加依赖:
implementation "androidx.video:video-editor:1.0.0-alpha08"
- 核心实现代码:
// 创建编辑会话 VideoEditor videoEditor = new VideoEditor(context); MediaSource mediaSource = MediaSource.fromUri(context, Uri.parse(inputPath)); EditingSession editingSession = videoEditor.createEditingSession(mediaSource); // 设置输出分辨率 OutputOptions outputOptions = new OutputOptions.Builder() .setOutputFormat(Muxer.OutputFormat.MPEG_4) .setResolution(new Size(640, 480)) .build(); // 添加旋转+缩放变换 TransformEffect transformEffect = new TransformEffect.Builder() .setRotation(rotation) // 根据原始视频旋转角度设置,竖屏录制一般设为90 .setScaleType(TransformEffect.ScaleType.FIT) .build(); editingSession.addEffect(transformEffect, TrackType.VIDEO); // 执行导出 editingSession.startExport(outputOptions, outputPath, new ExportCallback() { @Override public void onExportProgress(float progress) {} @Override public void onExportCompleted() {} @Override public void onExportFailed(@NonNull ExportException exportException) {} });
方案三:FFmpeg第三方库(兼容全版本)
通过FFmpeg命令行快速完成视频旋转、缩放和转码,适合低版本Android系统:
- 集成FFmpeg库:
implementation "com.arthenica:ffmpeg-kit:5.1.LTS"
- 执行转码命令:
// 竖屏转横屏+缩放到640×480 String command = "-i " + inputPath + " -vf \"transpose=1,scale=640:480\" -c:v libx264 -crf 23 -preset medium " + outputPath; FFmpegKit.execute(command);
transpose=1:顺时针旋转90度(适配竖屏转横屏)scale=640:480:缩放到目标分辨率- 可根据实际情况调整旋转参数(
transpose=0逆时针90度,transpose=2顺时针180度等)
另外,你调用setVideoSize无效的原因是CamcorderProfile的参数会覆盖手动设置的分辨率,建议先调用setVideoSize,再配置CamcorderProfile相关参数,或者直接手动配置编码器参数,不依赖CamcorderProfile。
内容的提问来源于stack exchange,提问作者Vũ Thao
相关产品推荐
相关产品推荐

