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