media-stream-player
Version:
Player built on top of media-stream-library
191 lines (190 loc) • 6.36 kB
JavaScript
import React, { useCallback, useEffect, useState } from 'react';
import styled from 'styled-components';
import { useInterval } from 'react-hooks-shareable';
import { Format } from './PlaybackArea';
import { StreamStats } from './img';
const isHtml5VideoPipeline = (pipeline) => {
var _a;
return ((_a = pipeline) === null || _a === void 0 ? void 0 : _a.tracks) !== undefined;
};
const StatsWrapper = styled.div `
position: absolute;
top: 24px;
left: 24px;
width: 360px;
min-width: 240px;
max-width: 80%;
max-height: 80%;
border-radius: 4px;
background: #292929 0% 0% no-repeat padding-box;
opacity: 0.88;
`;
const StatsHeader = styled.div `
padding: 8px 24px;
border-bottom: 1px solid #525252;
`;
const StatsIcon = styled.span `
width: 24px;
height: 24px;
float: left;
cursor: ${({ clickable }) => (clickable ? 'pointer' : 'default')};
& > svg {
fill: #e0e0e0;
}
`;
const StatsTitle = styled.span `
display: inline-block;
margin-left: 8px;
vertical-align: sub;
text-align: left;
font-size: 16px;
font-family: 'Open Sans', Sans-Serif;
line-height: 22px;
color: #f5f5f5;
`;
const StatsHide = styled.span `
float: right;
text-align: right;
`;
const HideLink = styled.a `
vertical-align: sub;
text-decoration: none;
font-size: 16px;
font-family: 'Open Sans', Sans-Serif;
line-height: 22px;
color: #b8b8b8;
`;
const Data = styled.div `
display: grid;
grid-template-columns: repeat(3, 1fr);
column-gap: 24px;
row-gap: 16px;
width: 100%;
padding: 16px 24px 24px;
`;
const StatItem = styled.div `
text-align: left;
font-family: 'Open Sans', Sans-Serif;
`;
const StatName = styled.div `
font-size: 12px;
line-height: 17px;
color: #b8b8b8;
`;
const StatValue = styled.div `
font-size: 13px;
line-height: 18px;
color: #e0e0e0;
`;
const StatsShow = styled.div `
position: absolute;
top: 24px;
left: 24px;
width: 32px;
height: 32px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 4px;
background: #292929 0% 0% no-repeat padding-box;
opacity: 0.88;
`;
const StatsData = ({ format, videoProperties, refresh, volume, }) => {
const [stats, setStats] = useState([]);
// Updates stat values
const updateValues = useCallback(() => {
var _a;
let streamType = 'Unknown';
if (format === Format.JPEG) {
streamType = 'Still image';
}
else if (format === Format.RTP_H264) {
streamType = 'RTSP (WebSocket)';
}
else if (format === Format.RTP_JPEG) {
streamType = 'MJPEG';
}
else if (format === Format.MP4_H264) {
streamType = 'MP4 (HTTP)';
}
const { width, height, pipeline } = videoProperties;
let statsData = [
{
name: 'Stream type',
value: streamType,
},
{
name: 'Resolution',
value: `${width}x${height}`,
},
{
name: 'Refreshed',
value: refresh,
unit: refresh > 1 ? 'times' : 'time',
},
];
if (isHtml5VideoPipeline(pipeline)) {
const tracks = (_a = pipeline.tracks) === null || _a === void 0 ? void 0 : _a.map((track, index) => Object.assign({ index }, track));
const videoTrack = tracks === null || tracks === void 0 ? void 0 : tracks.find((track) => track.type === 'video');
if (videoTrack !== undefined) {
const { coding, profile, level } = videoTrack === null || videoTrack === void 0 ? void 0 : videoTrack.codec;
const framerate = Number(pipeline.framerate[videoTrack.index].toFixed(2));
const bitrate = Math.round(pipeline.bitrate[videoTrack.index] / 1000);
statsData = statsData.concat([
{
name: 'Encoding',
value: `${coding} ${profile} (${level})`,
},
{
name: 'Frame rate',
value: framerate,
unit: 'fps',
},
{
name: 'Bitrate',
value: bitrate,
unit: 'kbit/s',
},
]);
}
}
if (volume !== undefined) {
statsData.push({
name: 'Volume',
value: Math.floor(volume * 100),
unit: '%',
});
}
setStats(statsData);
}, [format, refresh, videoProperties, volume]);
useEffect(() => {
updateValues();
}, [updateValues]);
useInterval(updateValues, 1000);
return (React.createElement(Data, null, stats.length > 0
? stats.map((stat) => {
return (React.createElement(StatItem, { key: stat.name },
React.createElement(StatName, null, stat.name),
React.createElement(StatValue, null, `${stat.value} ${stat.unit !== undefined ? stat.unit : ''}`)));
})
: null));
};
export const Stats = ({ format, videoProperties, refresh, volume, }) => {
const [showStats, setShowStats] = useState(true);
// Handles show/hide stats
const onToggleStats = useCallback((e) => {
e.preventDefault();
setShowStats((prevState) => !prevState);
}, [setShowStats]);
return (React.createElement(React.Fragment, null, showStats ? (React.createElement(StatsWrapper, null,
React.createElement(StatsHeader, null,
React.createElement(StatsIcon, { clickable: false },
React.createElement(StreamStats, null)),
React.createElement(StatsTitle, null, "Client stream data"),
React.createElement(StatsHide, null,
React.createElement(HideLink, { href: "", onClick: onToggleStats }, "Hide"))),
React.createElement(StatsData, { format: format, videoProperties: videoProperties, refresh: refresh, volume: volume }))) : (React.createElement(StatsShow, null,
React.createElement(StatsIcon, { onClick: onToggleStats, clickable: true },
React.createElement(StreamStats, { title: "Show client stream data" }))))));
};
//# sourceMappingURL=Stats.js.map