WebRTC+RecordRTC录制对等端视频流:方向检测与旋转适配需求
解决WebRTC/RecordRTC录制视频方向不一致的问题
我之前也踩过这个坑!用RecordRTC保存WebRTC对等端的MediaStream时,不同设备输出的视频方向经常乱掉——明明是竖屏录制的视频,录出来却是横的,甚至上下颠倒。折腾了好久,总结出两个靠谱的解决思路,核心都是先拿到视频的原始旋转角度,再针对性修正。
一、先获取视频的原始旋转角度
现代浏览器的MediaStreamTrack提供了getSettings()方法,能直接拿到设备传感器返回的视频旋转参数,这是最关键的一步。这个参数叫videoRotation,值只会是0、90、180、270中的一个,分别对应不同的旋转方向:
- 0:无旋转
- 90:顺时针旋转90度
- 180:顺时针旋转180度(上下颠倒)
- 270:顺时针旋转270度(等同于逆时针90度)
代码示例:
// 假设你已经获取到对等端的MediaStream const videoTrack = peerStream.getVideoTracks()[0]; const trackSettings = videoTrack.getSettings(); const rotationAngle = trackSettings.videoRotation; // 拿到0/90/180/270
注意:旧版浏览器可能不支持这个属性,比如Chrome 69以下,但主流现代浏览器(Chrome 69+、Firefox 63+、Edge 79+)都已经支持了。如果要兼容旧版本,可以用
deviceOrientation事件作为 fallback,但复杂度会高一些。
二、实时修正画面再录制(推荐)
如果不想后期处理,最直接的方式是在录制前,用Canvas把视频帧旋转到正确方向,再录制Canvas的流。这样录出来的视频直接就是正的,不用二次处理。
步骤和代码示例:
function getCorrectedStream(originalStream, rotation) { const video = document.createElement('video'); video.srcObject = originalStream; video.muted = true; video.play(); // 先加载视频流 const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); // 根据旋转角度调整Canvas的宽高(比如90度时,宽是原视频的高,高是原视频的宽) if (rotation === 90 || rotation === 270) { canvas.width = video.videoHeight; canvas.height = video.videoWidth; } else { canvas.width = video.videoWidth; canvas.height = video.videoHeight; } // 定时绘制视频帧到Canvas,做旋转处理 setInterval(() => { ctx.save(); // 先平移到Canvas中心,旋转后再平移回来,确保画面居中 ctx.translate(canvas.width / 2, canvas.height / 2); ctx.rotate((rotation * Math.PI) / 180); ctx.translate(-video.videoWidth / 2, -video.videoHeight / 2); ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight); ctx.restore(); }, 1000/30); // 按30fps绘制,可根据需求调整 // 返回修正后的Canvas流 return canvas.captureStream(30); } // 使用示例 const peerStream = peerConnection.getRemoteStreams()[0]; const videoTrack = peerStream.getVideoTracks()[0]; const rotation = videoTrack.getSettings().videoRotation; const correctedStream = getCorrectedStream(peerStream, rotation); // 用修正后的流开始录制 const recorder = new RecordRTC(correctedStream, { type: 'video' }); recorder.startRecording();
三、录制后批量修正视频
如果已经录好了视频文件,或者需要批量处理,可以用ffmpeg.wasm在浏览器里直接旋转视频。这种方式适合对实时性要求不高的场景。
代码示例:
// 先安装ffmpeg.wasm:npm install @ffmpeg/ffmpeg import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg'; const ffmpeg = createFFmpeg({ log: true }); async function rotateRecordedVideo(inputBlob, rotation) { await ffmpeg.load(); // 加载ffmpeg核心库,首次加载会稍慢 ffmpeg.FS('writeFile', 'input.webm', await fetchFile(inputBlob)); // 根据旋转角度设置ffmpeg的滤镜参数 let rotateFilter = ''; switch(rotation) { case 90: rotateFilter = 'transpose=1'; // 顺时针旋转90度 break; case 180: rotateFilter = 'transpose=2,transpose=2'; // 顺时针旋转180度 break; case 270: rotateFilter = 'transpose=2'; // 逆时针旋转90度 break; default: rotateFilter = ''; // 无需旋转 } if (rotateFilter) { // 旋转视频,音频直接复制不处理 await ffmpeg.run('-i', 'input.webm', '-vf', rotateFilter, '-c:a', 'copy', 'output.webm'); } else { // 无需旋转,直接复制文件 await ffmpeg.run('-i', 'input.webm', '-c', 'copy', 'output.webm'); } // 导出处理后的文件 const outputData = ffmpeg.FS('readFile', 'output.webm'); return new File([outputData.buffer], 'corrected-video.webm', { type: 'video/webm' }); } // 使用示例:录制完成后修正 recorder.stopRecording(() => { const recordedBlob = recorder.getBlob(); rotateRecordedVideo(recordedBlob, rotationAngle).then(correctedFile => { // 下载修正后的视频 const downloadUrl = URL.createObjectURL(correctedFile); const a = document.createElement('a'); a.href = downloadUrl; a.download = 'corrected-video.webm'; a.click(); URL.revokeObjectURL(downloadUrl); }); });
小提示
- 用Canvas实时旋转时,如果是高分辨率视频,可能会有性能损耗,可以考虑降低录制帧率或者用WebGL加速绘制。
- 部分安卓设备的
videoRotation可能返回异常值,建议在实际测试中多覆盖几种设备场景。
内容的提问来源于stack exchange,提问作者Daryl
相关产品推荐
相关产品推荐

