Я работаю над компонентом более высокого порядка, который предоставит возможность захвата мультимедиа с помощью API MediaRecorder. Однако, когда я пытаюсь использовать захваченное видео (в виде BLOB-объекта, переданного createObjectURL), я получаю сообщение об ошибке ERR_REQUEST_RANGE_NOT_SATISFIABLE
. Когда я веду консольный журнал BLOB-объекта, который передается упакованному компоненту, он имеет длину 0. Я включил свой код в конец этого поста.
Для диагностики проблемы я попробовал следующие тесты:
- Запись в консоли newChunks в
handleDataAvailable
записывает правильное значение (т. Е. [Blob]
).
- Я добавил
React.useEffect(() => console.log(chunks), [chunks]);
, чтобы посмотреть, действительно ли обновляются чанки. Это также приводит к регистрации правильного значения (т. Е. [Blob]
).
- Я добавил
React.useEffect(() => console.log(captured), [captured]);
, чтобы увидеть, обновляется ли захваченный. Это приводит к регистрации большого размера размером 0.
- В
handleStop
я поддерживаю порции журнала и большой двоичный объект, созданный путем объединения порций. В результате получается пустой массив и BLOB-объект с размером 0 соответственно.
Это наводит меня на мысль, что 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');