mirror of
https://github.com/vdalex25/rtsp-to-web-player.git
synced 2025-09-26 21:01:42 +08:00
Add react component example
This commit is contained in:
16
examples/ReactComponent/README.md
Normal file
16
examples/ReactComponent/README.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# React Player Component
|
||||||
|
|
||||||
|
## Project setup
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and hot-reloads for development
|
||||||
|
```
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and minifies for production
|
||||||
|
```
|
||||||
|
npm run build
|
||||||
|
```
|
34
examples/ReactComponent/package.json
Normal file
34
examples/ReactComponent/package.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"name": "rtsp-to-web-react",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"cra-template": "1.1.3",
|
||||||
|
"react": "^18.0.0",
|
||||||
|
"react-dom": "^18.0.0",
|
||||||
|
"react-scripts": "^5.0.0",
|
||||||
|
"rtsptowebplayer": "github:vdalex25/rtsp-to-web-player#51832916615d9e6c72ae2962ebec35a5061eb775"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "react-scripts start",
|
||||||
|
"build": "react-scripts build"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"extends": [
|
||||||
|
"react-app",
|
||||||
|
"react-app/jest"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"browserslist": {
|
||||||
|
"production": [
|
||||||
|
">0.2%",
|
||||||
|
"not dead",
|
||||||
|
"not op_mini all"
|
||||||
|
],
|
||||||
|
"development": [
|
||||||
|
"last 1 chrome version",
|
||||||
|
"last 1 firefox version",
|
||||||
|
"last 1 safari version"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
13
examples/ReactComponent/public/index.html
Normal file
13
examples/ReactComponent/public/index.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>RTSPtoWEBPlayerReact</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
<div id="root"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
29
examples/ReactComponent/src/App.js
Normal file
29
examples/ReactComponent/src/App.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import ReactPlayer from "./components/react-player/react-player";
|
||||||
|
import {useState} from "react";
|
||||||
|
import InputGroup from "./components/input-group";
|
||||||
|
|
||||||
|
const App = () => {
|
||||||
|
|
||||||
|
const [url, setUrl] = useState(null);
|
||||||
|
|
||||||
|
return (<div className="container mt-3">
|
||||||
|
<h3 className="text-center">Simple Example RTSPtoWEB player React</h3>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12">
|
||||||
|
<InputGroup setUrl={setUrl}/>
|
||||||
|
</div>
|
||||||
|
<div className="col-12">
|
||||||
|
<div className="card">
|
||||||
|
<div className="card-header">
|
||||||
|
PLAYER
|
||||||
|
</div>
|
||||||
|
<div className="card-body p-0">
|
||||||
|
<ReactPlayer url={url}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
15
examples/ReactComponent/src/components/control-btn.js
Normal file
15
examples/ReactComponent/src/components/control-btn.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import {ReactComponent as PlayImg} from '../components/images/play.svg';
|
||||||
|
import {ReactComponent as PauseImg} from '../components/images/pause.svg';
|
||||||
|
|
||||||
|
const ControlButton = ({type, onClick}) => {
|
||||||
|
switch (type) {
|
||||||
|
case 'pause':
|
||||||
|
return (<span className="c-button" onClick={onClick}><PlayImg/></span>)
|
||||||
|
case 'play':
|
||||||
|
return (<span className="c-button" onClick={onClick}><PauseImg/></span>)
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ControlButton;
|
15
examples/ReactComponent/src/components/images/pause.svg
Normal file
15
examples/ReactComponent/src/components/images/pause.svg
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
|
||||||
|
viewBox="0 0 499.233 499.233" style="enable-background:new 0 0 499.233 499.233;" xml:space="preserve">
|
||||||
|
|
||||||
|
<g fill="#fff">
|
||||||
|
<path d="M249.617,0C111.917,0,0,111.917,0,249.617s111.917,249.617,249.617,249.617s249.617-111.917,249.617-249.617
|
||||||
|
S387.317,0,249.617,0z M249.617,465.233c-119,0-215.617-96.617-215.617-215.617S130.617,34,249.617,34
|
||||||
|
s215.617,96.617,215.617,215.617S368.617,465.233,249.617,465.233z"/>
|
||||||
|
<path d="M192.667,139.117c-9.35,0-17,7.65-17,17v178.5c0,9.35,7.65,17,17,17c9.35,0,17-7.65,17-17v-178.5
|
||||||
|
C209.667,146.767,202.017,139.117,192.667,139.117z"/>
|
||||||
|
<path d="M308.833,139.117c-9.35,0-17,7.65-17,17v178.5c0,9.35,7.65,17,17,17s17-7.65,17-17v-178.5
|
||||||
|
C325.833,146.767,318.183,139.117,308.833,139.117z"/>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
</svg>
|
After Width: | Height: | Size: 839 B |
11
examples/ReactComponent/src/components/images/play.svg
Normal file
11
examples/ReactComponent/src/components/images/play.svg
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
|
||||||
|
viewBox="0 0 499.233 499.233" style="enable-background:new 0 0 499.233 499.233;" xml:space="preserve">
|
||||||
|
<g fill="#fff">
|
||||||
|
<path d="M383.067,234.883l-203.15-117.3c-5.383-3.117-11.617-3.117-17,0c-5.383,3.117-8.5,8.783-8.5,14.733v234.317
|
||||||
|
c0,5.95,3.117,11.617,8.5,14.733c2.55,1.417,5.667,2.267,8.5,2.267c2.833,0,5.95-0.85,8.5-2.267l202.867-117.3
|
||||||
|
c5.383-3.117,8.5-8.783,8.5-14.733S388.167,238,383.067,234.883z M188.417,337.45V161.783l151.867,87.833L188.417,337.45z"/>
|
||||||
|
<path d="M249.617,0C111.917,0,0,111.917,0,249.617s111.917,249.617,249.617,249.617s249.617-111.917,249.617-249.617
|
||||||
|
S387.317,0,249.617,0z M249.617,465.233c-119,0-215.617-96.617-215.617-215.617S130.617,34,249.617,34
|
||||||
|
s215.617,96.617,215.617,215.617S368.617,465.233,249.617,465.233z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 866 B |
28
examples/ReactComponent/src/components/input-group.js
Normal file
28
examples/ReactComponent/src/components/input-group.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import {useState} from "react";
|
||||||
|
|
||||||
|
const InputGroup = ({setUrl}) => {
|
||||||
|
|
||||||
|
const [linkInput, setLinkInput] = useState('');
|
||||||
|
const onClickHandler = () => {
|
||||||
|
try {
|
||||||
|
new URL(linkInput);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("URL is not valid ")
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
setUrl(linkInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (<div className="input-group mb-3">
|
||||||
|
<input type="text"
|
||||||
|
className="form-control"
|
||||||
|
placeholder="Type url link here"
|
||||||
|
value={linkInput}
|
||||||
|
onChange={(e) => {
|
||||||
|
setLinkInput(e.target.value);
|
||||||
|
}}/>
|
||||||
|
<button className="btn btn-outline-secondary" type="button" onClick={onClickHandler}>PLAY</button>
|
||||||
|
</div>)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default InputGroup;
|
@@ -0,0 +1,33 @@
|
|||||||
|
.player-wrapper {
|
||||||
|
position: relative;
|
||||||
|
aspectRatio: '16/9';
|
||||||
|
}
|
||||||
|
|
||||||
|
.player-wrapper video {
|
||||||
|
margin-bottom: -6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.player-wrapper .control {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.player-wrapper .control span {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.player-wrapper .control span:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.player-wrapper .control span svg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
48
examples/ReactComponent/src/components/react-player/react-player.js
vendored
Normal file
48
examples/ReactComponent/src/components/react-player/react-player.js
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import {useEffect, useRef, useState} from "react";
|
||||||
|
import './react-player.css';
|
||||||
|
import RTSPtoWEBPlayer from "rtsptowebplayer";
|
||||||
|
import ControlButton from "../control-btn";
|
||||||
|
|
||||||
|
const ReactPlayer = ({url}) => {
|
||||||
|
|
||||||
|
const playerElement = useRef(null);
|
||||||
|
const [player, setPlayer] = useState(null);
|
||||||
|
const [state, setState] = useState('pause');
|
||||||
|
const stateListener = (e) => {
|
||||||
|
setState(e.type);
|
||||||
|
}
|
||||||
|
const playPause = () => {
|
||||||
|
if (player.video.src !== '') {
|
||||||
|
player.video.paused ? player.video.play() : player.video.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (player === null) {
|
||||||
|
setPlayer(new RTSPtoWEBPlayer({
|
||||||
|
parentElement: playerElement.current, controls: false
|
||||||
|
}));
|
||||||
|
} else if (player.video.onpause === null && player.video.onplay === null) {
|
||||||
|
player.video.onpause = stateListener;
|
||||||
|
player.video.onplay = stateListener;
|
||||||
|
}
|
||||||
|
if (url !== null && player !== null) {
|
||||||
|
player.load(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (player !== null) {
|
||||||
|
player.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [url, player]);
|
||||||
|
|
||||||
|
return (<div className="player-wrapper">
|
||||||
|
<div ref={playerElement}/>
|
||||||
|
<div className="control">
|
||||||
|
<ControlButton type={state} onClick={playPause}/>
|
||||||
|
</div>
|
||||||
|
</div>)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ReactPlayer;
|
7
examples/ReactComponent/src/index.js
Normal file
7
examples/ReactComponent/src/index.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import {createRoot} from "react-dom/client";
|
||||||
|
import App from "./App";
|
||||||
|
|
||||||
|
const container = document.getElementById('root');
|
||||||
|
const root = createRoot(container);
|
||||||
|
|
||||||
|
root.render(<App/>);
|
Reference in New Issue
Block a user