UNPKG

media-stream-player

Version:

Player built on top of media-stream-library

149 lines 6.14 kB
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