Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(h5): 支持播放 hls 视频 #11542

Merged
merged 4 commits into from
Apr 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/taro-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"@tarojs/taro": "3.4.7",
"better-scroll": "^1.14.1",
"classnames": "^2.2.5",
"hls.js": "^1.1.5",
"intersection-observer": "^0.7.0",
"omit.js": "^1.0.0",
"resolve-pathname": "^3.0.0",
Expand Down
12 changes: 7 additions & 5 deletions packages/taro-components/src/components/video/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export const formatTime = (time: number): string => {
if (time === null) return ''
const sec = Math.round(time / 1000 % 60)
const min = Math.floor((time - sec) / 1000 / 60)
export const formatTime = (time?: number): string => {
if (!time) return ''
const sec = Math.round(time % 60)
const min = Math.round((time - sec) / 60)
return `${min < 10 ? `0${min}` : min}:${sec < 10 ? `0${sec}` : sec}`
}

Expand Down Expand Up @@ -72,7 +72,7 @@ export const screenFn = (function () {
]
let i = 0
const l = fnMap.length
const ret = {}
const ret: Record<string, any> = {}
// This for loop essentially checks the current document object for the property/methods above.
for (; i < l; i++) {
val = fnMap[i]
Expand All @@ -96,3 +96,5 @@ export const screenFn = (function () {
// and the fn variable is set to this returned value.
return ret
})()

export const isHls = url => /\.(m3u8)($|\?)/i.test(url)
12 changes: 6 additions & 6 deletions packages/taro-components/src/components/video/video-control.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export class VideoControl implements ComponentInterface {
private isDraggingProgressBall = false
private hideControlsTimer: NodeJS.Timeout
private percentage = 0
private progressDimentions = {
private progressDimensions = {
left: 0,
width: 0
}
Expand Down Expand Up @@ -89,10 +89,10 @@ export class VideoControl implements ComponentInterface {
}

calcPercentage = (pageX: number): number => {
let pos = pageX - this.progressDimentions.left
let pos = pageX - this.progressDimensions.left
pos = Math.max(pos, 0)
pos = Math.min(pos, this.progressDimentions.width)
return pos / this.progressDimentions.width
pos = Math.min(pos, this.progressDimensions.width)
return pos / this.progressDimensions.width
}

onDragProgressBallStart = () => {
Expand Down Expand Up @@ -148,8 +148,8 @@ export class VideoControl implements ComponentInterface {
ref={ref => {
if (!ref) return
const rect = ref.getBoundingClientRect()
this.progressDimentions.left = rect.left
this.progressDimentions.width = rect.width
this.progressDimensions.left = rect.left
this.progressDimensions.width = rect.width
}}>
<div class='taro-video-progress-buffered' style={{ width: '100%' }} />
<div
Expand Down
55 changes: 46 additions & 9 deletions packages/taro-components/src/components/video/video.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { Component, h, ComponentInterface, Prop, State, Event, EventEmitter, Host, Watch, Listen, Element, Method } from '@stencil/core'
import classNames from 'classnames'
import Hls from 'hls.js'

import { throttle } from '../../utils'
import {
formatTime,
calcDist,
normalizeNumber,
screenFn
screenFn,
isHls
} from './utils'

@Component({
Expand All @@ -31,6 +33,7 @@ export class Video implements ComponentInterface {
private lastPercentage
private nextPercentage
private gestureType = 'none'
private hls: Hls

@Element() el: HTMLTaroVideoCoreElement

Expand Down Expand Up @@ -186,6 +189,7 @@ export class Video implements ComponentInterface {
}

componentDidLoad () {
this.init()
if (this.initialTime) {
this.videoRef.currentTime = this.initialTime
}
Expand All @@ -211,7 +215,12 @@ export class Video implements ComponentInterface {
this._enableDanmu = newVal
}

analyseGesture = (e: TouchEvent) => {
@Watch('src')
watchSrc () {
this.init()
}

analyzeGesture = (e: TouchEvent) => {
const obj: {
type: string
dataX?: number
Expand Down Expand Up @@ -263,7 +272,7 @@ export class Video implements ComponentInterface {
if (this.lastTouchScreenX === undefined || this.lastTouchScreenY === undefined) return
if (await this.controlsRef.getIsDraggingProgressBall()) return

const gestureObj = this.analyseGesture(e)
const gestureObj = this.analyzeGesture(e)
if (gestureObj.type === 'adjustVolume') {
this.toastVolumeRef.style.visibility = 'visible'
const nextVolume = Math.max(Math.min(this.lastVolume - gestureObj.dataY!, 1), 0)
Expand Down Expand Up @@ -305,6 +314,37 @@ export class Video implements ComponentInterface {
this.lastTouchScreenY = undefined
}

loadNativePlayer = () => {
if (this.videoRef) {
this.videoRef.src = this.src
this.videoRef.load()
}
}

init = () => {
const { src, videoRef } = this

if (isHls(src)) {
if (Hls.isSupported()) {
if (this.hls) {
this.hls.destroy()
}
this.hls = new Hls()
this.hls.loadSource(src)
this.hls.attachMedia(videoRef)
this.hls.on(Hls.Events.MANIFEST_PARSED, () => {
this.autoplay && this.play()
})
} else if (videoRef.canPlayType('application/vnd.apple.mpegurl')) {
this.loadNativePlayer()
} else {
console.error('该浏览器不支持 HLS 播放')
}
} else {
this.loadNativePlayer()
}
}

handlePlay = () => {
this.isPlaying = true
this.isFirst = false
Expand Down Expand Up @@ -478,7 +518,6 @@ export class Video implements ComponentInterface {

render () {
const {
src,
controls,
autoplay,
loop,
Expand All @@ -488,8 +527,6 @@ export class Video implements ComponentInterface {
isFirst,
isMute,
isFullScreen,
duration,
_duration,
showCenterPlayBtn,
isPlaying,
_enableDanmu,
Expand All @@ -498,7 +535,8 @@ export class Video implements ComponentInterface {
showFullscreenBtn,
nativeProps
} = this
const durationTime = formatTime(duration || _duration || null)
const duration = this.duration || this._duration
const durationTime = formatTime(duration)

return (
<Host
Expand All @@ -518,7 +556,6 @@ export class Video implements ComponentInterface {
this.videoRef = dom as HTMLVideoElement
}
}}
src={src}
autoplay={autoplay}
loop={loop}
muted={muted}
Expand Down Expand Up @@ -562,7 +599,7 @@ export class Video implements ComponentInterface {
}}
controls={controls}
currentTime={this.currentTime}
duration={this.duration || this._duration || undefined}
duration={duration}
isPlaying={this.isPlaying}
pauseFunc={this._pause}
playFunc={this._play}
Expand Down
2 changes: 1 addition & 1 deletion packages/taro-components/types/Video.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ declare namespace VideoProps {
* id='video'
* src='https://wxsnsdy.tc.qq.com/105/20210/snsdyvideodownload?filekey=30280201010421301f0201690402534804102ca905ce620b1241b726bc41dcff44e00204012882540400&bizid=1023&hy=SH&fileparam=302c020101042530230204136ffd93020457e3c4ff02024ef202031e8d7f02030f42400204045a320a0201000400'
* poster='https://misc.aotu.io/booxood/mobile-video/cover_900x500.jpg'
* initialTime='0'
* initialTime={0}
* controls={true}
* autoplay={false}
* loop={false}
Expand Down