media-stream-player
Version:
Player built on top of media-stream-library
149 lines • 6.14 kB
JavaScript
import React, { useState, useEffect, useRef } from 'react';
import styled from 'styled-components';
import debug from 'debug';
import { pipelines, utils, } from 'media-stream-library';
import { useEventState } from './hooks/useEventState';
import { attachMetadataHandler, } from './metadata';
const debugLog = debug('msp:ws-rtsp-video');
const VideoNative = styled.video `
max-height: 100%;
object-fit: contain;
width: 100%;
`;
export const WsRtspVideo = ({ forwardedRef, play = false, ws, rtsp, autoPlay = true, muted = true, onPlaying, onSdp, metadataHandler, offset = 0, autoRetry = false, }) => {
let videoRef = useRef(null);
// Forwarded refs can either be a callback or the result of useRef
if (typeof forwardedRef === 'function') {
forwardedRef(videoRef.current);
}
else if (forwardedRef) {
videoRef = forwardedRef;
}
/**
* Internal state:
* -> canplay: there is enough data on the video element to play.
* -> playing: the video element playback is progressing.
*/
const [canplay, unsetCanplay] = useEventState(videoRef, 'canplay');
const [playing, unsetPlaying] = useEventState(videoRef, 'playing');
// State tied to resources
const [pipeline, setPipeline] = useState(null);
const [fetching, setFetching] = useState(false);
// keep track of changes in starting time
// (offset in seconds to start playing from)
const __offsetRef = useRef(offset);
const __rangeRef = useRef([offset, undefined]);
// keep a stable reference to the external onPlaying callback
const __onPlayingRef = useRef(onPlaying);
__onPlayingRef.current = onPlaying;
const __sensorTmRef = useRef();
useEffect(() => {
var _a;
const videoEl = videoRef.current;
if (videoEl === null) {
return;
}
if (play && canplay === true && playing === false) {
debugLog('play');
videoEl.play().catch((err) => {
console.error('VideoElement error: ', err.message);
});
}
else if (!play && playing === true) {
debugLog('pause');
videoEl.pause();
unsetPlaying();
}
else if (play && playing === true) {
if (__onPlayingRef.current !== undefined) {
__onPlayingRef.current({
el: videoEl,
pipeline: pipeline !== null && pipeline !== void 0 ? pipeline : undefined,
width: videoEl.videoWidth,
height: videoEl.videoHeight,
volume: ((_a = pipeline === null || pipeline === void 0 ? void 0 : pipeline.tracks) === null || _a === void 0 ? void 0 : _a.find((track) => track.type === 'audio'))
? videoEl.volume
: undefined,
range: __rangeRef.current,
sensorTm: __sensorTmRef.current,
});
}
}
}, [play, canplay, playing, unsetPlaying, pipeline]);
// keep a stable reference to the external metadatahandler
const __metadataHandlerRef = useRef(metadataHandler);
__metadataHandlerRef.current = metadataHandler;
useEffect(() => {
const videoEl = videoRef.current;
__offsetRef.current = offset;
if (ws !== undefined &&
ws.length > 0 &&
rtsp !== undefined &&
rtsp.length > 0 &&
videoEl !== null) {
debugLog('create pipeline', ws, rtsp);
const newPipeline = new pipelines.Html5VideoPipeline({
ws: { uri: ws },
rtsp: { uri: rtsp },
mediaElement: videoEl,
});
if (autoRetry) {
utils.addRTSPRetry(newPipeline.rtsp);
}
setPipeline(newPipeline);
let scheduler;
if (__metadataHandlerRef.current !== undefined) {
scheduler = attachMetadataHandler(newPipeline, __metadataHandlerRef.current);
}
return () => {
debugLog('close pipeline and clear video');
newPipeline.close();
videoEl.src = '';
scheduler === null || scheduler === void 0 ? void 0 : scheduler.reset();
setPipeline(null);
setFetching(false);
unsetCanplay();
unsetPlaying();
};
}
}, [ws, rtsp, offset, unsetCanplay, unsetPlaying, autoRetry]);
// keep a stable reference to the external SDP handler
const __onSdpRef = useRef(onSdp);
__onSdpRef.current = onSdp;
useEffect(() => {
if (play && pipeline && !fetching) {
pipeline.ready
.then(() => {
pipeline.onSdp = (sdp) => {
var _a;
const videoMedia = sdp.media.find((m) => {
return m.type === 'video';
});
if (videoMedia !== undefined) {
__sensorTmRef.current =
(_a = videoMedia['x-sensor-transform']) !== null && _a !== void 0 ? _a : videoMedia['transform'];
}
if (__onSdpRef.current !== undefined) {
__onSdpRef.current(sdp);
}
};
pipeline.rtsp.onPlay = (range) => {
if (range !== undefined) {
__rangeRef.current = [
parseFloat(range[0]) || 0,
parseFloat(range[1]) || undefined,
];
}
};
pipeline.rtsp.play(__offsetRef.current);
})
.catch((err) => {
console.error(err);
});
debugLog('initiated data fetching');
setFetching(true);
}
}, [play, pipeline, fetching]);
return React.createElement(VideoNative, { autoPlay: autoPlay, muted: muted, ref: videoRef });
};
//# sourceMappingURL=WsRtspVideo.js.map