| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- <template>
- <div
- class="o-video"
- :class="{ offline: !online, mask: !isPlaying, controls, floating, fullscreen: isFullscreen }"
- @mousemove="onMouseMove"
- >
- <template v-if="online">
- <video
- ref="video"
- class="o-video__player o-simple-video"
- :poster="poster"
- autoplay
- muted
- @play="onVideoPlay"
- @pause="onVideoPause"
- @waiting="onVideoWaiting"
- @playing="onVideoPlaying"
- @error="onVideoError"
- @ended="onVideoEnded"
- />
- <div class="o-video__mask">
- <div
- class="l-flex--row center o-video__btn u-pointer"
- @click.stop="onPlayOrPause"
- >
- <i :class="statusIconClass" />
- </div>
- </div>
- </template>
- <div
- v-if="controls"
- class="l-flex--row c-footer"
- >
- <div class="l-flex__fill c-sibling-item u-ellipsis">{{ device.name }}</div>
- <slot
- name="controls"
- :can-play="canPlay"
- :on-full-screen="onFullScreen"
- >
- <template v-if="canPlay">
- <i
- v-if="loadingQuality"
- class="c-sibling-item el-icon-loading"
- />
- <div
- v-else
- class="l-flex__none c-sibling-item o-quality-menu u-pointer"
- @click.stop="toggleQualityMenu"
- >
- <div
- v-if="showQualityMenu"
- class="o-quality-menu__list u-font-size--sm u-text--center"
- >
- <div
- v-for="item in qualities"
- :key="item.value"
- class="o-quality-menu__item has-active"
- :class="{ 'u-color--success': quality.value === item.value }"
- @click="changeQuality(item)"
- >
- {{ item.label }}
- </div>
- </div>
- <span class="has-active">{{ quality.label }}</span>
- </div>
- <i
- class="c-sibling-item el-icon-full-screen has-active"
- @click="onFullScreen"
- />
- </template>
- </slot>
- </div>
- </div>
- </template>
- <script>
- import {
- authCode,
- getRecordConfig,
- addRecordConfig,
- updateRecordConfig
- } from '@/api/device'
- import { GATEWAY } from '@/constant'
- import playerMixin from '../player'
- const Quality = {
- fff: {
- videoWidth: 640,
- videoHeight: 360,
- videoBitRate: 36 * 1024,
- frameRate: 1
- },
- ff: {
- videoWidth: 1280,
- videoHeight: 720,
- videoBitRate: 100 * 1024,
- frameRate: 10
- },
- f: {
- videoWidth: 1920,
- videoHeight: 1080,
- videoBitRate: 1024 * 1024,
- frameRate: 20
- }
- }
- export default {
- name: 'DevicePlayer',
- mixins: [playerMixin],
- props: {
- device: {
- type: Object,
- required: true
- }
- },
- data () {
- return {
- qualities: [
- { value: 'fff', label: '标清' },
- { value: 'ff', label: '高清' },
- { value: 'f', label: '超清' }
- ],
- loadingQuality: false,
- showQualityMenu: false,
- quality: null,
- recordConfig: null,
- floating: true
- }
- },
- computed: {
- online () {
- return this.device.onlineStatus === 1
- },
- canPlay () {
- return !this.loading && !this.needReset
- }
- },
- watch: {
- online (val) {
- if (val) {
- this.$nextTick(this.createPlayer)
- } else {
- this.hideQualityMenu()
- this.onVideoReset()
- this.destroyPlayer()
- }
- },
- isFullscreen () {
- this.onMouseMove()
- }
- },
- created () {
- this.$delayMoveTimer = -1
- this.$timer = -1
- if (this.online) {
- this.createPlayer()
- }
- },
- beforeDestroy () {
- clearTimeout(this.$delayMoveTimer)
- this.hideQualityMenu()
- },
- methods: {
- onMouseMove () {
- clearTimeout(this.$delayMoveTimer)
- this.floating = false
- if (this.isFullscreen) {
- this.$delayMoveTimer = setTimeout(() => {
- this.floating = true
- }, 3000)
- }
- },
- onVideoReset () {
- this.recordConfig = null
- this.$playerInfo = null
- },
- getRecordConfig () {
- this.loadingQuality = true
- getRecordConfig(this.device.id, { custom: true }).finally(() => {
- this.loadingQuality = false
- }).then(
- ({ data }) => {
- if (data) {
- const { frameRate } = data
- const key = Object.keys(Quality).find(key => Quality[key].frameRate === frameRate) || 'fff'
- this.quality = this.qualities.find(({ value }) => value === key) || this.qualities[0]
- this.recordConfig = data
- this.createPlayer()
- } else {
- this.setRecordConfig(this.qualities[0])
- }
- },
- () => {
- this.onVideoDestroyByError()
- }
- )
- },
- setRecordConfig (quality) {
- this.loadingQuality = true
- ;(this.recordConfig ? updateRecordConfig : addRecordConfig)({
- deviceId: this.device.id,
- ...Quality[quality.value]
- }, { custom: true }).then(
- ({ data }) => {
- this.quality = quality
- this.recordConfig = data
- this.createPlayer()
- },
- () => {
- this.onVideoDestroyByError()
- }
- ).finally(() => {
- this.loadingQuality = false
- })
- },
- hideQualityMenu () {
- if (this.showQualityMenu) {
- this.showQualityMenu = false
- document.removeEventListener('click', this.hideQualityMenu)
- }
- },
- toggleQualityMenu () {
- if (this.showQualityMenu) {
- this.hideQualityMenu()
- } else {
- document.addEventListener('click', this.hideQualityMenu)
- this.showQualityMenu = true
- }
- },
- changeQuality (quality) {
- if (this.quality.value !== quality.value) {
- this.$playerInfo = null
- this.setRecordConfig(quality)
- } else if (this.needReset) {
- this.createPlayer()
- }
- },
- getAuthCode () {
- this.$playerInfo = null
- authCode(this.recordConfig.stream).then(
- ({ data }) => {
- if (this.$timer !== null) {
- this.$playerInfo = data
- this.createPlayer()
- }
- },
- () => {
- this.onVideoDestroyByError()
- }
- )
- },
- createPlayer () {
- if (this.$timer === null) {
- return
- }
- this.loading = true
- clearTimeout(this.$timer)
- if (!this.recordConfig) {
- this.getRecordConfig()
- return
- }
- if (!this.$playerInfo) {
- this.getAuthCode()
- return
- }
- const { vhost = '__defaultVhost__', token, timestamp, expire } = this.$playerInfo
- if (Number(timestamp) + Number(expire) * 1000 <= Date.now()) {
- this.getAuthCode()
- return
- }
- this.destroyPlayer()
- this.playUrl(`${GATEWAY}/live/${this.recordConfig.stream}.flv?vhost=${vhost}&authorization=${token}×tamp=${timestamp}&expire=${expire}`)
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .o-quality-menu {
- display: inline-block;
- position: relative;
- padding: 0 $padding--xs;
- z-index: 1;
- &__list {
- position: absolute;
- right: 0;
- bottom: 100%;
- width: 100%;
- margin-bottom: $spacing--2xs;
- border-radius: $radius;
- background-color: rgba(#000, 0.85);
- z-index: -1;
- }
- &__item {
- padding: $padding--2xs 0;
- }
- }
- </style>
|