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

React.js+react-media-recorder:停止录制后关闭摄像头的问题解决

解决React Media Recorder停止录制后摄像头仍运行的问题

问题根源

你的代码存在两个核心问题:

  1. 重复获取媒体流:你在status === "idle"时手动调用getUserMedia获取预览流,而react-media-recorder插件在启动录制时也会独立获取媒体流,导致两个流同时占用摄像头。停止录制时仅尝试停止自己的预览流,插件内部的流仍在运行,摄像头无法关闭。
  2. 无效的停止逻辑:你最初在onStop里重新获取新流并停止,这和当前正在使用的摄像头流完全无关,自然无法关闭摄像头;后来尝试停止previewStream但未处理插件内部的流,仍有残留轨道在占用设备。

解决方案

使用插件内置的预览流管理功能,无需手动获取流,同时配置插件自动停止媒体轨道:

  1. 移除手动获取previewStream的逻辑,直接使用useReactMediaRecorder返回的previewStream。
  2. 添加stopTracksOnStop: true配置项,让插件在停止录制时自动停止所有媒体轨道。
  3. 调整组件渲染逻辑,使用插件提供的流做预览。

修改后的完整代码

import React, { useEffect, useRef} from "react";
import { useReactMediaRecorder } from "react-media-recorder";

const VideoPreview: React.FC<{ stream: MediaStream | null }> = ({ stream }) => {
  const videoRef = useRef<HTMLVideoElement>(null);

  useEffect(() => {
    if (videoRef.current && stream) {
      videoRef.current.srcObject = stream;
    }

    return () => {
      if (videoRef.current) {
        videoRef.current.srcObject = null;
      }
    };
  }, [stream]);

  if (!stream) {
    return null;
  }

  return <video ref={videoRef} width={500} height={500} autoPlay playsInline />;
};

const App: React.FC = () => {
  const { 
    status, 
    startRecording, 
    stopRecording, 
    mediaBlobUrl, 
    clearBlobUrl,
    previewStream // 直接使用插件提供的预览流
  } = useReactMediaRecorder({
    video: true,
    stopTracksOnStop: true, // 停止录制时自动停止媒体轨道
    onStop: () => {
      console.log("录制已停止");
    },
  });

  const handleReset = () => {
    clearBlobUrl();
  };

  return (
    <div className="m-16">
      <>
        {status === "idle" && (
          <button className="bg-yellow-300 mx-5 p-3" onClick={startRecording}>
            Start Recording
          </button>
        )}
        {(status === "recording" || status === "stopped") && (
          <button className="bg-red-400 p-3 mx-5" onClick={stopRecording}>
            Stop Recording
          </button>
        )}
        <button className="bg-lime-500 p-3 mx-5" onClick={handleReset}>
          Reset Recording
        </button>
      </>

      {(status === "idle" || status === "recording") && (
        <VideoPreview stream={previewStream} />
      )}
      {mediaBlobUrl && (
        <video src={mediaBlobUrl} className="m-5 w-88" controls autoPlay />
      )}
    </div>
  );
};

export default App;

关键修改点说明

  • 移除手动流获取:删除了previewStream的useRef和对应的useEffect,改用插件返回的previewStream,避免重复占用摄像头。
  • 启用自动停止轨道:stopTracksOnStop: true会让插件在调用stopRecording时,自动遍历所有媒体轨道并调用track.stop(),彻底释放摄像头设备。
  • 优化视频属性:给预览视频添加playsInline属性,避免在移动端出现全屏播放的问题(可选,但提升用户体验)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 19:07:19