• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15import mediaLibrary from '@ohos.multimedia.mediaLibrary'
16import prompt from '@ohos.prompt'
17import router from '@ohos.router'
18import Logger from '../model/Logger'
19import MediaUtils from '../model/MediaUtils'
20import NextVideo from '../common/NextVideo'
21import PlayButton from '../common/PlayButton'
22import PlayTitle from '../common/PlayTitle'
23import PreVideo from '../common/PreVideo'
24import VideoPlayerUtils from '../model/VideoPlayerUtils'
25import { getTimeString } from '../model/TimeUtils'
26
27const TAG: string = 'Player'
28
29@Entry
30@Component
31struct Player {
32  private currentIndex: number = -1
33  private fileAsset: mediaLibrary.FileAsset = undefined
34  private fileId: number = router.getParams()['fileId']
35  private fd: number = undefined
36  private intervalId: number = undefined
37  private mediaList: Array<mediaLibrary.FileAsset> = []
38  private videoPlayer: VideoPlayerUtils = new VideoPlayerUtils()
39  private mXComponentController: XComponentController = new XComponentController()
40  private surfaceId: number = 0
41  private mediaUtil: MediaUtils = new MediaUtils(getContext(this) as any)
42  @State currentTime: number = 0
43  @State displayName: string = router.getParams()['displayName']
44  @State isShowMenu: boolean = false
45  @State @Watch('playStateChange') isPlaying: boolean = false
46  @State ratio: number = 1.0
47
48  build() {
49    Stack({ alignContent: Alignment.Center }) {
50      if (this.isShowMenu) {
51        Column() {
52          PlayTitle({ title: this.displayName, handleBack: this.handleBack })
53          Row() {
54            PreVideo({ handleClick: this.handlePrevClick })
55            PlayButton({ isPlaying: $isPlaying })
56            NextVideo({ handleClick: this.handleNextClick })
57          }
58          .margin({ top: '40%' })
59
60          Blank()
61          Row() {
62            Text(getTimeString(this.currentTime))
63              .fontSize(25)
64              .fontColor(Color.White)
65            Blank()
66            Text(this.fileAsset ? getTimeString(this.fileAsset.duration) : '00:00')
67              .fontSize(25)
68              .fontColor(Color.White)
69          }
70          .width('95%')
71
72          Slider({ value: this.fileAsset ? this.currentTime / this.fileAsset.duration * 100 : 0 })
73            .width('92%')
74            .selectedColor(Color.White)
75            .onChange((value: number) => {
76              Logger.info(TAG, 'seek time change')
77              this.currentTime = this.fileAsset.duration * value / 100
78              this.videoPlayer.seek(this.currentTime)
79            })
80        }
81        .height('100%')
82        .zIndex(2)
83      }
84      Row() {
85        XComponent({
86          id: 'componentId',
87          type: 'surface',
88          controller: this.mXComponentController
89        })
90          .onLoad(() => {
91            Logger.info(TAG, 'onLoad is called')
92            this.playVideo()
93          })
94          .width('100%')
95          .aspectRatio(this.ratio)
96      }
97      .height('100%')
98      .width('100%')
99      .justifyContent(FlexAlign.Center)
100    }
101    .width('100%')
102    .height('100%')
103    .backgroundColor(Color.Black)
104    .onClick(() => {
105      this.isShowMenu = !this.isShowMenu
106    })
107  }
108
109  aboutToAppear() {
110    this.surfaceId = this.mXComponentController.getXComponentSurfaceId()
111    Logger.info(TAG, `aboutToAppear,surfaceId=${this.surfaceId}`)
112    Logger.info(TAG, `fileId=${this.fileId},displayName=${this.displayName}`)
113    this.videoPlayer.setFinishCallBack(() => {
114      this.isPlaying = false
115      this.currentTime = 0
116    })
117    this.intervalId = setInterval(() => {
118      if (this.isPlaying) {
119        this.currentTime = this.videoPlayer.getCurrentTime()
120      }
121    }, 1000)
122  }
123
124  async getMediaList() {
125    Logger.info(TAG, `getMediaList,id=${this.fileId}`)
126    this.mediaList = await this.mediaUtil.getFileAssetsFromType(mediaLibrary.MediaType.VIDEO)
127    this.mediaList.forEach((file, index) => {
128      Logger.info(TAG, `file.id=${file.id}`)
129      if (file.id === this.fileId) {
130        this.fileAsset = file
131        this.currentIndex = index
132      }
133    })
134  }
135
136  playStateChange() {
137    if (this.isPlaying) {
138      this.videoPlayer.play()
139    } else {
140      this.videoPlayer.pause()
141    }
142  }
143
144  handleBack = () => {
145    router.back()
146    this.clearVideoPlayer()
147  }
148  handlePrevClick = () => {
149    if (this.currentIndex > 0) {
150      this.currentIndex -= 1
151      this.resetVideo()
152    } else {
153      prompt.showToast({ message: '当前视频是第一个', duration: 1000 })
154    }
155  }
156  handleNextClick = () => {
157    if (this.currentIndex < this.mediaList.length - 1) {
158      this.currentIndex += 1
159      this.resetVideo()
160    } else {
161      prompt.showToast({ message: '当前视频是最后一个', duration: 1000 })
162    }
163  }
164
165  async resetVideo() {
166    await this.fileAsset.close(this.fd)
167    this.fileAsset = this.mediaList[this.currentIndex]
168    this.displayName = this.fileAsset.displayName
169    let fdPath = await this.prepareVideo()
170    await this.videoPlayer.reset(fdPath)
171    this.isPlaying = true
172  }
173
174  async prepareVideo() {
175    this.ratio = this.fileAsset.width / this.fileAsset.height
176    this.mXComponentController.setXComponentSurfaceSize({
177      surfaceWidth: this.fileAsset.width,
178      surfaceHeight: this.fileAsset.height
179    })
180    this.surfaceId = this.mXComponentController.getXComponentSurfaceId()
181    this.fd = await this.fileAsset.open('Rw')
182    Logger.info(TAG, `fd://' ${this.fd} `)
183    return 'fd://' + this.fd
184  }
185
186  async playVideo() {
187    Logger.info(TAG, 'playVideo')
188    try{
189      await this.getMediaList()
190      let fdPath = await this.prepareVideo()
191      await this.videoPlayer.initVideoPlayer(fdPath, this.surfaceId)
192      this.isPlaying = true
193    }catch(error) {
194      Logger.info(TAG, `playVideo error ${JSON.stringify(error)}`)
195    }
196  }
197
198  onPageHide() {
199    this.clearVideoPlayer()
200    router.replace({
201      url: 'pages/Index'
202    })
203  }
204
205  clearVideoPlayer() {
206    clearInterval(this.intervalId)
207    if (this.videoPlayer) {
208      this.videoPlayer.stop()
209      this.videoPlayer.release()
210    }
211    if (this.fileAsset) {
212      this.fileAsset.close(this.fd)
213    }
214  }
215}