Skip to content

Commit 6798882

Browse files
authored
feat: use auto quality (#147)
1 parent 79a8cff commit 6798882

File tree

13 files changed

+103
-58
lines changed

13 files changed

+103
-58
lines changed

example/hls/App.js

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,49 +2,27 @@ import React from 'react'
22
import {hot} from 'react-hot-loader'
33
import PlayerContainer from 'griffith'
44

5-
const duration = 89
6-
75
const sources = {
8-
hd: {
9-
bitrate: 905,
10-
size: 10105235,
11-
duration,
6+
// 注意,这里手动提供了 auto 品质的 source,因此会无视 useAutoQuality 的配置
7+
auto: {
128
format: 'm3u8',
13-
width: 640,
14-
height: 480,
15-
play_url:
16-
'http://zhihu-video-output.oss-cn-hangzhou.aliyuncs.com/test/hd-m3u8/999f95fc-0346-11e9-b494-0a580a44d740.m3u8',
9+
play_url: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',
1710
},
1811
sd: {
19-
bitrate: 580,
20-
size: 6531802,
21-
duration,
22-
format: 'm3u8',
23-
width: 320,
24-
height: 240,
25-
play_url:
26-
'http://zhihu-video-output.oss-cn-hangzhou.aliyuncs.com/test/sd-m3u8/999f95fc-0346-11e9-b494-0a580a44d740.m3u8',
27-
},
28-
ld: {
29-
bitrate: 261,
30-
size: 2984172,
31-
duration,
3212
format: 'm3u8',
33-
width: 160,
34-
height: 120,
3513
play_url:
36-
'http://zhihu-video-output.oss-cn-hangzhou.aliyuncs.com/test/ld-m3u8/999f95fc-0346-11e9-b494-0a580a44d740.m3u8',
14+
'https://test-streams.mux.dev/x36xhzz/url_6/193039199_mp4_h264_aac_hq_7.m3u8',
3715
},
3816
}
3917

4018
const props = {
41-
id: 'zhihu2018',
42-
title: '2018 我们如何与世界相处?',
19+
id: 'test-hls-video',
20+
title: 'Test HLS Video',
4321
standalone: true,
4422
cover: 'https://zhstatic.zhihu.com/cfe/griffith/player.png',
45-
duration,
4623
sources,
4724
shouldObserveResize: true,
25+
autoplay: true,
4826
}
4927

5028
const App = () => <PlayerContainer {...props} />

packages/griffith-hls/src/Video.js

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,62 @@ import Hls from 'hls.js/dist/hls.light.min'
33
import {getMasterM3U8Blob} from './utils'
44

55
export default class Video extends Component {
6+
manuallyBuildAdaptiveM3U8Blob = false
67
hasLoadStarted = false
78

89
componentDidMount() {
10+
const {src, sources, useAutoQuality} = this.props
911
this.hls = new Hls({autoStartLoad: false})
1012
this.hls.attachMedia(this.video)
11-
const {sources} = this.props
12-
const master = getMasterM3U8Blob(sources)
13-
this.src = URL.createObjectURL(master)
13+
14+
const isAutoQualitySourceProvided = Boolean(
15+
sources.find(s => s.quality === 'auto')
16+
)
17+
18+
// 启用自动质量但是又没有提供 auto 规格的 source,那么就尝试本地手动生成
19+
if (useAutoQuality && !isAutoQualitySourceProvided) {
20+
const master = getMasterM3U8Blob(sources)
21+
this.src = URL.createObjectURL(master)
22+
this.manuallyBuildAdaptiveM3U8Blob = true
23+
} else {
24+
this.src = src
25+
}
26+
1427
this.hls.loadSource(this.src)
1528
}
1629

1730
componentDidUpdate(prevProps) {
1831
const {currentQuality, sources, paused} = this.props
32+
33+
// 切换清晰度
1934
if (currentQuality !== prevProps.currentQuality) {
20-
const source = sources.find(source => source.quality === currentQuality)
35+
const source = sources.find(s => s.quality === currentQuality)
2136
if (source) {
22-
const levels = this.hls.levels
23-
const level = levels.findIndex(item => item.url.includes(source.source))
24-
this.hls.nextLevel = level
37+
if (this.manuallyBuildAdaptiveM3U8Blob) {
38+
const levels = this.hls.levels
39+
const level = levels.findIndex(l => l.url.includes(source.source))
40+
this.hls.nextLevel = level
41+
} else {
42+
// TODO: 没有在 hls 的 API 内部找到顺畅切换 source 的方法
43+
// 因此这里比较直接和生硬
44+
const currentTime = this.video.currentTime
45+
this.hls.destroy()
46+
this.hls = new Hls({autoStartLoad: false})
47+
this.hls.attachMedia(this.video)
48+
this.hls.loadSource(source.source)
49+
this.video.currentTime = currentTime
50+
this.hls.startLoad()
51+
if (!paused) {
52+
this.video.play()
53+
}
54+
}
2555
} else {
56+
// 一定意味着选择了手动生成的「auto」
2657
this.hls.nextLevel = -1
2758
}
2859
}
2960

61+
// 切换播放状态
3062
if (!paused && prevProps.paused && !this.hasLoadStarted) {
3163
this.hls.startLoad()
3264
this.hasLoadStarted = true
@@ -35,12 +67,23 @@ export default class Video extends Component {
3567

3668
componentWillUnmount() {
3769
this.hls.destroy()
38-
URL.revokeObjectURL(this.src)
70+
if (this.manuallyBuildAdaptiveM3U8Blob) {
71+
URL.revokeObjectURL(this.src)
72+
}
3973
}
4074

4175
render() {
42-
// eslint-disable-next-line no-unused-vars
43-
const {onRef, currentQuality, src, sources, paused, ...props} = this.props
76+
const {
77+
onRef,
78+
/* eslint-disable no-unused-vars */
79+
currentQuality,
80+
useAutoQuality,
81+
src,
82+
sources,
83+
paused,
84+
/* eslint-enable no-unused-vars */
85+
...props
86+
} = this.props
4487
return (
4588
<video
4689
ref={el => {

packages/griffith-hls/src/utils/__tests__/__snapshots__/createMasterM3U8.spec.js.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ http://zhihu-video-output.oss-cn-hangzhou.aliyuncs.com/test/sd-m3u8/999f95fc-034
88
http://zhihu-video-output.oss-cn-hangzhou.aliyuncs.com/test/hd-m3u8/999f95fc-0346-11e9-b494-0a580a44d740.m3u8"
99
`;
1010

11-
exports[`create master m3u8 palylist wihtout resolution 1`] = `
11+
exports[`create master m3u8 palylist without resolution 1`] = `
1212
"#EXTM3U
1313
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1029120
1414
http://zhihu-video-output.oss-cn-hangzhou.aliyuncs.com/test/sd-m3u8/999f95fc-0346-11e9-b494-0a580a44d740.m3u8

packages/griffith-hls/src/utils/__tests__/createMasterM3U8.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ describe('create master m3u8', () => {
2626
expect(createMasterM3U8(list)).toMatchSnapshot()
2727
})
2828

29-
it('palylist wihtout resolution', () => {
29+
it('palylist without resolution', () => {
3030
const list = [
3131
{
3232
bandwidth: 1029120,

packages/griffith-mp4/src/player.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,19 +96,20 @@ export default class Player extends Component {
9696
}
9797

9898
render() {
99-
/* eslint-disable no-unused-vars */
10099
const {
100+
/* eslint-disable no-unused-vars */
101101
src,
102102
onRef,
103103
currentQuality,
104+
useAutoQuality,
104105
onSeeking,
105106
onPlay,
106107
paused,
107108
onTimeUpdate,
108109
onProgress,
110+
/* eslint-enable no-unused-vars */
109111
...props
110112
} = this.props
111-
/* eslint-enable no-unused-vars */
112113
return (
113114
<video
114115
ref={el => {

packages/griffith/README-zh-Hans.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ render(<Player {...props} />)
2525
| `duration` | `number` | | 初始视频时长。在视频元数据载入后使用实际值 |
2626
| `sources` | `sources` | | 视频播放数据。具体见下, |
2727
| `defaultQuality` | `ld \| sd \| hd \| fhd` | | 视频默认播放清晰度 |
28+
| `useAutoQuality` | `boolean` | `false` | 是否启用自动清晰度功能 |
2829
| `standalone` | `boolean` | `false` | 是否启用 standalone 模式 |
2930
| `onBeforePlay` | `function` | `void` | 视频播放之前回调函数 |
3031
| `shouldObserveResize` | `boolean` | `false` | 是否监听窗口 resize |

packages/griffith/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ render(<Player {...props} />)
2626
| `duration` | `number` | | Initial video duration. Use actual values after video metadata is loaded |
2727
| `sources` | `sources` | | Video playback data |
2828
| `defaultQuality` | `ld \| sd \| hd \| fhd` | | Video default quality |
29+
| `useAutoQuality` | `boolean` | `false` | Enable auto quality |
2930
| `standalone` | `boolean` | `false` | Enable standalone mode |
3031
| `onBeforePlay` | `function` | `void` | Callback function before video playback |
3132
| `shouldObserveResize` | `boolean` | `false` | Listen to the window resize |

packages/griffith/src/components/Controller/items/__tests__/__snapshots__/CombinedTimeItem.spec.js.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
exports[`CombinedTimeItem get CombinedTimeItem component 1`] = `
44
<div
5-
className="time_uz62bc-o_O-fullScreenedTime_1xxtrer"
5+
className="time_kviad4-o_O-fullScreenedTime_1xxtrer"
66
>
77
<div
88
className=""

packages/griffith/src/components/Player/Player.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ class Player extends Component {
375375
standalone,
376376
onEvent,
377377
useMSE,
378+
useAutoQuality,
378379
disablePictureInPicture,
379380
} = this.props
380381

@@ -444,6 +445,7 @@ class Player extends Component {
444445
onProgress={this.handleVideoProgress}
445446
onEvent={onEvent}
446447
useMSE={useMSE}
448+
useAutoQuality={useAutoQuality}
447449
/>
448450
</div>
449451
<div

packages/griffith/src/components/PlayerContainer/PlayerContainer.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const PlayerContainer = ({
2828
autoplay,
2929
disablePictureInPicture,
3030
defaultQuality,
31+
useAutoQuality = false,
3132
}) => (
3233
<ObjectFitProvider initialObjectFit={initialObjectFit}>
3334
<PositionProvider shouldObserveResize={shouldObserveResize}>
@@ -39,12 +40,14 @@ const PlayerContainer = ({
3940
sources={sources}
4041
id={id}
4142
defaultQuality={defaultQuality}
43+
useAutoQuality={useAutoQuality}
4244
>
4345
<LocaleContext.Provider value={locale}>
4446
<VideoSourceContext.Consumer>
4547
{({currentSrc}) => (
4648
<Player
4749
useMSE={useMSE}
50+
useAutoQuality={useAutoQuality}
4851
autoplay={autoplay}
4952
disablePictureInPicture={disablePictureInPicture}
5053
standalone={standalone}
@@ -72,17 +75,17 @@ PlayerContainer.propTypes = {
7275
standalone: PropTypes.bool,
7376
id: PropTypes.string.isRequired,
7477
title: PropTypes.string,
75-
cover: PropTypes.string.isRequired,
76-
duration: PropTypes.number.isRequired,
78+
cover: PropTypes.string,
79+
duration: PropTypes.number,
7780
sources: PropTypes.objectOf(
7881
PropTypes.shape({
79-
bitrate: PropTypes.number.isRequired,
80-
duration: PropTypes.number.isRequired,
82+
bitrate: PropTypes.number,
83+
duration: PropTypes.number,
8184
format: PropTypes.string.isRequired,
82-
height: PropTypes.number.isRequired,
85+
height: PropTypes.number,
8386
play_url: PropTypes.string.isRequired,
84-
size: PropTypes.number.isRequired,
85-
width: PropTypes.number.isRequired,
87+
size: PropTypes.number,
88+
width: PropTypes.number,
8689
})
8790
).isRequired,
8891
error: PropTypes.shape({

0 commit comments

Comments
 (0)