@vtx/player 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/lib/index.es.js +533 -0
  2. package/lib/index.es.js.map +1 -0
  3. package/lib/index.umd.js +533 -0
  4. package/lib/index.umd.js.map +1 -0
  5. package/lib/types/api/fetch.d.ts +12 -0
  6. package/lib/types/api/index.d.ts +16 -0
  7. package/{src/api/types.ts → lib/types/api/types.d.ts} +7 -31
  8. package/lib/types/components/bill-player/index.d.ts +21 -0
  9. package/lib/types/components/controls/index.d.ts +52 -0
  10. package/lib/types/components/history-control/index.d.ts +39 -0
  11. package/lib/types/components/history-player/index.d.ts +31 -0
  12. package/lib/types/components/live-channel-player/index.d.ts +18 -0
  13. package/lib/types/components/live-control/index.d.ts +35 -0
  14. package/lib/types/components/live-player/index.d.ts +22 -0
  15. package/lib/types/components/player/index.d.ts +84 -0
  16. package/lib/types/context/index.d.ts +8 -0
  17. package/lib/types/hooks/useSettings.d.ts +9 -0
  18. package/lib/types/icons/index.d.ts +54 -0
  19. package/{src/main.ts → lib/types/main.d.ts} +0 -1
  20. package/lib/types/utils/index.d.ts +60 -0
  21. package/package.json +7 -5
  22. package/.eslintignore +0 -11
  23. package/.eslintrc.js +0 -31
  24. package/.prettierignore +0 -10
  25. package/.prettierrc.js +0 -22
  26. package/.storybook/main.js +0 -58
  27. package/.storybook/manager.js +0 -7
  28. package/.storybook/preview-head.html +0 -5
  29. package/.storybook/preview.js +0 -9
  30. package/.storybook/proxy.js +0 -6
  31. package/.storybook/theme.js +0 -8
  32. package/.stylelintrc.json +0 -13
  33. package/.vscode/extensions.json +0 -10
  34. package/.vscode/settings.json +0 -16
  35. package/commitlint.config.js +0 -10
  36. package/public/h5player.min.js +0 -311
  37. package/public/playctrl1/AudioRenderer.js +0 -225
  38. package/public/playctrl1/DecodeWorker.js +0 -711
  39. package/public/playctrl1/Decoder.js +0 -1
  40. package/public/playctrl1/SuperRender_10.js +0 -396
  41. package/public/playctrl2/Decoder.js +0 -21
  42. package/public/playctrl2/Decoder.wasm +0 -0
  43. package/public/playctrl2/Decoder.worker.js +0 -1
  44. package/public/playctrl3/Decoder.js +0 -21
  45. package/public/playctrl3/Decoder.wasm +0 -0
  46. package/public/playctrl3/Decoder.worker.js +0 -1
  47. package/rollup.config.js +0 -52
  48. package/src/api/fetch.ts +0 -50
  49. package/src/api/index.ts +0 -44
  50. package/src/components/bill-player/index.less +0 -58
  51. package/src/components/bill-player/index.stories.mdx +0 -24
  52. package/src/components/bill-player/index.stories.tsx +0 -14
  53. package/src/components/bill-player/index.tsx +0 -269
  54. package/src/components/controls/images/arrow.png +0 -0
  55. package/src/components/controls/images/error.png +0 -0
  56. package/src/components/controls/index.less +0 -182
  57. package/src/components/controls/index.tsx +0 -312
  58. package/src/components/history-control/images/collapse.png +0 -0
  59. package/src/components/history-control/index.less +0 -211
  60. package/src/components/history-control/index.stories.mdx +0 -64
  61. package/src/components/history-control/index.stories.tsx +0 -140
  62. package/src/components/history-control/index.tsx +0 -344
  63. package/src/components/history-player/index.less +0 -98
  64. package/src/components/history-player/index.stories.mdx +0 -38
  65. package/src/components/history-player/index.stories.tsx +0 -12
  66. package/src/components/history-player/index.tsx +0 -205
  67. package/src/components/live-channel-player/index.stories.mdx +0 -29
  68. package/src/components/live-channel-player/index.stories.tsx +0 -11
  69. package/src/components/live-channel-player/index.tsx +0 -79
  70. package/src/components/live-control/index.less +0 -65
  71. package/src/components/live-control/index.stories.mdx +0 -66
  72. package/src/components/live-control/index.stories.tsx +0 -69
  73. package/src/components/live-control/index.tsx +0 -255
  74. package/src/components/live-player/index.less +0 -71
  75. package/src/components/live-player/index.stories.mdx +0 -35
  76. package/src/components/live-player/index.stories.tsx +0 -12
  77. package/src/components/live-player/index.tsx +0 -118
  78. package/src/components/player/index.ts +0 -293
  79. package/src/context/index.ts +0 -13
  80. package/src/hooks/useSettings.tsx +0 -14
  81. package/src/icons/index.less +0 -27
  82. package/src/icons/index.tsx +0 -518
  83. package/src/stories/intro.stories.mdx +0 -16
  84. package/src/typings/@vtx/utils/index.d.ts +0 -27
  85. package/src/typings/h5player.d.ts +0 -133
  86. package/src/utils/index.ts +0 -177
  87. package/src/vite-env.d.ts +0 -1
  88. package/tsconfig.json +0 -24
@@ -1,255 +0,0 @@
1
- import './index.less';
2
-
3
- import { forwardRef, useEffect, useImperativeHandle, useRef } from 'react';
4
-
5
- import { useFullscreen, useRequest, useSetState } from 'ahooks';
6
- import { Space, Tooltip } from 'antd';
7
-
8
- import { getPreviewUrl } from '@/api';
9
- import { PlayerHeader } from '@/components/controls';
10
- import VtxLivePlayer from '@/components/live-player';
11
- import {
12
- CloseAllIcon,
13
- ExitFullScreenIcon,
14
- ExpandIcon,
15
- FoldIcon,
16
- FullScreenIcon,
17
- Grid1x1Icon,
18
- Grid2x2Icon,
19
- Grid3x3Icon,
20
- } from '@/icons';
21
-
22
- export type LiveControlHandle = {
23
- /** 加载视频 */
24
- load: (channel: ChannelType) => void;
25
- /** 卸载视频,参数为通道编号 */
26
- unLoad: (channelNum: string) => void;
27
- /** 一次加载多个视频,适用于初始化 */
28
- multiLoad: (channels: ChannelType[]) => void;
29
- };
30
-
31
- interface LiveControlProps {
32
- /** 展开/收缩按钮回调 */
33
- onExpandChange?: (expand: boolean) => void;
34
- /** 视频关闭回调,参数为通道编号数组 */
35
- onChannelChange?: (channelSNum: string[]) => void;
36
- /** 宽度 */
37
- width?: number | string;
38
- /** 高度 */
39
- height?: number | string;
40
- }
41
- export type ChannelType = {
42
- /** 通道号 */
43
- channelNum: string;
44
- /** 设备ID */
45
- deviceId?: string;
46
- /** 租户ID */
47
- tenantId?: string;
48
- /** 协议 */
49
- protocol?: string;
50
- };
51
- interface State {
52
- /** 展开/收缩 */
53
- expand: boolean;
54
- /** 网格布局 */
55
- grid: 1 | 2 | 3;
56
- /** 当前激活网格 */
57
- activeIndex: number;
58
- /** 通道配置 */
59
- channels: ChannelType[];
60
- }
61
- const DEFAULT_GRID = 2;
62
- const DEFAULT_ACTIVE = 0;
63
- const DEFAULT_CHANNELS: ChannelType[] = Array(9).fill({ channelNum: '' });
64
- /**
65
- * 实时分屏组件
66
- */
67
- const LiveControl = forwardRef<LiveControlHandle, LiveControlProps>((props, ref) => {
68
- const { height = '100%', width = '100%', onExpandChange, onChannelChange } = props;
69
- const [state, setState] = useSetState<State>({
70
- expand: true,
71
- grid: DEFAULT_GRID,
72
- activeIndex: DEFAULT_ACTIVE,
73
- channels: DEFAULT_CHANNELS,
74
- });
75
- const wrapRef = useRef<HTMLDivElement>(null);
76
- const [isFullscreen, { toggleFullscreen }] = useFullscreen(wrapRef);
77
- useImperativeHandle(ref, () => {
78
- return {
79
- load: (channel) => {
80
- const index = state.channels.findIndex((c) => c.channelNum === channel.channelNum);
81
- if (~index) {
82
- setState({ activeIndex: index }); // 如果通道号已经存在,则设置激活索引为该通道
83
- } else {
84
- // 播放该通道
85
- const newChannels = [...state.channels];
86
- newChannels[state.activeIndex] = channel;
87
- const activeIndex = getActiveIndex(newChannels, state.grid, state.activeIndex);
88
- setState({ channels: newChannels, activeIndex });
89
- }
90
- },
91
- multiLoad: (channels) => {
92
- let grid: 1 | 2 | 3 = 1;
93
- if (channels.length > 1) grid = 2;
94
- if (channels.length > 4) grid = 3;
95
- const newChannels = [];
96
- for (let i = 0; i < 9; i++) {
97
- newChannels.push(channels[i] ? channels[i] : { channelNum: '' });
98
- }
99
- setState({ grid, channels: newChannels });
100
- },
101
- unLoad: (channelNum) => {
102
- const index = state.channels.findIndex((c) => c.channelNum === channelNum);
103
- if (~index) {
104
- // 卸载通道
105
- const newChannels = [...state.channels];
106
- newChannels[index] = { channelNum: '' };
107
- setState({ channels: newChannels });
108
- }
109
- },
110
- };
111
- });
112
- useEffect(() => {
113
- if (onChannelChange) {
114
- onChannelChange(state.channels.filter((c) => !!c.channelNum).map((c) => c.channelNum));
115
- }
116
- }, [state.channels]);
117
- const handleCloseAll = () => {
118
- setState({ channels: DEFAULT_CHANNELS });
119
- };
120
-
121
- const handleExpand = () => {
122
- onExpandChange && onExpandChange(!state.expand);
123
- setState({ expand: !state.expand });
124
- };
125
-
126
- const getGridItems = () => {
127
- const items = [];
128
- for (let i = 0; i < state.grid * state.grid; i++) {
129
- const element = (
130
- <GridItem
131
- active={state.activeIndex === i}
132
- key={i}
133
- onClick={() => setState({ activeIndex: i })}
134
- channel={state.channels[i]}
135
- onClose={() => {
136
- const newChannels = [...state.channels];
137
- newChannels[i] = { channelNum: '' };
138
- setState({ channels: newChannels });
139
- }}
140
- />
141
- );
142
- items.push(element);
143
- }
144
- return items;
145
- };
146
-
147
- return (
148
- <div className="vtx-live-control" ref={wrapRef} style={{ height, width }}>
149
- <div className={`player-grid-container _${state.grid}`}>{getGridItems()}</div>
150
- <div className="controls">
151
- <Space className="left" size={12} align="center">
152
- {onExpandChange && (
153
- <Tooltip title={state.expand ? '收起' : '展开'}>
154
- <div onClick={handleExpand}>
155
- {state.expand ? <FoldIcon /> : <ExpandIcon />}
156
- </div>
157
- </Tooltip>
158
- )}
159
- </Space>
160
- <Space className="right" size={12} align="center">
161
- <Tooltip title="全部关闭">
162
- <div>
163
- <CloseAllIcon onClick={handleCloseAll} />
164
- </div>
165
- </Tooltip>
166
- <Tooltip title="1分屏">
167
- <div>
168
- <Grid1x1Icon
169
- active={state.grid === 1}
170
- onClick={() => setState({ grid: 1 })}
171
- />
172
- </div>
173
- </Tooltip>
174
- <Tooltip title="4分屏">
175
- <div>
176
- <Grid2x2Icon
177
- active={state.grid === 2}
178
- onClick={() => setState({ grid: 2 })}
179
- />
180
- </div>
181
- </Tooltip>
182
- <Tooltip title="9分屏">
183
- <div>
184
- <Grid3x3Icon
185
- active={state.grid === 3}
186
- onClick={() => setState({ grid: 3 })}
187
- />
188
- </div>
189
- </Tooltip>
190
- <Tooltip title="全屏">
191
- <div>
192
- {isFullscreen ? (
193
- <ExitFullScreenIcon onClick={toggleFullscreen} />
194
- ) : (
195
- <FullScreenIcon onClick={toggleFullscreen} />
196
- )}
197
- </div>
198
- </Tooltip>
199
- </Space>
200
- </div>
201
- </div>
202
- );
203
- });
204
- LiveControl.displayName = 'LiveControl';
205
-
206
- interface GridItemProps {
207
- /** 选中状态 */
208
- active: boolean;
209
- /** 通道属性 */
210
- channel: ChannelType;
211
- /** 点击操作回调 */
212
- onClick: () => void;
213
- /** 关闭操作回调 */
214
- onClose: () => void;
215
- }
216
- const GridItem: React.FC<GridItemProps> = (props) => {
217
- const { active, onClick, channel, onClose } = props;
218
- const empty = !channel.channelNum;
219
- const { data } = useRequest(() => getPreviewUrl(channel as Required<ChannelType>), {
220
- ready: !!channel.channelNum,
221
- refreshDeps: [channel.channelNum],
222
- });
223
- const name = `${data?.deviceName}-${data?.channelName}`;
224
- return (
225
- <div className={`grid-item-container ${active ? 'active' : ''}`} onClick={onClick}>
226
- {data && !empty && (
227
- <>
228
- <PlayerHeader name={name} onClose={onClose} />
229
- <div className="content">
230
- <VtxLivePlayer url={data.url} captureName={name} talkUrl={data.apiUrl} />
231
- </div>
232
- </>
233
- )}
234
- </div>
235
- );
236
- };
237
-
238
- /**
239
- * 获取当前激活的网格
240
- * @param channels 现有通道数组
241
- * @param grid 当前网格状态
242
- * @param currentIndex 当前索引
243
- * @returns
244
- */
245
- const getActiveIndex = (channels: ChannelType[], grid: 1 | 2 | 3, currentIndex: number) => {
246
- const currentChannels = channels.slice(0, grid * grid);
247
- for (let i = currentIndex + 1; i < currentChannels.length; i++) {
248
- if (!currentChannels[i].channelNum) return i;
249
- }
250
- for (let i = 0; i < currentIndex; i++) {
251
- if (!currentChannels[i].channelNum) return i;
252
- }
253
- return currentIndex;
254
- };
255
- export default LiveControl;
@@ -1,71 +0,0 @@
1
- .vtx-live-player {
2
- position: relative;
3
- display: flex;
4
- align-items: center;
5
- justify-content: center;
6
- background-color: #2b3d51;
7
- border: 1px solid transparent;
8
-
9
- .controls {
10
- position: absolute;
11
- bottom: 0;
12
- display: flex;
13
- align-items: center;
14
- width: 100%;
15
- height: 30px;
16
- padding: 0 12px;
17
- background-color: #131d27;
18
- opacity: 0;
19
- transition: opacity 0.5s;
20
-
21
- .right {
22
- margin-left: auto;
23
-
24
- > div {
25
- height: 24px;
26
- }
27
- }
28
- }
29
-
30
- &:hover {
31
- .controls {
32
- opacity: 1;
33
- }
34
- }
35
-
36
- video {
37
- width: 100%;
38
- height: 100%;
39
- object-fit: fill;
40
- }
41
-
42
- .sub-wnd {
43
- width: 100% !important;
44
- height: 100% !important;
45
- background-color: #2b3d51 !important;
46
- border: 1px solid transparent !important;
47
- }
48
-
49
- .error-container {
50
- position: absolute;
51
- top: 50%;
52
- left: 50%;
53
- display: flex;
54
- flex-direction: column;
55
- align-items: center;
56
- transform: translate(-50%, -50%);
57
-
58
- .text {
59
- margin: 20px 0;
60
- font-size: 14px;
61
- color: rgb(255 255 255 / 65%);
62
- }
63
- }
64
-
65
- .loading-container {
66
- position: absolute;
67
- top: 50%;
68
- left: 50%;
69
- transform: translate(-50%, -50%);
70
- }
71
- }
@@ -1,35 +0,0 @@
1
- import LivePlayer from '.';
2
- import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs';
3
- import { Alert } from 'antd';
4
-
5
- import * as stories from './index.stories';
6
-
7
- <Meta title="组件/实时播放器" />
8
-
9
- # 实时播放器
10
-
11
- ## 引入
12
-
13
- ```js
14
- import { LivePlayer } from '@vtx/player';
15
- ```
16
-
17
- ## 支持的格式
18
-
19
- - 海康 ws,使用海康提供的 h5player.js 实现
20
- - flv,使用 flv.js 实现
21
- - hls,使用 hls.js 实现
22
-
23
- ## 注意
24
-
25
- <Alert message="当type属性为空时,组件将自动根据url判断视频流格式" type="warning" />
26
-
27
- ## 属性
28
-
29
- <ArgsTable of={LivePlayer} />
30
-
31
- ## 例子
32
-
33
- <Canvas>
34
- <Story name="实时播放器" story={stories.Default} />
35
- </Canvas>
@@ -1,12 +0,0 @@
1
- import LivePlayer from '.';
2
- import { ComponentStory } from '@storybook/react';
3
-
4
- const Template: ComponentStory<typeof LivePlayer> = (args) => <LivePlayer {...args} />;
5
-
6
- export const Default = Template.bind({});
7
- Default.args = {
8
- url: '',
9
- width: 1000,
10
- height: 600,
11
- };
12
- export default Default;
@@ -1,118 +0,0 @@
1
- import './index.less';
2
-
3
- import { useEffect, useRef } from 'react';
4
-
5
- import { useFullscreen, useSetState } from 'ahooks';
6
- import { Space } from 'antd';
7
-
8
- import {
9
- CloudControlPanel,
10
- CloudControlPanelProps,
11
- LoadingState,
12
- TalkControl,
13
- VolumeControl,
14
- } from '@/components/controls';
15
- import Player, { VideoType } from '@/components/player';
16
- import { CaptureIcon, CloudControlIcon, ExitFullScreenIcon, FullScreenIcon } from '@/icons';
17
- import { guidGenerator } from '@/utils';
18
-
19
- interface VtxPlayerProps {
20
- /** 视频流地址 */
21
- url: string;
22
- /** 宽度 */
23
- width?: number;
24
- /** 高度 */
25
- height?: number;
26
- /** 视频流格式,如果为空则根据url自行判断 */
27
- type?: VideoType;
28
- /** 截图文件名 */
29
- captureName?: string;
30
- /** 对讲地址 */
31
- talkUrl?: string;
32
- /** 云台控制 */
33
- cloudParams?: CloudControlPanelProps;
34
- }
35
- type State = {
36
- /** 播放状态 */
37
- play: boolean;
38
- /** 错误状态 */
39
- error: boolean;
40
- /** 加载状态 */
41
- loading: boolean;
42
- /** 音量 */
43
- volume: number;
44
- /** id */
45
- id: string;
46
- /** 是否展示云台面板 */
47
- showCloudPanel: boolean;
48
- };
49
- export const LivePlayer = (props: VtxPlayerProps) => {
50
- const { url, width = '100%', height = '100%', captureName, type, talkUrl, cloudParams } = props;
51
- const ref = useRef<HTMLDivElement>(null);
52
- const wrapRef = useRef<HTMLDivElement>(null);
53
- const controlsRef = useRef<HTMLDivElement>(null);
54
- const playerRef = useRef<Player>();
55
- const [isFullscreen, { toggleFullscreen }] = useFullscreen(wrapRef);
56
- const [state, setState] = useSetState<State>({
57
- play: false,
58
- error: false,
59
- loading: false,
60
- id: 'vtx_hk_player_' + guidGenerator(),
61
- volume: 0,
62
- showCloudPanel: false,
63
- });
64
- useEffect(() => {
65
- const container = ref.current;
66
- if (!url || !container) return;
67
- const player = new Player({ url, container, type });
68
- playerRef.current = player;
69
- setState({ loading: true });
70
- player
71
- .play()
72
- .then(() => setState({ play: true, error: false }))
73
- .catch(() => setState({ error: true }))
74
- .finally(() => setState({ loading: false }));
75
- return () => {
76
- player.destroy();
77
- setState({ error: false, loading: false, play: false });
78
- };
79
- }, [url]);
80
- const handleCapture: React.MouseEventHandler = (e) => {
81
- const player = playerRef.current;
82
- player && player.capture(captureName);
83
- e.stopPropagation();
84
- };
85
- const handleFullScreen: React.MouseEventHandler = (e) => {
86
- toggleFullscreen();
87
- const player = playerRef.current;
88
- player && player.resize();
89
- e.stopPropagation();
90
- };
91
- return (
92
- <div className="vtx-live-player" ref={wrapRef} style={{ width, height }}>
93
- <div ref={ref} style={{ height: '100%', width: '100%' }} id={state.id} />
94
- {/* {state.error && <ErrorState onClick={handleRetry} />} */}
95
- {state.loading && <LoadingState />}
96
- {state.showCloudPanel && cloudParams && <CloudControlPanel {...cloudParams} />}
97
- <div className="controls" ref={controlsRef}>
98
- <Space className="right" size={12} align="center">
99
- <VolumeControl player={playerRef.current} container={controlsRef.current} />
100
- <CaptureIcon onClick={handleCapture} />
101
- {talkUrl && <TalkControl player={playerRef.current} url={talkUrl} />}
102
- {cloudParams && (
103
- <CloudControlIcon
104
- active={state.showCloudPanel}
105
- onClick={() => setState({ showCloudPanel: !state.showCloudPanel })}
106
- />
107
- )}
108
- {isFullscreen ? (
109
- <ExitFullScreenIcon onClick={handleFullScreen} />
110
- ) : (
111
- <FullScreenIcon onClick={handleFullScreen} />
112
- )}
113
- </Space>
114
- </div>
115
- </div>
116
- );
117
- };
118
- export default LivePlayer;