feat: 视频补充帧跳转功能 (#3653)

This commit is contained in:
liaoxuezhi 2022-02-28 18:45:33 +08:00 committed by GitHub
parent b8123a92d0
commit 93fedfb4a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 72 additions and 17 deletions

View File

@ -25,16 +25,56 @@ order: 71
- `video/x-flv`,使用 [mpegts.js](https://github.com/xqq/mpegts.js) 播放 flv
- `application/x-mpegURL`,使用 [hls.js](https://github.com/video-dev/hls.js/) 播放 hls 格式
## 视频帧切换功能
可以定义一组视频帧,渲染的时候会列出来这些帧,点击的时候会自动跳转到对应位置开始播放。
```schema: scope="body"
{
"type": "video",
"src": "https://amis.bj.bcebos.com/amis/2019-12/1577157317579/trailer_hd.mp4",
"poster": "https://internal-amis-res.cdn.bcebos.com/images/2019-12/1577157239810/da6376bf988c.png",
"jumpFrame": true,
"jumpBufferDuration": 0,
frames: {
'00:10': '',
'00:20': '',
'00:30': ''
},
}
```
可以设置帧图片如果有的话,这个示例偷懒直接用封面了。
```schema: scope="body"
{
"type": "video",
"src": "https://amis.bj.bcebos.com/amis/2019-12/1577157317579/trailer_hd.mp4",
"poster": "https://internal-amis-res.cdn.bcebos.com/images/2019-12/1577157239810/da6376bf988c.png",
"jumpFrame": true,
"jumpBufferDuration": 0,
stopOnNextFrame: true,
frames: {
'00:10': 'https://internal-amis-res.cdn.bcebos.com/images/2019-12/1577157239810/da6376bf988c.png',
'00:20': 'https://internal-amis-res.cdn.bcebos.com/images/2019-12/1577157239810/da6376bf988c.png',
'00:30': 'https://internal-amis-res.cdn.bcebos.com/images/2019-12/1577157239810/da6376bf988c.png'
},
}
```
## 属性表
| 属性名 | 类型 | 默认值 | 说明 |
| --------- | --------- | --------- | -------------------------------------------------------- |
| type | `string` | `"video"` | 指定为 video 渲染器 |
| className | `string` | | 外层 Dom 的类名 |
| src | `string` | | 视频地址 |
| isLive | `boolean` | false | 是否为直播,视频为直播时需要添加上,支持`flv`和`hls`格式 |
| videoType | `string` | | 指定直播视频格式 |
| poster | `string` | | 视频封面地址 |
| muted | `boolean` | | 是否静音 |
| autoPlay | `boolean` | | 是否自动播放 |
| rates | `array` | | 倍数,格式为`[1.0, 1.5, 2.0]` |
| 属性名 | 类型 | 默认值 | 说明 |
| ------------------ | --------- | --------- | ------------------------------------------------------------------------- |
| type | `string` | `"video"` | 指定为 video 渲染器 |
| className | `string` | | 外层 Dom 的类名 |
| src | `string` | | 视频地址 |
| isLive | `boolean` | false | 是否为直播,视频为直播时需要添加上,支持`flv`和`hls`格式 |
| videoType | `string` | | 指定直播视频格式 |
| poster | `string` | | 视频封面地址 |
| muted | `boolean` | | 是否静音 |
| autoPlay | `boolean` | | 是否自动播放 |
| rates | `array` | | 倍数,格式为`[1.0, 1.5, 2.0]` |
| frames | `object` | | key 是时刻信息value 可以可以为空,可有设置为图片地址,请看上方示例 |
| jumpBufferDuration | `boolean` | | 点击帧的时候默认是跳转到对应的时刻,如果想提前 3 秒钟,可以设置这个值为 3 |
| stopOnNextFrame | `boolean` | | 到了下一帧默认是接着播放,配置这个会自动停止 |

View File

@ -113,6 +113,12 @@ export interface VideoSchema extends BaseSchema {
*
*/
jumpBufferDuration?: number;
/**
*
*
*/
stopOnNextFrame?: boolean;
}
const str2seconds: (str: string) => number = str =>
@ -389,6 +395,7 @@ export default class Video extends React.Component<VideoProps, VideoState> {
player: any;
times: Array<number>;
currentIndex: number;
manualJump = false;
constructor(props: VideoProps) {
super(props);
@ -459,6 +466,7 @@ export default class Video extends React.Component<VideoProps, VideoState> {
let index = 0;
const times = this.times;
const len = times.length;
const stopOnNextFrame = this.props.stopOnNextFrame;
while (index < len - 1) {
if (
times[index + 1] &&
@ -472,6 +480,12 @@ export default class Video extends React.Component<VideoProps, VideoState> {
if (this.currentIndex !== index) {
this.moveCursorToIndex(index);
stopOnNextFrame && !this.manualJump && player.pause();
if (this.manualJump) {
this.manualJump = false;
}
}
});
}
@ -505,6 +519,7 @@ export default class Video extends React.Component<VideoProps, VideoState> {
const times = this.times;
const player = this.player;
this.manualJump = true;
player.seek(times[index] - jumpBufferDuration);
player.play();
}
@ -572,11 +587,11 @@ export default class Video extends React.Component<VideoProps, VideoState> {
}
return (
<div className="pull-in-xxs" key={i}>
<div className={`${ns}Hbox ${ns}Video-frameItem`}>
<div className="pull-in-xs" key={i}>
<div className={cx(`Hbox Video-frameItem`)}>
{items.map((item, key) => (
<div
className={`${ns}Hbox-col Wrapper--xxs ${ns}Video-frame`}
className={cx(`Hbox-col Wrapper--xs Video-frame`)}
key={key}
onClick={() =>
this.jumpToIndex(i * (columnsCount as number) + key)
@ -585,7 +600,7 @@ export default class Video extends React.Component<VideoProps, VideoState> {
{item.src ? (
<img className="w-full" alt="poster" src={item.src} />
) : null}
<div className={`${ns}Video-frameLabel`}>{item.time}</div>
<div className={cx(`Video-frameLabel`)}>{item.time}</div>
</div>
))}
@ -593,7 +608,7 @@ export default class Video extends React.Component<VideoProps, VideoState> {
/* 补充空白 */ restCount
? blankArray.map((_, index) => (
<div
className={`${ns}Hbox-col Wrapper--xxs`}
className={cx(`Hbox-col Wrapper--xs`)}
key={`blank_${index}`}
/>
))
@ -604,7 +619,7 @@ export default class Video extends React.Component<VideoProps, VideoState> {
);
})}
{jumpFrame ? (
<span ref={this.cursorRef} className={`${ns}Video-cursor`} />
<span ref={this.cursorRef} className={cx('Video-cursor')} />
) : null}
</div>
);