3

我正在开发一个更高阶的组件,它将提供使用 MediaRecorder API 捕获媒体的能力。但是,当我尝试使用捕获的视频(以传递给 createObjectURL 的 Blob 的形式)时,出现错误ERR_REQUEST_RANGE_NOT_SATISFIABLE。当我控制台记录传递给包装组件的 Blob 时,它的长度为 0。我在本文末尾包含了我的代码。

为了诊断问题,我尝试了以下测试:

  • 控制台记录 newChunks inhandleDataAvailable记录正确的值(即[Blob])。
  • 我添加React.useEffect(() => console.log(chunks), [chunks]);是为了查看块是否实际上正在更新。这也会导致记录正确的值(即[Blob])。
  • 我添加React.useEffect(() => console.log(captured), [captured]);是为了查看捕获的是否正在更新。这会导致记录大小为 0 的 Blob。
  • handleStop中,我控制台日志块和通过组合块创建的 blob。这将分别产生一个空数组和一个大小为 0 的 blob。

这让我相信这handleDataAvailable是正确地将每个块添加到块数组中,但不知何故,数组handleStop在运行时被清空了。

有谁看到可能导致这种情况发生的原因?

代码:

import React from 'react';

import { getUserMedia, getConstraints } from '../../utils/general';

const withMediaCapture = (WrappedComponent, recordingType, facingMode, deviceID) => {
  const constraints = getConstraints(recordingType, facingMode, deviceID);

  const type = recordingType === 'audio'
    ? 'audio/ogg; codecs=opus'
    : 'video/webm; codecs=vp9';

  return props => {
    const [mediaStream, setMediaStream] = React.useState(undefined);
    const [mediaRecorder, setMediaRecorder] = React.useState(undefined);
    const [isRecording, setIsRecording] = React.useState(false);
    const [captured, setCaptured] = React.useState(undefined);
    const [chunks, setChunks] = React.useState([]);

    // On mount, get the mediaStream:
    const setupStream = () => {
      getUserMedia(constraints)
      .then(setMediaStream)
      .catch(error => {/* TODO: Handle error */});
    };
    React.useEffect(setupStream, []);

    // Once we have gotten the mediaStream, get the mediaRecorder:
    const handleDataAvailable = ({ data }) => {
      const newChunks = [...chunks, data];
      setChunks(newChunks);
    };
    const handleStop = foo => {
      const blob = new Blob(chunks, { type });
      setCaptured(blob);
      setChunks([]);
    }
    const getMediaRecorder = () => {
      mediaStream && setMediaRecorder(Object.assign(
        new MediaRecorder(mediaStream),
        {
          ondataavailable: handleDataAvailable,
          onstop: handleStop,
        },
      ));
    }
    React.useEffect(getMediaRecorder, [mediaStream]);

    const toggleRecording = () => {
      isRecording
        ? mediaRecorder.stop()
        : mediaRecorder.start();
      setIsRecording(!isRecording);
    };

    return <WrappedComponent {...{ preview: mediaStream, captured, toggleRecording, isRecording, ...props }} />;
  };
};

const VideoCaptureDemo = ({ preview, captured, toggleRecording, isRecording }) => {
  const previewRef = React.useRef(null);
  const capturedRef = React.useRef(null);

  const setupPreview = () => {
    previewRef.current.srcObject = preview;
  };
  React.useEffect(setupPreview, [preview]);

  const setupCaptured = () => {
    const url = captured && window.URL.createObjectURL(captured);
    capturedRef.current.src = url;
  };
  React.useEffect(setupCaptured, [captured]);

  return (
    <div>
      <video ref={previewRef} autoPlay={true} muted={true} />
      <video ref={capturedRef} controls />
      <button onClick={toggleRecording}>
        {isRecording ? 'Stop Recording' : 'Start Recording'}
      </button>
    </div>
  );
};

export default withMediaCapture(VideoCaptureDemo, 'videoAndAudio');
4

1 回答 1

3

handleStop并且handleDataAvailable都关闭了初始的空chunks数组。如果handleDataAvailable被多次调用,较早的块将会丢失,并且handleStop总是会从空的块数组中创建一个 Blob。引起的重新渲染setChunks将导致创建新版本的handle方法,但 MediaRecorder 仍将使用创建 MediaRecorder 时的版本。

您可以handleDataAvailable通过使用功能更新来修复,但为了修复,handleStop我认为您最好切换到使用 useReducer (减速器同时管理chunkscaptured),这样您就可以调度一个动作,然后减速器可以访问当前块并适当地创建 Blob。

于 2019-04-03T16:35:05.107 回答