liyubing

feat: 1)处理直播预告视频播放;2)处理视频资源播放完毕状态,支持重新播放

@@ -11,7 +11,7 @@ import { UserInfoDTO } from './UserInfoDTO' @@ -11,7 +11,7 @@ import { UserInfoDTO } from './UserInfoDTO'
11 * 接口定义: 11 * 接口定义:
12 * http://192.168.1.3:3300/project/3802/interface/api/200915 12 * http://192.168.1.3:3300/project/3802/interface/api/200915
13 */ 13 */
14 -export interface ContentDetailDTO { 14 +export class ContentDetailDTO {
15 newsId: number; 15 newsId: number;
16 newsTitle: string; 16 newsTitle: string;
17 newsShortTitle: string; 17 newsShortTitle: string;
@@ -72,4 +72,8 @@ export interface ContentDetailDTO { @@ -72,4 +72,8 @@ export interface ContentDetailDTO {
72 isNewspaper: boolean; 72 isNewspaper: boolean;
73 oldNewsId: string; 73 oldNewsId: string;
74 serials: any; 74 serials: any;
  75 +
  76 +
  77 + // 本地字段
  78 + showTime:boolean = false;
75 } 79 }
@@ -112,6 +112,23 @@ export struct DetailPlayLiveCommon { @@ -112,6 +112,23 @@ export struct DetailPlayLiveCommon {
112 }) 112 })
113 } 113 }
114 114
  115 + // /**
  116 + // *
  117 + // * @returns true : 沉浸式;false : 非沉浸式
  118 + // */
  119 + // isImmersionLive(): boolean {
  120 + //
  121 + // let flag = false
  122 + //
  123 + // if (this.liveState === 'wait' || this.liveLandscape === 'news') {
  124 + // flag = false
  125 + // } else if (this.liveLandscape === 'general') {
  126 + // flag = true
  127 + // }
  128 + //
  129 + // return flag
  130 + // }
  131 +
115 onPageShow() { 132 onPageShow() {
116 this.pageShow = Math.random() 133 this.pageShow = Math.random()
117 Logger.info(TAG, 'onPageShow') 134 Logger.info(TAG, 'onPageShow')
@@ -119,8 +119,8 @@ export struct DetailPlayLivePage { @@ -119,8 +119,8 @@ export struct DetailPlayLivePage {
119 119
120 getLiveDetails() { 120 getLiveDetails() {
121 const data = this.contentDetailData 121 const data = this.contentDetailData
122 - console.error("XXXXZZZZ", 'contentDetailData ----liveState==>' + data.liveInfo?.liveState)  
123 - console.error("XXXXZZZZ", 'contentDetailData ----liveStyle==>' + data.liveInfo?.liveStyle) 122 + // console.error("XXXXZZZZ", 'contentDetailData ----liveState==>' + data.liveInfo?.liveState)
  123 + // console.error("XXXXZZZZ", 'contentDetailData ----liveStyle==>' + data.liveInfo?.liveStyle)
124 if (data.liveInfo?.liveState == 'wait') { 124 if (data.liveInfo?.liveState == 'wait') {
125 //直播样式 0-正常模式 , 1-隐藏直播间,2-隐藏大家聊 【人民号发布是竖屏的,为空】 125 //直播样式 0-正常模式 , 1-隐藏直播间,2-隐藏大家聊 【人民号发布是竖屏的,为空】
126 if (data.liveInfo?.liveStyle == 1) { 126 if (data.liveInfo?.liveStyle == 1) {
1 -import { window } from '@kit.ArkUI' 1 +import { window } from '@kit.ArkUI';
2 import lottie from '@ohos/lottie'; 2 import lottie from '@ohos/lottie';
3 3
4 -import { NumberFormatterUtils, StringUtils, WindowModel } from 'wdKit/Index'  
5 -import { DateFormatUtil, WDAliPlayerController, WDPlayerController } from 'wdPlayer/Index'  
6 -import { ContentDetailDTO, LiveDetailsBean, LiveRoomDataBean } from 'wdBean/Index'  
7 -import { DisplayDirection } from 'wdConstant/Index'  
8 -import { LiveFollowComponent, LottieView } from 'wdComponent/Index' 4 +import { NumberFormatterUtils, StringUtils, WindowModel } from 'wdKit/Index';
  5 +import { DateFormatUtil, PlayerConstants, WDAliPlayerController } from 'wdPlayer/Index';
  6 +import { ContentDetailDTO, LiveRoomDataBean } from 'wdBean/Index';
  7 +import { DisplayDirection } from 'wdConstant/Index';
  8 +import { LiveFollowComponent, LottieView } from 'wdComponent/Index';
9 9
10 @Component 10 @Component
11 export struct PlayUIComponent { 11 export struct PlayUIComponent {
12 playerController?: WDAliPlayerController; 12 playerController?: WDAliPlayerController;
13 //菜单键是否可见 13 //菜单键是否可见
14 @State @Watch('onChangeMenuVisible') isMenuVisible: boolean = true 14 @State @Watch('onChangeMenuVisible') isMenuVisible: boolean = true
15 -// @Consume liveDetailsBean: LiveDetailsBean  
16 @Consume contentDetailData: ContentDetailDTO 15 @Consume contentDetailData: ContentDetailDTO
17 @Consume liveRoomDataBean: LiveRoomDataBean 16 @Consume liveRoomDataBean: LiveRoomDataBean
18 @State currentTime: string = '' 17 @State currentTime: string = ''
@@ -21,8 +20,11 @@ export struct PlayUIComponent { @@ -21,8 +20,11 @@ export struct PlayUIComponent {
21 //是否处于播放状态中 20 //是否处于播放状态中
22 @State isPlayStatus: boolean = true 21 @State isPlayStatus: boolean = true
23 @Consume displayDirection: DisplayDirection 22 @Consume displayDirection: DisplayDirection
24 -  
25 @Prop isShowBottom: boolean 23 @Prop isShowBottom: boolean
  24 + // 播放地址 (视频或者 直播地址)
  25 + @Prop liveUrl: string
  26 + // 当前播放资源的状态
  27 + @Consume playSourceState: number
26 28
27 onChangeMenuVisible() { 29 onChangeMenuVisible() {
28 if (!this.contentDetailData || !this.contentDetailData.liveInfo || 30 if (!this.contentDetailData || !this.contentDetailData.liveInfo ||
@@ -41,6 +43,21 @@ export struct PlayUIComponent { @@ -41,6 +43,21 @@ export struct PlayUIComponent {
41 43
42 aboutToAppear(): void { 44 aboutToAppear(): void {
43 this.onChangeMenuVisible() 45 this.onChangeMenuVisible()
  46 +
  47 + this.initPlayerSet()
  48 + }
  49 +
  50 + aboutToDisappear(): void {
  51 + if (this.contentDetailData.liveInfo?.liveState == 'running') {
  52 + lottie.destroy('live_status_wait')
  53 + }
  54 + }
  55 +
  56 + /*
  57 + 初始话播放器设置
  58 + */
  59 + initPlayerSet(){
  60 +
44 //播放进度监听 61 //播放进度监听
45 if (this.playerController) { 62 if (this.playerController) {
46 this.playerController.onTimeUpdate = (position: number, duration: number) => { 63 this.playerController.onTimeUpdate = (position: number, duration: number) => {
@@ -49,12 +66,7 @@ export struct PlayUIComponent { @@ -49,12 +66,7 @@ export struct PlayUIComponent {
49 this.progressVal = Math.floor(position * 100 / duration); 66 this.progressVal = Math.floor(position * 100 / duration);
50 } 67 }
51 } 68 }
52 - }  
53 69
54 - aboutToDisappear(): void {  
55 - if (this.contentDetailData.liveInfo?.liveState == 'running') {  
56 - lottie.destroy('live_status_wait')  
57 - }  
58 } 70 }
59 71
60 build() { 72 build() {
@@ -62,7 +74,7 @@ export struct PlayUIComponent { @@ -62,7 +74,7 @@ export struct PlayUIComponent {
62 if (this.contentDetailData && this.contentDetailData.liveInfo) { 74 if (this.contentDetailData && this.contentDetailData.liveInfo) {
63 this.getTopUIComponent() 75 this.getTopUIComponent()
64 this.getMiddleUIComponent() 76 this.getMiddleUIComponent()
65 - if(this.isShowBottom){ 77 + if (this.isShowBottom) {
66 this.getBottomUIComponent() 78 this.getBottomUIComponent()
67 } 79 }
68 80
@@ -251,16 +263,13 @@ export struct PlayUIComponent { @@ -251,16 +263,13 @@ export struct PlayUIComponent {
251 @Builder 263 @Builder
252 getBottomUIComponent() { 264 getBottomUIComponent() {
253 Row() { 265 Row() {
254 - if (this.contentDetailData?.liveInfo?.liveState == 'wait') {  
255 - Blank()  
256 - } else if (this.contentDetailData?.liveInfo?.liveState == 'running') { 266 +
  267 + // 视频资源
  268 + if (!StringUtils.isEmpty(this.liveUrl)) {
  269 + // 暂定和播放按钮
257 this.playOrPauseBtn() 270 this.playOrPauseBtn()
258 - Blank()  
259 - } else if (this.contentDetailData?.liveInfo?.liveState == 'end') {  
260 - if (StringUtils.isEmpty(this.contentDetailData?.liveInfo?.vlive[0]?.replayUri)) {  
261 - Blank()  
262 - } else {  
263 - this.playOrPauseBtn() 271 + // 开始时间
  272 + if (this.contentDetailData?.liveInfo?.liveState != 'running' || this.contentDetailData.showTime) {
264 Text(this.currentTime) 273 Text(this.currentTime)
265 .fontColor(Color.White) 274 .fontColor(Color.White)
266 .fontWeight(600) 275 .fontWeight(600)
@@ -268,7 +277,12 @@ export struct PlayUIComponent { @@ -268,7 +277,12 @@ export struct PlayUIComponent {
268 .margin({ 277 .margin({
269 left: 16 278 left: 16
270 }) 279 })
271 - this.playProgressView() 280 + }
  281 +
  282 + // 进度条
  283 + this.playProgressView()
  284 + // 总的播放时间
  285 + if (this.contentDetailData?.liveInfo?.liveState != 'running' || this.contentDetailData.showTime) {
272 Text(this.totalTime) 286 Text(this.totalTime)
273 .fontColor(Color.White) 287 .fontColor(Color.White)
274 .fontWeight(600) 288 .fontWeight(600)
@@ -277,11 +291,13 @@ export struct PlayUIComponent { @@ -277,11 +291,13 @@ export struct PlayUIComponent {
277 right: 16 291 right: 16
278 }) 292 })
279 } 293 }
  294 +
  295 + } else {
  296 + Blank()
280 } 297 }
281 - if (this.contentDetailData?.liveInfo?.liveState == 'running'  
282 - || (this.contentDetailData?.liveInfo?.liveState == 'end' &&  
283 - StringUtils.isNotEmpty(this.contentDetailData?.liveInfo?.vlive[0]?.replayUri))  
284 - ) { 298 +
  299 + // 全屏按钮
  300 + if (!StringUtils.isEmpty(this.liveUrl)) {
285 Image($r('app.media.icon_live_player_full_screen')) 301 Image($r('app.media.icon_live_player_full_screen'))
286 .width(24) 302 .width(24)
287 .height(24) 303 .height(24)
@@ -298,6 +314,7 @@ export struct PlayUIComponent { @@ -298,6 +314,7 @@ export struct PlayUIComponent {
298 }) 314 })
299 .visibility(this.displayDirection == DisplayDirection.VERTICAL ? Visibility.Visible : Visibility.None) 315 .visibility(this.displayDirection == DisplayDirection.VERTICAL ? Visibility.Visible : Visibility.None)
300 } 316 }
  317 +
301 } 318 }
302 .alignItems(VerticalAlign.Center) 319 .alignItems(VerticalAlign.Center)
303 .linearGradient({ angle: 0, colors: [['#99000000', 0], ['#00000000', 1]] }) 320 .linearGradient({ angle: 0, colors: [['#99000000', 0], ['#00000000', 1]] })
@@ -313,19 +330,34 @@ export struct PlayUIComponent { @@ -313,19 +330,34 @@ export struct PlayUIComponent {
313 330
314 @Builder 331 @Builder
315 playOrPauseBtn() { 332 playOrPauseBtn() {
316 - //暂停、播放  
317 - Image(this.isPlayStatus ? $r('app.media.icon_live_player_pause') : $r('app.media.player_play_ic'))  
318 - .width(24)  
319 - .height(24)  
320 - .onClick(() => {  
321 - if (this.isPlayStatus) {  
322 - this.isPlayStatus = false  
323 - this.playerController?.pause()  
324 - } else { 333 +
  334 + if (this.playSourceState === PlayerConstants.STATUS_COMPLETION) {
  335 + //资源播放完成
  336 + Image($r('app.media.player_play_ic'))
  337 + .width(24)
  338 + .height(24)
  339 + .onClick(() => {
325 this.isPlayStatus = true 340 this.isPlayStatus = true
  341 + this.initPlayerSet()
  342 + this.playerController?.firstPlay(this.liveUrl)
326 this.playerController?.play() 343 this.playerController?.play()
327 - }  
328 - }) 344 + })
  345 + } else {
  346 + //暂停、播放
  347 + Image(this.isPlayStatus ? $r('app.media.icon_live_player_pause') : $r('app.media.player_play_ic'))
  348 + .width(24)
  349 + .height(24)
  350 + .onClick(() => {
  351 + if (this.isPlayStatus) {
  352 + this.isPlayStatus = false
  353 + this.playerController?.pause()
  354 + } else {
  355 + this.isPlayStatus = true
  356 + this.playerController?.play()
  357 + }
  358 + })
  359 + }
  360 +
329 } 361 }
330 362
331 @Builder 363 @Builder
@@ -13,7 +13,9 @@ const TAG: string = 'TopPlayComponent' @@ -13,7 +13,9 @@ const TAG: string = 'TopPlayComponent'
13 export struct TopPlayComponent { 13 export struct TopPlayComponent {
14 @Consume @Watch('updateData') contentDetailData: ContentDetailDTO 14 @Consume @Watch('updateData') contentDetailData: ContentDetailDTO
15 playerController?: WDAliPlayerController 15 playerController?: WDAliPlayerController
16 - @State imgUrl: string = '' 16 + // 预告片图片/视频url
  17 + @State previewUrl: string = ''
  18 + @State isVideoSource: boolean = false
17 //未开始 19 //未开始
18 @State isWait: boolean = false 20 @State isWait: boolean = false
19 //已结束直播 21 //已结束直播
@@ -24,14 +26,15 @@ export struct TopPlayComponent { @@ -24,14 +26,15 @@ export struct TopPlayComponent {
24 @State isLoading: boolean = false 26 @State isLoading: boolean = false
25 // 获取播放资源能播放了 27 // 获取播放资源能播放了
26 @State isCanPlay: boolean = false 28 @State isCanPlay: boolean = false
27 - 29 + // 当前播放资源的状态
  30 + @Provide playSourceState: number = 0
28 private playUrl: string = "" 31 private playUrl: string = ""
29 private xComponentIsLoaded: boolean = false 32 private xComponentIsLoaded: boolean = false
30 33
31 aboutToAppear(): void { 34 aboutToAppear(): void {
32 if (this.playerController) { 35 if (this.playerController) {
33 this.playerController.onCanplay = () => { 36 this.playerController.onCanplay = () => {
34 - 37 + Logger.debug(TAG, 'onCanplay==>')
35 this.isCanPlay = true 38 this.isCanPlay = true
36 this.isLoading = true 39 this.isLoading = true
37 this.playerController?.play() 40 this.playerController?.play()
@@ -40,35 +43,56 @@ export struct TopPlayComponent { @@ -40,35 +43,56 @@ export struct TopPlayComponent {
40 43
41 this.playerController.onStatusChange = (status: number) => { 44 this.playerController.onStatusChange = (status: number) => {
42 45
  46 + this.playSourceState = status
  47 + Logger.debug(TAG, 'status==>' + status)
43 if (status === PlayerConstants.STATUS_ERROR) { 48 if (status === PlayerConstants.STATUS_ERROR) {
44 this.isError = true 49 this.isError = true
45 this.isLoading = true 50 this.isLoading = true
46 -  
47 this.isCanPlay = false 51 this.isCanPlay = false
  52 + } else if (status === PlayerConstants.STATUS_COMPLETION) {
  53 + // 播放完成
  54 +
  55 +
48 } else { 56 } else {
49 this.isError = false 57 this.isError = false
50 } 58 }
51 59
52 -  
53 } 60 }
54 } 61 }
55 this.updateData() 62 this.updateData()
56 } 63 }
57 64
58 updateData() { 65 updateData() {
  66 +
  67 + // 检测等待中的直播预告是否视频资源
  68 + if (this.contentDetailData.liveInfo && this.contentDetailData.liveInfo.previewType === 1
  69 + && this.contentDetailData.liveInfo.previewUrl &&
  70 + this.contentDetailData.liveInfo.previewUrl.length > 0) {
  71 + // 预告资源是视频
  72 + this.isVideoSource = true
  73 + this.contentDetailData.showTime = true
  74 + }
59 //直播新闻-直播状态 wait待开播running直播中end已结束cancel已取消paused暂停 75 //直播新闻-直播状态 wait待开播running直播中end已结束cancel已取消paused暂停
60 if (this.contentDetailData.liveInfo && this.contentDetailData.liveInfo.previewUrl && 76 if (this.contentDetailData.liveInfo && this.contentDetailData.liveInfo.previewUrl &&
61 this.contentDetailData.liveInfo.previewUrl.length > 0) { 77 this.contentDetailData.liveInfo.previewUrl.length > 0) {
62 - this.imgUrl = this.contentDetailData.liveInfo.previewUrl  
63 - Logger.debug(TAG, 'ok+' + `${this.imgUrl}`) 78 + this.previewUrl = this.contentDetailData.liveInfo.previewUrl
  79 +
64 } else if (this.contentDetailData.fullColumnImgUrls && this.contentDetailData.fullColumnImgUrls.length > 0) { 80 } else if (this.contentDetailData.fullColumnImgUrls && this.contentDetailData.fullColumnImgUrls.length > 0) {
65 - this.imgUrl = this.contentDetailData.fullColumnImgUrls[0].url  
66 - Logger.debug(TAG, 'ok-' + `${this.imgUrl}`) 81 + this.previewUrl = this.contentDetailData.fullColumnImgUrls[0].url
67 } 82 }
68 - this.isWait = this.contentDetailData?.liveInfo?.liveState == 'wait'  
69 - if(this.isWait ){  
70 - this.isLoading = true 83 +
  84 + Logger.debug(TAG, 'ok+' + `${this.previewUrl}`)
  85 +
  86 + if (this.isVideoSource) {
  87 + this.isWait = false
  88 + this.isLoading = false
  89 + } else {
  90 + this.isWait = this.contentDetailData?.liveInfo?.liveState == 'wait'
  91 + if (this.isWait) {
  92 + this.isLoading = true
  93 + }
71 } 94 }
  95 +
72 this.isEnd = this.contentDetailData?.liveInfo?.liveState === 'end' && 96 this.isEnd = this.contentDetailData?.liveInfo?.liveState === 'end' &&
73 StringUtils.isEmpty(this.contentDetailData?.liveInfo?.vlive[0]?.replayUri) 97 StringUtils.isEmpty(this.contentDetailData?.liveInfo?.vlive[0]?.replayUri)
74 if (!this.isWait && this.contentDetailData.liveInfo && this.contentDetailData.liveInfo.vlive.length > 0) { 98 if (!this.isWait && this.contentDetailData.liveInfo && this.contentDetailData.liveInfo.vlive.length > 0) {
@@ -78,12 +102,18 @@ export struct TopPlayComponent { @@ -78,12 +102,18 @@ export struct TopPlayComponent {
78 } else if (this.contentDetailData.liveInfo.liveState == 'end') { 102 } else if (this.contentDetailData.liveInfo.liveState == 'end') {
79 playUrl = this.contentDetailData.liveInfo.vlive[0].replayUri 103 playUrl = this.contentDetailData.liveInfo.vlive[0].replayUri
80 } 104 }
81 - // this.playerController?.firstPlay('https://rmrbcmsonline.peopleapp.com/upload/rmh/video/mp4/202404/1713752415708fb81d0b8f137b.mp4');  
82 - if (StringUtils.isNotEmpty(playUrl)) {  
83 - Logger.debug(TAG, `${playUrl}`)  
84 - this.playUrl = playUrl 105 +
  106 + if (this.isVideoSource) {
  107 + this.playUrl = this.previewUrl
85 this.tryToPlay() 108 this.tryToPlay()
  109 + } else {
  110 + if (StringUtils.isNotEmpty(playUrl)) {
  111 + Logger.debug(TAG, `${playUrl}`)
  112 + this.playUrl = playUrl
  113 + this.tryToPlay()
  114 + }
86 } 115 }
  116 +
87 } 117 }
88 } 118 }
89 119
@@ -115,18 +145,22 @@ export struct TopPlayComponent { @@ -115,18 +145,22 @@ export struct TopPlayComponent {
115 .width('100%') 145 .width('100%')
116 .visibility(this.isWait ? Visibility.None : Visibility.Visible) 146 .visibility(this.isWait ? Visibility.None : Visibility.Visible)
117 147
118 - // 直播房间图  
119 - Image(this.imgUrl)  
120 - .objectFit(ImageFit.Cover)  
121 - .visibility(this.isWait || this.isEnd ? Visibility.Visible : Visibility.None)  
122 - .contrast(this.isEnd ? 0.2 : 1)  
123 - .width('100%') 148 + if (this.isVideoSource) {
  149 +
  150 + } else {
  151 + // 直播房间图
  152 + Image(this.previewUrl)
  153 + .objectFit(ImageFit.Cover)
  154 + .visibility(this.isWait || this.isEnd ? Visibility.Visible : Visibility.None)
  155 + .contrast(this.isEnd ? 0.2 : 1)
  156 + .width('100%')
  157 + }
124 158
125 // loading 159 // loading
126 PictureLoading().visibility(this.isLoading ? Visibility.None : Visibility.Visible) 160 PictureLoading().visibility(this.isLoading ? Visibility.None : Visibility.Visible)
127 161
128 // 视频播放器上的控制面板和信息 162 // 视频播放器上的控制面板和信息
129 - PlayUIComponent({ playerController: this.playerController, isShowBottom: this.isCanPlay }) 163 + PlayUIComponent({ playerController: this.playerController, isShowBottom: this.isCanPlay, liveUrl: this.playUrl })
130 164
131 // 直播结束 165 // 直播结束
132 Text('直播已结束') 166 Text('直播已结束')
@@ -50,8 +50,6 @@ export struct WDPlayerRenderLiveView { @@ -50,8 +50,6 @@ export struct WDPlayerRenderLiveView {
50 50
51 aboutToAppear() { 51 aboutToAppear() {
52 MGPlayRenderViewIns.add(); 52 MGPlayRenderViewIns.add();
53 -  
54 - console.log('playerController', this.playerController)  
55 insIndex++; 53 insIndex++;
56 if (!this.playerController) { 54 if (!this.playerController) {
57 return 55 return
@@ -59,7 +57,6 @@ export struct WDPlayerRenderLiveView { @@ -59,7 +57,6 @@ export struct WDPlayerRenderLiveView {
59 57
60 this.playerController.onVideoSizeChange = (width: number, height: number) => { 58 this.playerController.onVideoSizeChange = (width: number, height: number) => {
61 // console.log(`WDPlayerRenderView onVideoSizeChange width:${width} videoTop:${height}`) 59 // console.log(`WDPlayerRenderView onVideoSizeChange width:${width} videoTop:${height}`)
62 - Logger.info(TAG, ` onVideoSizeChange width:${width} videoTop:${height}`)  
63 this.videoWidth = width; 60 this.videoWidth = width;
64 this.videoHeight = height; 61 this.videoHeight = height;
65 this.updateLayout() 62 this.updateLayout()
@@ -83,8 +80,6 @@ export struct WDPlayerRenderLiveView { @@ -83,8 +80,6 @@ export struct WDPlayerRenderLiveView {
83 .onLoad(async (event) => { 80 .onLoad(async (event) => {
84 Logger.info(TAG, 'onLoad') 81 Logger.info(TAG, 'onLoad')
85 let surfaceId = this.xComponentController.getXComponentSurfaceId() 82 let surfaceId = this.xComponentController.getXComponentSurfaceId()
86 - console.log('surfaceId===', surfaceId)  
87 - console.log('insId===', this.insId)  
88 this.xComponentController.setXComponentSurfaceSize({ 83 this.xComponentController.setXComponentSurfaceSize({
89 surfaceWidth: 1920, 84 surfaceWidth: 1920,
90 surfaceHeight: 720 85 surfaceHeight: 720