|
@@ -1,2445 +0,0 @@
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-import router from '@ohos.router';
|
|
|
|
|
-import { BusinessError, Callback } from '@ohos.base';
|
|
|
|
|
-import { IjkMediaPlayer, InterruptEvent, InterruptHintType } from '@ohos/ijkplayer';
|
|
|
|
|
-import { OnPreparedListener } from '@ohos/ijkplayer';
|
|
|
|
|
-import { OnVideoSizeChangedListener } from '@ohos/ijkplayer';
|
|
|
|
|
-import { OnCompletionListener } from '@ohos/ijkplayer';
|
|
|
|
|
-import { OnBufferingUpdateListener } from '@ohos/ijkplayer';
|
|
|
|
|
-import { OnErrorListener, OnTimedTextListener } from '@ohos/ijkplayer';
|
|
|
|
|
-import { OnInfoListener } from '@ohos/ijkplayer';
|
|
|
|
|
-import { OnSeekCompleteListener } from '@ohos/ijkplayer';
|
|
|
|
|
-import { LogUtils } from '@ohos/ijkplayer';
|
|
|
|
|
-import prompt from '@ohos.promptAction';
|
|
|
|
|
-import { PlayStatus } from '../common/PlayStatus';
|
|
|
|
|
-import { RouterParam } from './RouterParam';
|
|
|
|
|
-import { VideoItem } from '../viewmodel/VideoItem';
|
|
|
|
|
-import { CommonConstants } from '../common/constants/CommonConstants';
|
|
|
|
|
-import { PlayConstants } from '../common/constants/PlayConstants';
|
|
|
|
|
-import { ArrayUtil, DialogUtil, DisplayUtil, GlobalContext,
|
|
|
|
|
- LogUtil,
|
|
|
|
|
- PreferencesUtil,
|
|
|
|
|
- StrUtil,
|
|
|
|
|
- ToastUtil } from '@pura/harmony-utils';
|
|
|
|
|
-import { BubbleBean } from '../viewmodel/BubbleBean';
|
|
|
|
|
-import { PopupPosition, XPopup } from '@chinalike/popup';
|
|
|
|
|
-import { display, promptAction, window } from '@kit.ArkUI';
|
|
|
|
|
-import Logger from '../common/util/Logger';
|
|
|
|
|
-import { PiPWindow } from '@kit.ArkUI';
|
|
|
|
|
-import { AnimationHelper, DialogHelper } from '@pura/harmony-dialog';
|
|
|
|
|
-import fs from '@ohos.file.fs';
|
|
|
|
|
-import { AvSessionController } from '../controller/AvSessionController';
|
|
|
|
|
-import { AVCastPicker, AVCastPickerState, avSession } from '@kit.AVSessionKit';
|
|
|
|
|
-import { CommonConstants2 } from '../common/util/CommonConstants2';
|
|
|
|
|
-import { secondToTime } from '../common/util/CommUtils';
|
|
|
|
|
-import { hilog } from '@kit.PerformanceAnalysisKit';
|
|
|
|
|
-import { SettingPage } from './SettingPage';
|
|
|
|
|
-import { fileIo, picker } from '@kit.CoreFileKit';
|
|
|
|
|
-import { Utility } from '../common/util/Utility';
|
|
|
|
|
-import { LazyDataSource } from '../common/util/LazyDataSource';
|
|
|
|
|
-
|
|
|
|
|
-const TAG = 'onecold videoPlayer';
|
|
|
|
|
-interface GeneratedObjectLiteralInterface_1 {
|
|
|
|
|
- assetId: string;
|
|
|
|
|
- title: string;
|
|
|
|
|
- artist: string;
|
|
|
|
|
-
|
|
|
|
|
- // 网络资源投播,设置mediaUri; 本地资源投播,将本地文件打开后,相关的文件描述符设置到fdSrc
|
|
|
|
|
- mediaUri: string;
|
|
|
|
|
-
|
|
|
|
|
- // 该字段大写,音频'AUDIO',视频'VIDEO'
|
|
|
|
|
- mediaType: string;
|
|
|
|
|
- mediaSize: number;
|
|
|
|
|
-
|
|
|
|
|
- //startPosition为投播当前进度,设置该字段可将本机播放进度同步到远端
|
|
|
|
|
- startPosition: number;
|
|
|
|
|
-
|
|
|
|
|
- // 投播资源播放时长,设置该字段可将本机播放时长同步到远端显示
|
|
|
|
|
- duration: number;
|
|
|
|
|
- albumCoverUri: string;
|
|
|
|
|
- albumTitle: string;
|
|
|
|
|
- appName: string;
|
|
|
|
|
-
|
|
|
|
|
- // DRM资源,需要配置支持的DRM类型, 以chinaDRM为例。
|
|
|
|
|
- drmScheme: string;
|
|
|
|
|
-}
|
|
|
|
|
-@Entry
|
|
|
|
|
-@Component
|
|
|
|
|
-struct IjkVideoPlayerPage {
|
|
|
|
|
- @State progressValue: number = 0;
|
|
|
|
|
- @State currentTime: string = "00:00";
|
|
|
|
|
- @State totalTime: string = "00:00";
|
|
|
|
|
- @State loadingVisible: Visibility = Visibility.None;
|
|
|
|
|
- @State replayVisible: Visibility = Visibility.None;
|
|
|
|
|
- @State slideEnable: boolean = false;
|
|
|
|
|
- @State aspRatio: number = 0.5;
|
|
|
|
|
- @State mContext: object | undefined = undefined;
|
|
|
|
|
- @State mFirst: boolean = true;
|
|
|
|
|
- @State mDestroyPage: boolean = false;
|
|
|
|
|
- @State playSpeed: string = '1f';
|
|
|
|
|
-
|
|
|
|
|
- @State oldSeconds: number = 0;
|
|
|
|
|
- @State isSeekTo: boolean = false;
|
|
|
|
|
- @State isCurrentTime: boolean = false;
|
|
|
|
|
- @State videoWidth: string = '100%';
|
|
|
|
|
- @State videoHeight: string = '100%';
|
|
|
|
|
- @State initAspectRatio: number = 1;
|
|
|
|
|
- @State videoAspectRatio: number = this.initAspectRatio;
|
|
|
|
|
- private videoUrl: string = '';
|
|
|
|
|
- private last: number = 0;
|
|
|
|
|
- @State videoParentAspectRatio: number = this.initAspectRatio;
|
|
|
|
|
- private mIjkMediaPlayer = IjkMediaPlayer.getInstance();
|
|
|
|
|
- @State CONTROL_PlayStatus:number = PlayStatus.INIT;
|
|
|
|
|
- @State PROGRESS_MAX_VALUE: number = 100;
|
|
|
|
|
- @State updateProgressTimer: number = 0;
|
|
|
|
|
- @State curIndex: number = 0;
|
|
|
|
|
- @State isHide: boolean = false;//是否因此播放器的按钮,默认是进入横屏模式隐藏,点击视频的时候显示
|
|
|
|
|
- @State name: string = '';
|
|
|
|
|
- // @State loop: boolean = false;
|
|
|
|
|
- @State playType: number = 0; //0:连续播放 1:单片重复播放 2:正常播放
|
|
|
|
|
- @State isLandscape: boolean = false;
|
|
|
|
|
- @Provide globalVideoList: Array<VideoItem> = []
|
|
|
|
|
- @State multiple: string = '1.0X';
|
|
|
|
|
-
|
|
|
|
|
- xcomponentController: XComponentController = new XComponentController()
|
|
|
|
|
- private panOptionBright: PanGestureOptions = new PanGestureOptions({ direction:PanDirection.Up| PanDirection.Down});
|
|
|
|
|
- private panOptionVolume: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.Vertical| PanDirection.Up| PanDirection.Down });
|
|
|
|
|
- private panOptionSeekTo: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.Horizontal });
|
|
|
|
|
- //手势的音量控制和亮度控制
|
|
|
|
|
- private positionX: number = PlayConstants.POSITION_X;
|
|
|
|
|
- private positionY: number = PlayConstants.POSITION_Y;
|
|
|
|
|
- private windowClass: window.Window = globalThis.windowClass
|
|
|
|
|
- @State volume: number = 0.5;
|
|
|
|
|
- @State volumeShow: boolean = PlayConstants.VOLUME_SHOW;
|
|
|
|
|
- @State bright: number = PlayConstants.BRIGHT;
|
|
|
|
|
- @State brightShow: boolean = PlayConstants.BRIGHT_SHOW;
|
|
|
|
|
- @State seekToShow: boolean = PlayConstants.BRIGHT_SHOW;
|
|
|
|
|
- // @State screenHeight:number = 0
|
|
|
|
|
- @State screenWidth: number =0
|
|
|
|
|
- @State screenHeight: number =0
|
|
|
|
|
- @State statusBarHeight: number =0
|
|
|
|
|
-
|
|
|
|
|
- @State isYesFull: boolean = false
|
|
|
|
|
- private seekValue:number = 0
|
|
|
|
|
- @State isVideoLock: boolean = false; // Whether the video playback is locked
|
|
|
|
|
- eventHub = getContext().eventHub;
|
|
|
|
|
-
|
|
|
|
|
- //投播组件
|
|
|
|
|
- private avSessionController: AvSessionController = AvSessionController.getInstance(true);
|
|
|
|
|
- private castController: avSession.AVCastController | undefined = undefined;
|
|
|
|
|
- @State isCastPlaying: boolean = false;
|
|
|
|
|
- @State currentTime2: number = 0;
|
|
|
|
|
- @State currentStringTime: string = '00:00';
|
|
|
|
|
- @State duration: number = 0;
|
|
|
|
|
- @State isReady: boolean = false;
|
|
|
|
|
- @State durationTime: number = 0;
|
|
|
|
|
- @State durationStringTime: string = '00:00';
|
|
|
|
|
- @State isPlaying: boolean = false;
|
|
|
|
|
- private castSeek: boolean = false;
|
|
|
|
|
- private castItem: avSession.AVQueueItem | undefined = undefined;
|
|
|
|
|
- @State isBgPlayOpen:boolean = true //是否启用后台播放
|
|
|
|
|
- @State subtitleText: string = '';//字幕
|
|
|
|
|
-
|
|
|
|
|
- @State isShowSheetView: boolean = false;
|
|
|
|
|
-
|
|
|
|
|
- aboutToAppear() {
|
|
|
|
|
- LogUtils.getInstance().LOGI("aboutToAppear");
|
|
|
|
|
-
|
|
|
|
|
- let params = router.getParams() as Record<string, Object>;
|
|
|
|
|
- this.name = params.name as string;
|
|
|
|
|
- this.curIndex = params.index as number;
|
|
|
|
|
- this.playType = params.playType as number;
|
|
|
|
|
- this.globalVideoList = params.globalVideoList as VideoItem[];
|
|
|
|
|
-
|
|
|
|
|
- this.videoUrl = (router.getParams() as RouterParam).videoUrl;
|
|
|
|
|
- this.isBgPlayOpen = PreferencesUtil.getBooleanSync(SettingPage.IS_BGPLAY_OPEN,true)
|
|
|
|
|
- let event: Callback<InterruptEvent> = (event) => {
|
|
|
|
|
- LogUtils.getInstance().LOGI(`event: ${JSON.stringify(event)}`);
|
|
|
|
|
- if (event.hintType === InterruptHintType.INTERRUPT_HINT_PAUSE) {
|
|
|
|
|
- this.pause();
|
|
|
|
|
- } else if (event.hintType === InterruptHintType.INTERRUPT_HINT_RESUME) {
|
|
|
|
|
- this.startPlayOrResumePlay();
|
|
|
|
|
- } else if (event.hintType === InterruptHintType.INTERRUPT_HINT_STOP) {
|
|
|
|
|
- this.stop();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- this.mIjkMediaPlayer.on('audioInterrupt', event);
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- window.getLastWindow(getContext(this))
|
|
|
|
|
- .then((windowClass: window.Window) => {
|
|
|
|
|
- let area = windowClass.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);
|
|
|
|
|
- this.screenWidth = px2fp(windowClass.getWindowProperties().windowRect.width);
|
|
|
|
|
- this.screenHeight = px2fp(windowClass.getWindowProperties().windowRect.height);
|
|
|
|
|
- this.statusBarHeight = px2fp(area.topRect.height);
|
|
|
|
|
- })
|
|
|
|
|
- .catch((error: Error) => {
|
|
|
|
|
- Logger.error('[ScreenUtil] Failed to obtain the window size. Cause: ' + JSON.stringify(error));
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- this.windowClass.on('windowSizeChange', (size) => {
|
|
|
|
|
- let viewWidth = px2vp(size.width);
|
|
|
|
|
- let viewHeight = px2vp(size.height);
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- if (viewWidth > viewHeight) {
|
|
|
|
|
- Logger.info('横屏 windowSizeChange isLandscape = ' + this.isLandscape)
|
|
|
|
|
- this.isLandscape = true;
|
|
|
|
|
- this.windowClass.setSpecificSystemBarEnabled('navigationIndicator', false); // hide bottom navigation bar
|
|
|
|
|
- } else {
|
|
|
|
|
- Logger.info('竖屏 windowSizeChange isLandscape = ' + this.isLandscape)
|
|
|
|
|
- this.windowClass.setSpecificSystemBarEnabled('navigationIndicator', true); // show bottom navigation bar
|
|
|
|
|
- this.isLandscape = false;
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- this.getVideoSize()
|
|
|
|
|
-
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- this.eventHub.on('onStateChange', (fg: boolean) => {
|
|
|
|
|
- if (fg && this.curState === 'STARTED') {
|
|
|
|
|
- this.stopPip();
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- //8s后自动隐藏
|
|
|
|
|
- this.setHideAfter()
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- aboutToDisappear() {
|
|
|
|
|
- LogUtils.getInstance().LOGI("aboutToDisappear");
|
|
|
|
|
- this.mDestroyPage = true;
|
|
|
|
|
- this.mIjkMediaPlayer.setScreenOnWhilePlaying(false);
|
|
|
|
|
- if (this.CONTROL_PlayStatus != PlayStatus.INIT) {
|
|
|
|
|
- this.pause();
|
|
|
|
|
- }
|
|
|
|
|
- // this.mIjkMediaPlayer.off('audioInterrupt');
|
|
|
|
|
- this.stopPip();
|
|
|
|
|
- this.destroyPipController()
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- onPageShow() {
|
|
|
|
|
-
|
|
|
|
|
- this.getVideoSize()
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- //修复播放器全屏横屏的时候 按home键处理页面为竖屏
|
|
|
|
|
- onBackPress(): boolean | void {
|
|
|
|
|
- Logger.info('playPage player onBackPress: ' );
|
|
|
|
|
- if(this.isLandscape){
|
|
|
|
|
- this.isLandscape = false
|
|
|
|
|
- this.setOrientation(window.Orientation.USER_ROTATION_PORTRAIT);
|
|
|
|
|
- }
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- onPageHide() {
|
|
|
|
|
- // this.pause();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- getStatus() {
|
|
|
|
|
- return this.CONTROL_PlayStatus;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- isExpandedOrHalfFolded(): boolean {
|
|
|
|
|
- return display.getFoldStatus() === display.FoldStatus.FOLD_STATUS_EXPANDED ||
|
|
|
|
|
- display.getFoldStatus() == display.FoldStatus.FOLD_STATUS_HALF_FOLDED
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- setOrientation(orientation: number) {
|
|
|
|
|
- this.windowClass.setPreferredOrientation(orientation).then(() => {
|
|
|
|
|
- Logger.info('setWindowOrientation: ' + orientation + ' Succeeded.');
|
|
|
|
|
- }).catch((err: BusinessError) => {
|
|
|
|
|
- Logger.info('setWindowOrientation: ' + orientation + ' Failed. Cause: ' + JSON.stringify(err));
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- showPlayList(){
|
|
|
|
|
- promptAction.openCustomDialog({
|
|
|
|
|
- transition: AnimationHelper.transitionInRight(888),
|
|
|
|
|
- builder: () => {
|
|
|
|
|
- this.customDialogComponent()
|
|
|
|
|
- },
|
|
|
|
|
- alignment: this.isLandscape?DialogAlignment.TopEnd:DialogAlignment.BottomEnd,
|
|
|
|
|
- onWillDismiss: (dismissDialogAction: DismissDialogAction) => {
|
|
|
|
|
- console.info("reason" + JSON.stringify(dismissDialogAction.reason))
|
|
|
|
|
- console.log("dialog onWillDismiss")
|
|
|
|
|
- if (dismissDialogAction.reason == DismissReason.PRESS_BACK) {
|
|
|
|
|
- dismissDialogAction.dismiss()
|
|
|
|
|
- }
|
|
|
|
|
- if (dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {
|
|
|
|
|
- dismissDialogAction.dismiss()
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }).then((dialogId: number) => {
|
|
|
|
|
- this.customDialogComponentId = dialogId
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- private customDialogComponentId: number = 0
|
|
|
|
|
- @Builder
|
|
|
|
|
- customDialogComponent() {
|
|
|
|
|
- Column() {
|
|
|
|
|
- Row(){
|
|
|
|
|
- Blank()
|
|
|
|
|
- Text('播放列表')
|
|
|
|
|
- .fontSize(15)
|
|
|
|
|
- .fontColor($r('app.color.pri_bg'))
|
|
|
|
|
- .margin({top:16})
|
|
|
|
|
- Blank()
|
|
|
|
|
- Image($r('app.media.close'))
|
|
|
|
|
- .fillColor(Color.White)
|
|
|
|
|
- .margin({top:18,right:18})
|
|
|
|
|
- .width(20)
|
|
|
|
|
- .onClick(()=>{
|
|
|
|
|
- promptAction.closeCustomDialog(this.customDialogComponentId)
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- .width('100%') // 使Row占据整个宽度
|
|
|
|
|
- .justifyContent(FlexAlign.SpaceBetween); // 在Row中创建空间
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- List() {
|
|
|
|
|
- ForEach(this.globalVideoList, (item: VideoItem, index: number) => {
|
|
|
|
|
- ListItem() {
|
|
|
|
|
- Row(){
|
|
|
|
|
- Text(index+1+'')
|
|
|
|
|
- .margin({left:20,top:5,bottom:5,right:1})
|
|
|
|
|
- .fontWeight(900)
|
|
|
|
|
- .fontColor(Color.Gray)
|
|
|
|
|
- if(this.curIndex === index){
|
|
|
|
|
- Text('正在播放:')
|
|
|
|
|
- .margin({left:1,top:5,bottom:5})
|
|
|
|
|
- .fontWeight(500)
|
|
|
|
|
- .fontColor( $r('app.color.title_bar_bg'))
|
|
|
|
|
- .padding({ top:10,bottom:10,left:10})
|
|
|
|
|
- Text(item.name)
|
|
|
|
|
- .margin({top:5,bottom:5,right:10})
|
|
|
|
|
- .maxLines(1)
|
|
|
|
|
- .fontColor( $r('app.color.title_bar_bg'))
|
|
|
|
|
- .padding({ top:10,bottom:10 ,left:1,right:10})
|
|
|
|
|
- .textAlign(TextAlign.Start)
|
|
|
|
|
- .textOverflow({overflow: TextOverflow.MARQUEE}) //超长滚动
|
|
|
|
|
- }else{
|
|
|
|
|
- Text(item.name)
|
|
|
|
|
- .margin({left:1,top:5,bottom:5,right:10})
|
|
|
|
|
- .maxLines(1)
|
|
|
|
|
- .fontColor(Color.Black)
|
|
|
|
|
- .padding({ top:10,bottom:10 ,left:10,right:10})
|
|
|
|
|
- .textAlign(TextAlign.Start)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- .width('93%')
|
|
|
|
|
-
|
|
|
|
|
- }.onClick(() => {
|
|
|
|
|
- promptAction.closeCustomDialog(this.customDialogComponentId)
|
|
|
|
|
- this.playIndex(index)
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- })
|
|
|
|
|
- }
|
|
|
|
|
- // .margin({left:15,right:15,top:20,bottom:10})
|
|
|
|
|
- // .borderRadius(30)
|
|
|
|
|
- // .backgroundColor($r('app.color.white'))
|
|
|
|
|
- .width('100%')
|
|
|
|
|
- .height('100%')
|
|
|
|
|
- .divider({
|
|
|
|
|
- strokeWidth:1,
|
|
|
|
|
- color:"#D3D3D3"
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- }.height(this.isLandscape?'100%':'60%')
|
|
|
|
|
- .backgroundColor($r('app.color.index_background'))
|
|
|
|
|
- .justifyContent(FlexAlign.SpaceBetween)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- //倍速播放
|
|
|
|
|
- showMultipleDialog(xid:string){
|
|
|
|
|
-
|
|
|
|
|
- let dataBean = new BubbleBean()
|
|
|
|
|
- dataBean.data = ["0.75X","1.0X", "1.25X","1.5X","1.75X", "2.0X", "3.0X"]
|
|
|
|
|
- dataBean.onItemClick = (i) => {
|
|
|
|
|
- // ToastUtil.showToast('您点击了第'+index+'个')
|
|
|
|
|
- this.multiple = dataBean.data[i]
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- switch (i){
|
|
|
|
|
-
|
|
|
|
|
- case 0://0.75X
|
|
|
|
|
- this.playSpeed = '0.75f'
|
|
|
|
|
- this.mIjkMediaPlayer.setSpeed("0.75f");
|
|
|
|
|
- break
|
|
|
|
|
- case 1://1.0X
|
|
|
|
|
- this.playSpeed = '1f'
|
|
|
|
|
- this.mIjkMediaPlayer.setSpeed("1f");
|
|
|
|
|
- break
|
|
|
|
|
- case 2://1.25X
|
|
|
|
|
- this.playSpeed = '1.25f'
|
|
|
|
|
- this.mIjkMediaPlayer.setSpeed("1.25f");
|
|
|
|
|
- break
|
|
|
|
|
- case 3://1.5X
|
|
|
|
|
- this.playSpeed = '1.5f'
|
|
|
|
|
- this.mIjkMediaPlayer.setSpeed("1.5f");
|
|
|
|
|
- break
|
|
|
|
|
- case 4://1.75X
|
|
|
|
|
- this.playSpeed = '1.75f'
|
|
|
|
|
- this.mIjkMediaPlayer.setSpeed("1.75f");
|
|
|
|
|
- break
|
|
|
|
|
- case 5://2.0X
|
|
|
|
|
- this.playSpeed = '2f'
|
|
|
|
|
- this.mIjkMediaPlayer.setSpeed("2f");
|
|
|
|
|
- break
|
|
|
|
|
-
|
|
|
|
|
- case 6://3.0X
|
|
|
|
|
- this.playSpeed = '3f'
|
|
|
|
|
- this.mIjkMediaPlayer.setSpeed("3f");
|
|
|
|
|
- break
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- xpup.dismiss()
|
|
|
|
|
- }
|
|
|
|
|
- let popupPosition:PopupPosition = PopupPosition.BOTTOM
|
|
|
|
|
- if(xid.includes('down')){
|
|
|
|
|
- popupPosition = PopupPosition.TOP
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- let xpup = XPopup.Builder()
|
|
|
|
|
- .setPopupPosition(popupPosition)
|
|
|
|
|
- .atView(xid)
|
|
|
|
|
- .asBubble(wrapBuilder(customPopupBuilder), dataBean)
|
|
|
|
|
- .show()
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- //画中画功能
|
|
|
|
|
- pipController?: PiPWindow.PiPController;
|
|
|
|
|
- navigationId: string = '';
|
|
|
|
|
- @State curState: string = '';
|
|
|
|
|
- @State curError: ResourceStr = '';
|
|
|
|
|
- @State buttonAction: string = '';
|
|
|
|
|
- //开启画中画功能
|
|
|
|
|
- async startPip() {
|
|
|
|
|
- if (!this.pipController) {
|
|
|
|
|
- await this.createPipController();
|
|
|
|
|
- }
|
|
|
|
|
- if (!this.pipController) {
|
|
|
|
|
- Logger.info(`[${TAG}] pipController create error`);
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- await this.pipController.startPiP();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- async stopPip() {
|
|
|
|
|
- if (!this.pipController) {
|
|
|
|
|
- Logger.info(`[${TAG}] pipController is not exist`);
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- await this.pipController.stopPiP();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- async createPipController() {
|
|
|
|
|
- this.pipController = await PiPWindow.create({
|
|
|
|
|
- context: getContext(this),
|
|
|
|
|
- componentController: this.xcomponentController,
|
|
|
|
|
- navigationId: this.navigationId,
|
|
|
|
|
- templateType: PiPWindow.PiPTemplateType.VIDEO_PLAY
|
|
|
|
|
- });
|
|
|
|
|
- this.pipController.on('stateChange', (state: PiPWindow.PiPState, reason: string) => {
|
|
|
|
|
- this.onStateChange(state, reason);
|
|
|
|
|
- });
|
|
|
|
|
- this.pipController.on('controlPanelActionEvent', (event: PiPWindow.PiPActionEventType, status?: number) => {
|
|
|
|
|
- this.onActionEvent(event, status);
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- destroyPipController() {
|
|
|
|
|
- if (!this.pipController) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- this.pipController.off('stateChange');
|
|
|
|
|
- this.pipController.off('controlPanelActionEvent');
|
|
|
|
|
- this.pipController = undefined;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- onStateChange(state: PiPWindow.PiPState, reason: string) {
|
|
|
|
|
- switch (state) {
|
|
|
|
|
- case PiPWindow.PiPState.ABOUT_TO_START:
|
|
|
|
|
- this.curState = 'ABOUT_TO_START';
|
|
|
|
|
- this.curError = $r('app.string.current_error_hint');
|
|
|
|
|
- break;
|
|
|
|
|
- case PiPWindow.PiPState.STARTED:
|
|
|
|
|
- this.curState = 'STARTED';
|
|
|
|
|
- this.curError = $r('app.string.current_error_hint');
|
|
|
|
|
- break;
|
|
|
|
|
- case PiPWindow.PiPState.ABOUT_TO_STOP:
|
|
|
|
|
- this.curState = 'ABOUT_TO_STOP';
|
|
|
|
|
- this.curError = $r('app.string.current_error_hint');
|
|
|
|
|
- break;
|
|
|
|
|
- case PiPWindow.PiPState.STOPPED:
|
|
|
|
|
- // this.updatePlayStatus(true);
|
|
|
|
|
- this.startPlayOrResumePlay()
|
|
|
|
|
- this.curState = 'STOPPED';
|
|
|
|
|
- this.curError = $r('app.string.current_error_hint');
|
|
|
|
|
- break;
|
|
|
|
|
- case PiPWindow.PiPState.ABOUT_TO_RESTORE:
|
|
|
|
|
- this.curState = 'ABOUT_TO_RESTORE';
|
|
|
|
|
- this.curError = $r('app.string.current_error_hint');
|
|
|
|
|
- break;
|
|
|
|
|
- case PiPWindow.PiPState.ERROR:
|
|
|
|
|
- this.curState = 'ERROR';
|
|
|
|
|
- this.curError = reason;
|
|
|
|
|
- break;
|
|
|
|
|
- default:
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- Logger.info(`[${TAG}] onStateChange: ${this.curState}, reason: ${reason}`);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // updatePlayStatus(status:boolean) {
|
|
|
|
|
- // if(status){
|
|
|
|
|
- // this.CONTROL_PlayStatus = PlayStatus.PLAY;
|
|
|
|
|
- // }else{
|
|
|
|
|
- // this.CONTROL_PlayStatus = PlayStatus.PAUSE;
|
|
|
|
|
- // }
|
|
|
|
|
- //
|
|
|
|
|
- // }
|
|
|
|
|
-
|
|
|
|
|
- onActionEvent(event: PiPWindow.PiPActionEventType, status: number | undefined) {
|
|
|
|
|
- switch (event) {
|
|
|
|
|
- case 'playbackStateChanged':
|
|
|
|
|
- if (status === 0) {
|
|
|
|
|
- // this.updatePlayStatus(false);
|
|
|
|
|
- this.pause();
|
|
|
|
|
- } else {
|
|
|
|
|
- // this.updatePlayStatus(true);
|
|
|
|
|
- this.startPlayOrResumePlay();
|
|
|
|
|
- }
|
|
|
|
|
- break;
|
|
|
|
|
- default:
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- this.buttonAction = event + `-status:${status}`;
|
|
|
|
|
- Logger.info(`[${TAG}] onActionEvent: ${this.buttonAction} status:${status}}`);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- build() {
|
|
|
|
|
- Stack() {
|
|
|
|
|
-
|
|
|
|
|
- Stack({ alignContent: Alignment.Center }) {
|
|
|
|
|
-
|
|
|
|
|
- Column(){
|
|
|
|
|
-
|
|
|
|
|
- XComponent({
|
|
|
|
|
- id: 'xcomponentId',
|
|
|
|
|
- type: 'surface',
|
|
|
|
|
- libraryname: 'ijkplayer_napi',
|
|
|
|
|
- controller: this.xcomponentController
|
|
|
|
|
-
|
|
|
|
|
- })
|
|
|
|
|
- .onLoad((event?: object) => {
|
|
|
|
|
- if (!!event) {
|
|
|
|
|
- this.initDelayPlay(event);
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- .onDestroy(() => {
|
|
|
|
|
- })
|
|
|
|
|
- .width('100%')
|
|
|
|
|
- // .width(this.videoWidth)
|
|
|
|
|
- .aspectRatio(this.videoAspectRatio)
|
|
|
|
|
- }
|
|
|
|
|
- .aspectRatio(this.videoAspectRatio)
|
|
|
|
|
- .justifyContent(FlexAlign.Center)
|
|
|
|
|
- .height(CommonConstants.FULL_PERCENT)
|
|
|
|
|
- .width(CommonConstants.FULL_PERCENT)
|
|
|
|
|
- .onClick(()=>{
|
|
|
|
|
-
|
|
|
|
|
- //是否因此播放器的按钮,默认是进入横屏模式隐藏,点击视频的时候显示
|
|
|
|
|
- this.isHide = !this.isHide
|
|
|
|
|
- // ToastUtil.showToast('你点击了屏幕')
|
|
|
|
|
-
|
|
|
|
|
- })
|
|
|
|
|
- // .zIndex(0)
|
|
|
|
|
- // .hitTestBehavior(HitTestMode.Transparent)
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- Image($r('app.media.icon_load'))
|
|
|
|
|
- .objectFit(ImageFit.Auto)
|
|
|
|
|
- .width('120px')
|
|
|
|
|
- .height('120px')
|
|
|
|
|
- .visibility(this.loadingVisible)
|
|
|
|
|
- .border({ width: 0 })
|
|
|
|
|
- .borderStyle(BorderStyle.Dashed)
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- Stack() {
|
|
|
|
|
- Progress({
|
|
|
|
|
- value: Math.floor(this.bright * CommonConstants.ONE_HUNDRED),
|
|
|
|
|
- type: ProgressType.Ring
|
|
|
|
|
- })
|
|
|
|
|
- .width(CommonConstants.FULL_PERCENT)
|
|
|
|
|
- .aspectRatio(CommonConstants.ASPECT_RATIO)
|
|
|
|
|
- Image($r('app.media.ic_brightness'))
|
|
|
|
|
- .width(PlayConstants.PLAYER_IMAGE_WIDTH)
|
|
|
|
|
- .aspectRatio(CommonConstants.ASPECT_RATIO)
|
|
|
|
|
- }
|
|
|
|
|
- .width(55)
|
|
|
|
|
- .aspectRatio(CommonConstants.ASPECT_RATIO)
|
|
|
|
|
- .visibility(this.brightShow ? Visibility.Visible : Visibility.Hidden)
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- //音量控制
|
|
|
|
|
- Stack() {
|
|
|
|
|
- Progress({
|
|
|
|
|
- value: Math.floor(this.volume * CommonConstants.ONE_HUNDRED),
|
|
|
|
|
- type: ProgressType.Ring
|
|
|
|
|
- })
|
|
|
|
|
- .width(CommonConstants.FULL_PERCENT)
|
|
|
|
|
- .aspectRatio(CommonConstants.ASPECT_RATIO)
|
|
|
|
|
- Image($r('app.media.ic_volume'))
|
|
|
|
|
- .width(PlayConstants.PLAYER_IMAGE_WIDTH)
|
|
|
|
|
- .aspectRatio(CommonConstants.ASPECT_RATIO)
|
|
|
|
|
- }
|
|
|
|
|
- .width(55)
|
|
|
|
|
- .aspectRatio(CommonConstants.ASPECT_RATIO)
|
|
|
|
|
- .visibility(this.volumeShow ? Visibility.Visible : Visibility.Hidden)
|
|
|
|
|
- //手势拖动快进和快退
|
|
|
|
|
- Column(){
|
|
|
|
|
- Row(){
|
|
|
|
|
- Text(this.currentTime)
|
|
|
|
|
- .fontSize(18)
|
|
|
|
|
- .fontColor($r('app.color.title_bar_bg'))
|
|
|
|
|
- .margin({ top:5 })
|
|
|
|
|
- .fontWeight(80)
|
|
|
|
|
- .padding({top:8})
|
|
|
|
|
- Text('/')
|
|
|
|
|
- .margin({ top:5 })
|
|
|
|
|
- .fontColor(Color.White)
|
|
|
|
|
- .padding({top:8})
|
|
|
|
|
- .fontWeight(80)
|
|
|
|
|
- Text(this.totalTime)
|
|
|
|
|
- .fontSize(14)
|
|
|
|
|
- .fontColor(Color.White)
|
|
|
|
|
- .margin({ top:5 })
|
|
|
|
|
- .padding({top:8})
|
|
|
|
|
- .fontWeight(80)
|
|
|
|
|
- }
|
|
|
|
|
- Slider({
|
|
|
|
|
- value: this.progressValue,
|
|
|
|
|
- min: 0,
|
|
|
|
|
- max: this.PROGRESS_MAX_VALUE,
|
|
|
|
|
- step: 1,
|
|
|
|
|
- style: SliderStyle.OutSet
|
|
|
|
|
- })
|
|
|
|
|
- .width(150)
|
|
|
|
|
- .blockColor(Color.Red)
|
|
|
|
|
- .trackColor($r('app.color.track_color'))
|
|
|
|
|
- .selectedColor($r('app.color.title_bar_bg'))
|
|
|
|
|
- .trackThickness(PlayConstants.PROGRESS_TRACK_THICKNESS)
|
|
|
|
|
- .margin({ left: 8,right:8 })
|
|
|
|
|
- .showSteps(true)
|
|
|
|
|
- .showTips(true)
|
|
|
|
|
- .enabled(this.slideEnable)
|
|
|
|
|
- .onChange((value: number, mode: SliderChangeMode) => {
|
|
|
|
|
- // if (mode == 2) {
|
|
|
|
|
- // this.isSeekTo = true;
|
|
|
|
|
- // this.mDestroyPage = false;
|
|
|
|
|
- // this.showLoadIng();
|
|
|
|
|
- // LogUtils.getInstance().LOGI("slider-->seekValue start:" + value);
|
|
|
|
|
- // let seekValue = value * (this.mIjkMediaPlayer.getDuration() / 100);
|
|
|
|
|
- // this.seekTo(seekValue + "");
|
|
|
|
|
- // this.setProgress()
|
|
|
|
|
- // LogUtils.getInstance().LOGI("slider-->seekValue end:" + seekValue);
|
|
|
|
|
- //
|
|
|
|
|
- // this.isSeekTo = false;
|
|
|
|
|
- // }
|
|
|
|
|
- })
|
|
|
|
|
- }
|
|
|
|
|
- .backgroundColor($r('app.color.pri_bg'))
|
|
|
|
|
- .backgroundBlurStyle(BlurStyle.BACKGROUND_ULTRA_THICK)
|
|
|
|
|
- .opacity(0.7)
|
|
|
|
|
- .borderRadius(22)
|
|
|
|
|
- .visibility(this.seekToShow ? Visibility.Visible : Visibility.Hidden)
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- .width(this.videoWidth)
|
|
|
|
|
- .height(this.videoHeight)
|
|
|
|
|
- .clip(true)
|
|
|
|
|
- .backgroundColor('#000000')
|
|
|
|
|
- .hitTestBehavior(HitTestMode.Transparent)
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- Column() {
|
|
|
|
|
-
|
|
|
|
|
- Column() {
|
|
|
|
|
- //播放标题
|
|
|
|
|
- Column() {
|
|
|
|
|
- this.PlayTitle()
|
|
|
|
|
- }
|
|
|
|
|
- .position({x:0,y:0})
|
|
|
|
|
- .width('100%')
|
|
|
|
|
- .margin(this.isLandscape?{top:13}:{top:0})
|
|
|
|
|
- .height(PlayConstants.HEIGHT)
|
|
|
|
|
-
|
|
|
|
|
- Stack(){
|
|
|
|
|
- //手势拖动快进
|
|
|
|
|
- Column()
|
|
|
|
|
- .width(CommonConstants.FULL_PERCENT)
|
|
|
|
|
- .height('100%')
|
|
|
|
|
- .gesture(
|
|
|
|
|
- PanGesture(this.panOptionSeekTo)
|
|
|
|
|
- .onActionStart((event?: GestureEvent) => {
|
|
|
|
|
- this.onSeekToActionStart(event);
|
|
|
|
|
- })
|
|
|
|
|
- .onActionUpdate((event?: GestureEvent) => {
|
|
|
|
|
- this.onSeekToActionUpdate(event);
|
|
|
|
|
- })
|
|
|
|
|
- .onActionEnd(() => {
|
|
|
|
|
- this.onSeekToActionEnd();
|
|
|
|
|
- })
|
|
|
|
|
- )
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- Row(){
|
|
|
|
|
- //亮度控制
|
|
|
|
|
- Column()
|
|
|
|
|
- .width('50%')
|
|
|
|
|
- .height('100%')
|
|
|
|
|
- .gesture(
|
|
|
|
|
- PanGesture(this.panOptionBright)
|
|
|
|
|
- .onActionStart((event?: GestureEvent) => {
|
|
|
|
|
- this.onBrightActionStart(event);
|
|
|
|
|
- })
|
|
|
|
|
- .onActionUpdate((event?: GestureEvent) => {
|
|
|
|
|
- this.onBrightActionUpdate(event);
|
|
|
|
|
- })
|
|
|
|
|
- .onActionEnd(() => {
|
|
|
|
|
- this.onActionEnd();
|
|
|
|
|
- })
|
|
|
|
|
- )
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- //音量控制
|
|
|
|
|
- Column()
|
|
|
|
|
- .width('50%')
|
|
|
|
|
- .height('100%')
|
|
|
|
|
- .gesture(
|
|
|
|
|
- PanGesture(this.panOptionVolume)
|
|
|
|
|
- .onActionStart((event?: GestureEvent) => {
|
|
|
|
|
-
|
|
|
|
|
- this.onVolumeActionStart(event);
|
|
|
|
|
- })
|
|
|
|
|
- .onActionUpdate((event?: GestureEvent) => {
|
|
|
|
|
- this.onVolumeActionUpdate(event);
|
|
|
|
|
- })
|
|
|
|
|
- .onActionEnd(() => {
|
|
|
|
|
- this.onActionEnd();
|
|
|
|
|
- })
|
|
|
|
|
- )
|
|
|
|
|
- }
|
|
|
|
|
- .width(CommonConstants.FULL_PERCENT)
|
|
|
|
|
- .height('100%')
|
|
|
|
|
- .hitTestBehavior(HitTestMode.Transparent)
|
|
|
|
|
- }
|
|
|
|
|
- .height('65%')
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- Image($r('app.media.icon_replay'))
|
|
|
|
|
- .objectFit(ImageFit.Auto)
|
|
|
|
|
- .width('120px')
|
|
|
|
|
- .height('120px')
|
|
|
|
|
- .position({x:'45.1%',y:'47.5%'})
|
|
|
|
|
- // .visibility(this.replayVisible)
|
|
|
|
|
- .border({ width: 0 })
|
|
|
|
|
- .visibility(Visibility.None)
|
|
|
|
|
- .borderStyle(BorderStyle.Dashed)
|
|
|
|
|
- // .hitTestBehavior(HitTestMode.Transparent)
|
|
|
|
|
- .onClick(() => {
|
|
|
|
|
- this.startPlayOrResumePlay();
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- // Text(this.subtitleText)
|
|
|
|
|
- // .fontSize(16)
|
|
|
|
|
- // .fontColor(Color.White)
|
|
|
|
|
- // .padding(10)
|
|
|
|
|
- // .backgroundColor(Color.Black)
|
|
|
|
|
- // .opacity(0.7)
|
|
|
|
|
- // .position({ bottom: 30, left: 10, right: 10 })
|
|
|
|
|
- // .textAlign(TextAlign.Center)
|
|
|
|
|
- // .visibility(this.subtitleText ? Visibility.Visible : Visibility.Hidden)
|
|
|
|
|
-
|
|
|
|
|
- //播放 暂停,下一首,上一首
|
|
|
|
|
- Row() {
|
|
|
|
|
- Image($r('app.media.ic_previous'))
|
|
|
|
|
- .width($r('app.float.control_image_width'))
|
|
|
|
|
- .aspectRatio(CommonConstants.ASPECT_RATIO)
|
|
|
|
|
- .onClick(async () => {
|
|
|
|
|
- this.playPrevious()
|
|
|
|
|
-
|
|
|
|
|
- })
|
|
|
|
|
- Column() {
|
|
|
|
|
- Image(this.CONTROL_PlayStatus === PlayStatus.PLAY ?
|
|
|
|
|
- $r('app.media.ic_public_play') : $r('app.media.ic_public_pause'))
|
|
|
|
|
- .width(38)
|
|
|
|
|
- .aspectRatio(CommonConstants.ASPECT_RATIO)
|
|
|
|
|
- .onClick(async () => {
|
|
|
|
|
- if (this.CONTROL_PlayStatus === PlayStatus.PLAY) {
|
|
|
|
|
- this.pause();
|
|
|
|
|
- } else {
|
|
|
|
|
- this.startPlayOrResumePlay();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- })
|
|
|
|
|
- }
|
|
|
|
|
- .layoutWeight(1)
|
|
|
|
|
-
|
|
|
|
|
- Image($r('app.media.ic_next'))
|
|
|
|
|
- .width($r('app.float.control_image_width'))
|
|
|
|
|
- .aspectRatio(CommonConstants.ASPECT_RATIO)
|
|
|
|
|
- .onClick(() => {
|
|
|
|
|
-
|
|
|
|
|
- this.playNext();
|
|
|
|
|
-
|
|
|
|
|
- })
|
|
|
|
|
- }
|
|
|
|
|
- .width(PlayConstants.CONTROL_ROW_WIDTH)
|
|
|
|
|
- .margin(10)
|
|
|
|
|
- .visibility(this.isHide?Visibility.None:Visibility.Visible)
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- //播放进度条
|
|
|
|
|
- Row() {
|
|
|
|
|
- Column(){
|
|
|
|
|
- if (this.playType === 0) {
|
|
|
|
|
- Image($r('app.media.loop'))
|
|
|
|
|
- .width($r('app.float.control_image_width'))
|
|
|
|
|
- .margin(10)
|
|
|
|
|
- .aspectRatio(CommonConstants.ASPECT_RATIO)
|
|
|
|
|
- } else if (this.playType === 1) {
|
|
|
|
|
- Image($r('app.media.single'))
|
|
|
|
|
- .width($r('app.float.control_image_width'))
|
|
|
|
|
- .margin(10)
|
|
|
|
|
- .aspectRatio(CommonConstants.ASPECT_RATIO)
|
|
|
|
|
- } else if (this.playType === 2) {
|
|
|
|
|
- Image($r('app.media.play_nor'))
|
|
|
|
|
- .width($r('app.float.control_image_width'))
|
|
|
|
|
- .margin(10)
|
|
|
|
|
- .aspectRatio(CommonConstants.ASPECT_RATIO)
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- .onClick(async () => {
|
|
|
|
|
- let itype = this.playType+1
|
|
|
|
|
- if( itype >= 3 ){
|
|
|
|
|
- this.playType = 0
|
|
|
|
|
- ToastUtil.showToast('连续播放')
|
|
|
|
|
- }else if(itype ===1){
|
|
|
|
|
- this.playType = 1
|
|
|
|
|
- ToastUtil.showToast('单片循环')
|
|
|
|
|
- }else if(itype ===2){
|
|
|
|
|
- this.playType = 2
|
|
|
|
|
- ToastUtil.showToast('正常播放')
|
|
|
|
|
- }else if(itype ===0){
|
|
|
|
|
- this.playType = 0
|
|
|
|
|
- ToastUtil.showToast('连续播放')
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- Text(this.currentTime)
|
|
|
|
|
- .fontSize($r('app.float.slider_font_size'))
|
|
|
|
|
- .fontColor(Color.White)
|
|
|
|
|
- .margin(3)
|
|
|
|
|
- Slider({
|
|
|
|
|
- value: this.progressValue,
|
|
|
|
|
- min: 0,
|
|
|
|
|
- max: this.PROGRESS_MAX_VALUE,
|
|
|
|
|
- step: 1,
|
|
|
|
|
- style: SliderStyle.OutSet
|
|
|
|
|
- })
|
|
|
|
|
- .width('600px')
|
|
|
|
|
- .blockColor(Color.White)
|
|
|
|
|
- .trackColor($r('app.color.track_color'))
|
|
|
|
|
- .selectedColor(Color.White)
|
|
|
|
|
- .trackThickness(PlayConstants.PROGRESS_TRACK_THICKNESS)
|
|
|
|
|
- .layoutWeight(1)
|
|
|
|
|
- .margin({ left: PlayConstants.PROGRESS_MARGIN_LEFT })
|
|
|
|
|
- .showSteps(true)
|
|
|
|
|
- .showTips(true)
|
|
|
|
|
- .enabled(this.slideEnable)
|
|
|
|
|
- .onChange((value: number, mode: SliderChangeMode) => {
|
|
|
|
|
- // if (mode == 2) {
|
|
|
|
|
- this.isSeekTo = true;
|
|
|
|
|
- this.mDestroyPage = false;
|
|
|
|
|
- this.showLoadIng();
|
|
|
|
|
- LogUtils.getInstance().LOGI("slider-->seekValue start:" + value);
|
|
|
|
|
- let seekValue = value * (this.mIjkMediaPlayer.getDuration() / 100);
|
|
|
|
|
- this.seekTo(seekValue + "");
|
|
|
|
|
- // this.setProgress()
|
|
|
|
|
- LogUtils.getInstance().LOGI("slider-->seekValue end:" + seekValue);
|
|
|
|
|
- this.isSeekTo = false;
|
|
|
|
|
- // }
|
|
|
|
|
- })
|
|
|
|
|
- Text(this.totalTime)
|
|
|
|
|
- .fontSize($r('app.float.slider_font_size'))
|
|
|
|
|
- .fontColor(Color.White)
|
|
|
|
|
- .margin(3)
|
|
|
|
|
- .margin({ left: PlayConstants.PROGRESS_MARGIN_LEFT })
|
|
|
|
|
- Text(this.multiple)
|
|
|
|
|
- .fontSize(16)
|
|
|
|
|
- .fontColor(Color.White)
|
|
|
|
|
- .margin({ right:25,left:18 })
|
|
|
|
|
- .visibility(this.isLandscape?Visibility.None:Visibility.None)
|
|
|
|
|
- .id('down_xid')
|
|
|
|
|
- .onClick(()=>{
|
|
|
|
|
- this.showMultipleDialog('down_xid')
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- //播放列表
|
|
|
|
|
- Image($r('app.media.playlist'))
|
|
|
|
|
- .width($r('app.float.control_image_width'))
|
|
|
|
|
- .margin({ right:10,left:20 })
|
|
|
|
|
- .aspectRatio(CommonConstants.ASPECT_RATIO)
|
|
|
|
|
- .bindSheet($$this.isShowSheetView, this.PlayListSheet(), {
|
|
|
|
|
- height:this.isLandscape?'90%': '65%',
|
|
|
|
|
- dragBar: true,
|
|
|
|
|
- showClose: true,
|
|
|
|
|
- title: { title: $r('app.string.current_play_list', this.globalVideoList.length) }
|
|
|
|
|
- })
|
|
|
|
|
- .onClick(() => {
|
|
|
|
|
- this.isShowSheetView = !this.isShowSheetView;
|
|
|
|
|
- })
|
|
|
|
|
- // .onClick(async () => {
|
|
|
|
|
- // this.showPlayList()
|
|
|
|
|
- //
|
|
|
|
|
- // })
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- //横屏全屏功能
|
|
|
|
|
- Image($r('app.media.full_4'))
|
|
|
|
|
- .width($r('app.float.control_image_width'))
|
|
|
|
|
- .margin(10)
|
|
|
|
|
- .aspectRatio(CommonConstants.ASPECT_RATIO)
|
|
|
|
|
- .onClick(async () => {
|
|
|
|
|
- this.isLandscape = !this.isLandscape;
|
|
|
|
|
- if (this.isLandscape) {
|
|
|
|
|
-
|
|
|
|
|
- this.setOrientation(window.Orientation.USER_ROTATION_LANDSCAPE);
|
|
|
|
|
- } else {
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- this.setOrientation(window.Orientation.USER_ROTATION_PORTRAIT);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- })
|
|
|
|
|
- }
|
|
|
|
|
- .width(PlayConstants.PROGRESS_ROW_WIDTH)
|
|
|
|
|
- .visibility(this.isHide?Visibility.Hidden:Visibility.Visible)
|
|
|
|
|
- }
|
|
|
|
|
- .width(CommonConstants.FULL_PERCENT)
|
|
|
|
|
- .height(CommonConstants.FULL_PERCENT)
|
|
|
|
|
- .justifyContent(FlexAlign.End)
|
|
|
|
|
- }
|
|
|
|
|
- .justifyContent(FlexAlign.End)
|
|
|
|
|
- .margin({bottom:8})
|
|
|
|
|
-
|
|
|
|
|
- .onClick(()=>{
|
|
|
|
|
- if(this.isVideoLock){
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
- //是否因此播放器的按钮,点击视频的时候显示
|
|
|
|
|
- this.isHide = !this.isHide
|
|
|
|
|
- // ToastUtil.showToast('你点击了屏幕')
|
|
|
|
|
- //10s后自动隐藏
|
|
|
|
|
- this.setHideAfter()
|
|
|
|
|
-
|
|
|
|
|
- })
|
|
|
|
|
- }
|
|
|
|
|
- // .height(CommonConstants.FULL_PERCENT)
|
|
|
|
|
- // .width(CommonConstants.FULL_PERCENT)
|
|
|
|
|
- .backgroundColor(Color.Black)
|
|
|
|
|
- .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- @Builder
|
|
|
|
|
- PlayListSheet() {
|
|
|
|
|
- Column(){
|
|
|
|
|
- this.PlayList()
|
|
|
|
|
- }
|
|
|
|
|
- .width('100%')
|
|
|
|
|
- .height('100%')
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @Builder
|
|
|
|
|
- PlayList(){
|
|
|
|
|
- List() {
|
|
|
|
|
- LazyForEach(new LazyDataSource(this.globalVideoList), (item: VideoItem, index: number) => {
|
|
|
|
|
- ListItem() {
|
|
|
|
|
- this.VideoItemSon(item,index)
|
|
|
|
|
- }
|
|
|
|
|
- .onClick(() => {
|
|
|
|
|
- this.playIndex(index)
|
|
|
|
|
- })
|
|
|
|
|
- }, (item: VideoItem) => item.filePath)
|
|
|
|
|
- }
|
|
|
|
|
- .width('100%')
|
|
|
|
|
- .height('100%')
|
|
|
|
|
- .cachedCount(10)
|
|
|
|
|
- .padding({
|
|
|
|
|
- bottom: 0
|
|
|
|
|
- })
|
|
|
|
|
- .divider({
|
|
|
|
|
- strokeWidth: 1,
|
|
|
|
|
- color: '#E8E8E8',
|
|
|
|
|
- startMargin: 16,
|
|
|
|
|
- endMargin: 16
|
|
|
|
|
- })
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @Builder
|
|
|
|
|
- private VideoItemSon(item:VideoItem,index?:number){
|
|
|
|
|
-
|
|
|
|
|
- Row() {
|
|
|
|
|
- Stack() {
|
|
|
|
|
- Image(item.pixelMap === undefined ? $r('app.media.ic_avatar1') : item.pixelMapPath)
|
|
|
|
|
- .height(40)
|
|
|
|
|
- .width(50)
|
|
|
|
|
- .margin({ left: 20 ,top:2,bottom:2})
|
|
|
|
|
- .borderRadius(8)
|
|
|
|
|
- .clip(true)
|
|
|
|
|
- Image($r('app.media.video_play_center_btn'))
|
|
|
|
|
- .height(28)
|
|
|
|
|
- .width(28)
|
|
|
|
|
- .margin({ left: 20 })
|
|
|
|
|
- }
|
|
|
|
|
- .width('15%')
|
|
|
|
|
- Column() {
|
|
|
|
|
- Column() {
|
|
|
|
|
-
|
|
|
|
|
- Text(item.name)
|
|
|
|
|
- .fontSize(16)
|
|
|
|
|
- .fontColor(this.curIndex === index? $r('app.color.title_bar_bg'):Color.Black)
|
|
|
|
|
- .maxLines(1)
|
|
|
|
|
- .margin({ left: 20 })
|
|
|
|
|
- Row(){
|
|
|
|
|
- Text(item.cTime)
|
|
|
|
|
- .fontSize(11)
|
|
|
|
|
- .padding({ top: 8 })
|
|
|
|
|
- .fontColor(this.curIndex === index? $r('app.color.title_bar_bg'):Color.Gray)
|
|
|
|
|
- .margin({ left: 20 })
|
|
|
|
|
- Blank()
|
|
|
|
|
- Text(item.size)
|
|
|
|
|
- .fontSize(11)
|
|
|
|
|
- .padding({ top: 8 })
|
|
|
|
|
- .fontColor(this.curIndex === index? $r('app.color.title_bar_bg'):Color.Gray)
|
|
|
|
|
- .margin({ left: 20})
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- .height('100%')
|
|
|
|
|
- .width('100%')
|
|
|
|
|
- .justifyContent(FlexAlign.Center)
|
|
|
|
|
- .alignItems(HorizontalAlign.Start)
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- .height('100%')
|
|
|
|
|
- .width('65%')
|
|
|
|
|
-
|
|
|
|
|
- Column(){
|
|
|
|
|
- Image( $r('app.media.hm_play') )
|
|
|
|
|
- .height(16)
|
|
|
|
|
- .width(16)
|
|
|
|
|
- .clip(true)
|
|
|
|
|
- .visibility(this.curIndex === index?Visibility.Visible:Visibility.None)
|
|
|
|
|
- .margin({ right: 8 })
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- .width('20%')
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- .width('100%')
|
|
|
|
|
- .height(68)
|
|
|
|
|
- .justifyContent(FlexAlign.SpaceBetween)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @Builder
|
|
|
|
|
- private PlayTitle() {
|
|
|
|
|
-
|
|
|
|
|
- Row() {
|
|
|
|
|
- Row(){
|
|
|
|
|
- Image($r('app.media.back'))
|
|
|
|
|
- .width($r('app.float.title_image_size'))
|
|
|
|
|
- .aspectRatio(CommonConstants.ASPECT_RATIO)
|
|
|
|
|
- .hitTestBehavior(HitTestMode.Transparent)
|
|
|
|
|
- // .visibility(this.isLandscape?Visibility.None:Visibility.Visible)
|
|
|
|
|
-
|
|
|
|
|
- Text(this.name)
|
|
|
|
|
- .fontColor(Color.White)
|
|
|
|
|
- .fontSize($r('app.float.title_font_size'))
|
|
|
|
|
- .textOverflow({overflow: TextOverflow.MARQUEE}) //超长滚动
|
|
|
|
|
- .maxLines(1)
|
|
|
|
|
- .margin({ left: 2,right:30 })
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- .layoutWeight(1)
|
|
|
|
|
- .visibility(this.isHide?Visibility.Hidden:Visibility.Visible)
|
|
|
|
|
- .onClick(() => {
|
|
|
|
|
-
|
|
|
|
|
- if(this.isLandscape){
|
|
|
|
|
- this.setOrientation(window.Orientation.USER_ROTATION_PORTRAIT);
|
|
|
|
|
- this.isLandscape = false
|
|
|
|
|
- }else{
|
|
|
|
|
- router.back();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- Text(this.multiple)
|
|
|
|
|
- .fontSize(16)
|
|
|
|
|
- .fontColor(Color.White)
|
|
|
|
|
- .margin({ right:15 })
|
|
|
|
|
- .visibility(this.isHide?Visibility.None:Visibility.Visible)
|
|
|
|
|
- .id('xid')
|
|
|
|
|
- .onClick(()=>{
|
|
|
|
|
- this.showMultipleDialog('xid')
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- Image(this.isYesFull?$r('app.media.not_full'):$r('app.media.yes_full'))
|
|
|
|
|
- .width($r('app.float.title_image_size'))
|
|
|
|
|
- .margin({left:6,right:8})
|
|
|
|
|
- .visibility(this.isLandscape?(this.isHide?Visibility.None:Visibility.Visible):Visibility.None)
|
|
|
|
|
- .onClick(() => {
|
|
|
|
|
- if(!this.isLandscape){
|
|
|
|
|
- ToastUtil.showToast('当前视频不支持撑满全屏')
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
- let VideoWidth = this.mIjkMediaPlayer.getVideoWidth();
|
|
|
|
|
- let VideoHeight = this.mIjkMediaPlayer.getVideoHeight();
|
|
|
|
|
- if(VideoHeight > VideoWidth) { //竖屏视频
|
|
|
|
|
- ToastUtil.showToast('当前视频不支持撑满全屏')
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
- this.isYesFull = !this.isYesFull
|
|
|
|
|
- if(this.isYesFull){
|
|
|
|
|
- ToastUtil.showToast('撑满全屏')
|
|
|
|
|
- }else{
|
|
|
|
|
- ToastUtil.showToast('恢复不撑满')
|
|
|
|
|
- }
|
|
|
|
|
- this.getVideoSize()
|
|
|
|
|
-
|
|
|
|
|
- })
|
|
|
|
|
- //视频的画中画功能布局
|
|
|
|
|
- Image($r('app.media.hua_zhong_hua'))
|
|
|
|
|
- .width($r('app.float.title_image_size'))
|
|
|
|
|
- .visibility(this.isHide?Visibility.None:Visibility.Visible)
|
|
|
|
|
- .margin({left:6,right:6})
|
|
|
|
|
- .onClick(() => {
|
|
|
|
|
-
|
|
|
|
|
- this.startPip();
|
|
|
|
|
-
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- //视频的字幕功能
|
|
|
|
|
- // Image($r('app.media.lyric'))
|
|
|
|
|
- // .width($r('app.float.title_image_size'))
|
|
|
|
|
- // .visibility(this.isHide?Visibility.None:Visibility.Visible)
|
|
|
|
|
- // .margin({left:6,right:6})
|
|
|
|
|
- // .onClick(() => {
|
|
|
|
|
- //
|
|
|
|
|
- // this.callFilePickerSelectFile()
|
|
|
|
|
- //
|
|
|
|
|
- // })
|
|
|
|
|
-
|
|
|
|
|
- Image(this.isVideoLock ? $r('app.media.icon_lock') : $r('app.media.icon_lock_open'))
|
|
|
|
|
- .height(24)
|
|
|
|
|
- .width(24)
|
|
|
|
|
- .margin({left:6,right:6})
|
|
|
|
|
- .fillColor(Color.White)
|
|
|
|
|
- .visibility(this.isHide?(this.isVideoLock?Visibility.Visible:Visibility.None):Visibility.Visible)
|
|
|
|
|
- .onClick(() => {
|
|
|
|
|
- this.isVideoLock = !this.isVideoLock;
|
|
|
|
|
- if(this.isVideoLock){
|
|
|
|
|
- this.isHide = true
|
|
|
|
|
- }else{
|
|
|
|
|
- this.isHide = false
|
|
|
|
|
- //10s后自动隐藏
|
|
|
|
|
- this.setHideAfter()
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- })
|
|
|
|
|
- Column() {
|
|
|
|
|
- AVCastPicker({
|
|
|
|
|
- normalColor: Color.White,
|
|
|
|
|
- onStateChange: this.onStateVastChange
|
|
|
|
|
- })
|
|
|
|
|
- .width(24)
|
|
|
|
|
- .height(24)
|
|
|
|
|
- }
|
|
|
|
|
- .visibility(this.isHide?Visibility.Hidden:this.isBgPlayOpen?Visibility.Visible:Visibility.None)
|
|
|
|
|
- }
|
|
|
|
|
- .width(PlayConstants.ROW_WIDTH)
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 应用可以通过onStateChange接口监听组件显示/消失状态,当组件显示时建议不要销毁AVCastPicker的显示;当组件消失时,再根据业务隐藏AVCastPicker。
|
|
|
|
|
- private onStateVastChange(state: AVCastPickerState) {
|
|
|
|
|
- if (state == AVCastPickerState.STATE_APPEARING) {
|
|
|
|
|
- console.log('The picker starts showing.');
|
|
|
|
|
- } else if (state == AVCastPickerState.STATE_DISAPPEARING) {
|
|
|
|
|
- console.log('The picker finishes presenting.');
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- //10s后自动隐藏
|
|
|
|
|
- private setHideAfter() {
|
|
|
|
|
- if(!this.isHide){
|
|
|
|
|
- setTimeout(()=>{
|
|
|
|
|
- this.isHide = true
|
|
|
|
|
- },10000)
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- private initDelayPlay(context: object) {
|
|
|
|
|
- this.mContext = context;
|
|
|
|
|
- let that = this;
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- that.startPlayOrResumePlay();
|
|
|
|
|
- }, 200)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private startPlayOrResumePlay() {
|
|
|
|
|
- this.mDestroyPage = false;
|
|
|
|
|
- LogUtils.getInstance().LOGI("startPlayOrResumePlay start this.CONTROL_PlayStatus:" + this.CONTROL_PlayStatus)
|
|
|
|
|
- if (this.CONTROL_PlayStatus == PlayStatus.INIT) {
|
|
|
|
|
- this.stopProgressTask();
|
|
|
|
|
- this.startProgressTask();
|
|
|
|
|
- this.play(this.videoUrl.toString());
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- if (this.CONTROL_PlayStatus == PlayStatus.PAUSE) {
|
|
|
|
|
- this.mIjkMediaPlayer.start();
|
|
|
|
|
- this.setProgress()
|
|
|
|
|
- this.CONTROL_PlayStatus = PlayStatus.PLAY
|
|
|
|
|
- }
|
|
|
|
|
- this.updateSessionPlayState(true)
|
|
|
|
|
- this.watchStatus();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private completionNum(num: number): string | number {
|
|
|
|
|
- if (num < 10) {
|
|
|
|
|
- return '0' + num;
|
|
|
|
|
- } else {
|
|
|
|
|
- return num;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private stringForTime(timeMs: number): string {
|
|
|
|
|
- let totalSeconds: number | string = (timeMs / 1000);
|
|
|
|
|
- let newSeconds: number | string = totalSeconds % 60;
|
|
|
|
|
- let minutes: number | string = (totalSeconds / 60) % 60;
|
|
|
|
|
- let hours: number | string = totalSeconds / 3600;
|
|
|
|
|
- //LogUtils.getInstance().LOGI("stringForTime hours:" + hours + ",minutes:" + minutes + ",seconds:" + newSeconds);
|
|
|
|
|
- hours = this.completionNum(Math.floor(Math.floor(hours * 100) / 100));
|
|
|
|
|
- minutes = this.completionNum(Math.floor(Math.floor(minutes * 100) / 100));
|
|
|
|
|
- newSeconds = Math.floor(Math.floor(newSeconds * 100) / 100)
|
|
|
|
|
- if (this.isCurrentTime) {
|
|
|
|
|
- if (this.oldSeconds < newSeconds || newSeconds === 0 || this.isSeekTo) {
|
|
|
|
|
- this.oldSeconds = newSeconds
|
|
|
|
|
- } else {
|
|
|
|
|
- newSeconds = this.oldSeconds
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- newSeconds = this.completionNum(newSeconds);
|
|
|
|
|
- if (hours > 0) {
|
|
|
|
|
- return hours + ":" + minutes + ":" + newSeconds;
|
|
|
|
|
- } else {
|
|
|
|
|
- return minutes + ":" + newSeconds;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private setProgress() {
|
|
|
|
|
- let position = this.mIjkMediaPlayer.getCurrentPosition();
|
|
|
|
|
- let duration = this.mIjkMediaPlayer.getDuration();
|
|
|
|
|
- let pos = 0;
|
|
|
|
|
- if (duration > 0) {
|
|
|
|
|
- this.slideEnable = true;
|
|
|
|
|
- let curPercent = position / duration;
|
|
|
|
|
- pos = curPercent * 100;
|
|
|
|
|
- if (pos > this.PROGRESS_MAX_VALUE) {
|
|
|
|
|
- this.progressValue = this.PROGRESS_MAX_VALUE
|
|
|
|
|
- } else {
|
|
|
|
|
- this.progressValue = pos;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- // LogUtils.getInstance()
|
|
|
|
|
- // .LOGI("setProgress position:" + position + ",duration:" + duration + ",progressValue:" + pos);
|
|
|
|
|
- this.totalTime = this.stringForTime(duration);
|
|
|
|
|
- if (position > duration) {
|
|
|
|
|
- position = duration;
|
|
|
|
|
- }
|
|
|
|
|
- this.isCurrentTime = true;
|
|
|
|
|
- this.currentTime = this.stringForTime(position);
|
|
|
|
|
- this.isCurrentTime = false
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private startProgressTask() {
|
|
|
|
|
- let that = this;
|
|
|
|
|
- this.updateProgressTimer = setInterval(() => {
|
|
|
|
|
- //LogUtils.getInstance().LOGI("startProgressTask");
|
|
|
|
|
- if (!that.mDestroyPage) {
|
|
|
|
|
- that.setProgress();
|
|
|
|
|
- }
|
|
|
|
|
- }, 300);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private stopProgressTask() {
|
|
|
|
|
- LogUtils.getInstance().LOGI("stopProgressTask");
|
|
|
|
|
- clearInterval(this.updateProgressTimer);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private showLoadIng() {
|
|
|
|
|
- this.loadingVisible = Visibility.Visible;
|
|
|
|
|
- this.replayVisible = Visibility.None;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private hideLoadIng() {
|
|
|
|
|
- this.loadingVisible = Visibility.None;
|
|
|
|
|
- this.replayVisible = Visibility.None;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private showRePlay() {
|
|
|
|
|
- this.loadingVisible = Visibility.None;
|
|
|
|
|
- this.replayVisible = Visibility.Visible;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private async play(url: string) {
|
|
|
|
|
- let that = this;
|
|
|
|
|
- that.showLoadIng();
|
|
|
|
|
- //设置XComponent回调的context
|
|
|
|
|
- if (!!this.mContext) {
|
|
|
|
|
- this.mIjkMediaPlayer.setContext(this.mContext, 'xcomponentId');
|
|
|
|
|
- }
|
|
|
|
|
- if (this.CONTROL_PlayStatus == PlayStatus.INIT) {
|
|
|
|
|
- this.mIjkMediaPlayer.reset();
|
|
|
|
|
- }
|
|
|
|
|
- this.CONTROL_PlayStatus = PlayStatus.PLAY;
|
|
|
|
|
- //设置debug模式
|
|
|
|
|
- this.mIjkMediaPlayer.setDebug(false);
|
|
|
|
|
- //初始化配置
|
|
|
|
|
- this.mIjkMediaPlayer.native_setup();
|
|
|
|
|
- // 初始化配置后需要重新设置音频流音量,否则音量为默认值1.0
|
|
|
|
|
- this.mIjkMediaPlayer.setVolume(this.volume.toString(), this.volume.toString());
|
|
|
|
|
- //设置视频源
|
|
|
|
|
- this.mIjkMediaPlayer.setDataSource(url);
|
|
|
|
|
- //设置视频源http请求头
|
|
|
|
|
- let headers = new Map([
|
|
|
|
|
- ["user_agent", "Mozilla/5.0 BiliDroid/7.30.0 (bbcallen@gmail.com)"],
|
|
|
|
|
- ["referer", "https://www.bilibili.com"]
|
|
|
|
|
- ]);
|
|
|
|
|
- this.mIjkMediaPlayer.setDataSourceHeader(headers);
|
|
|
|
|
- if(PreferencesUtil.getBooleanSync(SettingPage.IS_MIDIACODEC_OPEN,false)){
|
|
|
|
|
- this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", "1"); // 启用硬件解码,会导致无法顺序播放
|
|
|
|
|
- }else{
|
|
|
|
|
- this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", "0");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- //使用精确寻帧 例如,拖动播放后,会寻找最近的关键帧进行播放,很有可能关键帧的位置不是拖动后的位置,而是较前的位置.可以设置这个参数来解决问题
|
|
|
|
|
- this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "enable-accurate-seek", "1");
|
|
|
|
|
- const fileSize = await this.getFileSize(this.videoUrl);
|
|
|
|
|
- let bufferSize = 2 * 1024 * 1024; // 默认缓冲区大小为2MB
|
|
|
|
|
- if (fileSize > 3 * 1024 * 1024 * 1024) { // 文件大于3GB
|
|
|
|
|
- bufferSize = 25 * 1024 * 1024; // 设置缓冲区大小为25MB
|
|
|
|
|
- }
|
|
|
|
|
- //预读数据的缓冲区大小.修复大文件播放前几秒挂掉的bug,太大了会导致倍数播放失效
|
|
|
|
|
- this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", bufferSize +'');
|
|
|
|
|
- //停止预读的最小帧数
|
|
|
|
|
- // this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "min-frames", "100");
|
|
|
|
|
-
|
|
|
|
|
- this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "reconnect", '1');////重连模式,如果中途服务器断开了连接,让它重新连接
|
|
|
|
|
- // 设置其他缓冲相关选项
|
|
|
|
|
- this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "min-frames", "100"); // 设置最小缓冲帧数
|
|
|
|
|
- this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-frames", "1000"); // 设置最大缓冲
|
|
|
|
|
- //启动预加载
|
|
|
|
|
- this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", "1");
|
|
|
|
|
- // 设置无缓冲,这是播放器的缓冲区,有数据就播放
|
|
|
|
|
- this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", "0");
|
|
|
|
|
- //跳帧处理,放CPU处理较慢时,进行跳帧处理,保证播放流程,画面和声音同步
|
|
|
|
|
- this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", "5");
|
|
|
|
|
- // 最大缓冲cache是3s, 有时候网络波动,会突然在短时间内收到好几秒的数据
|
|
|
|
|
- // 因此需要播放器丢包,才不会累积延时
|
|
|
|
|
- // 这个和第三个参数packet-buffering无关。
|
|
|
|
|
- this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max_cached_duration", "3000");
|
|
|
|
|
- // 无限制收流
|
|
|
|
|
- this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "infbuf", "1");
|
|
|
|
|
- this.mIjkMediaPlayer.setOptionLong(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "infbuf", "1")
|
|
|
|
|
- // 屏幕常亮
|
|
|
|
|
- this.mIjkMediaPlayer.setScreenOnWhilePlaying(true);
|
|
|
|
|
- // 设置超时
|
|
|
|
|
- this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "timeout", "10000000");
|
|
|
|
|
- this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "connect_timeout", "10000000");
|
|
|
|
|
- this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "addrinfo_timeout", "10000000");
|
|
|
|
|
- this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_timeout", "10000000");
|
|
|
|
|
- // 变速播放
|
|
|
|
|
- this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "soundtouch", "1");
|
|
|
|
|
- this.mIjkMediaPlayer.setSpeed(this.playSpeed);
|
|
|
|
|
- let Speed = this.mIjkMediaPlayer.getSpeed()
|
|
|
|
|
-
|
|
|
|
|
- // this.videoUrl = this.globalVideoList[this.curIndex].filePath
|
|
|
|
|
- // let srtPath = this.videoUrl.substring(0,this.videoUrl.lastIndexOf('.'))+'.srt'
|
|
|
|
|
- // this.setSubTitleFile(srtPath)
|
|
|
|
|
-
|
|
|
|
|
- LogUtils.getInstance().LOGI('getSpeed--' + Speed)
|
|
|
|
|
- //是否开启循环播放
|
|
|
|
|
- // this.mIjkMediaPlayer.setLoopCount(this.loop);
|
|
|
|
|
- let mOnVideoSizeChangedListener: OnVideoSizeChangedListener = {
|
|
|
|
|
- onVideoSizeChanged: (width: number, height: number, sar_num: number, sar_den: number) => {
|
|
|
|
|
- if (height === 0) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- const va = width / height;
|
|
|
|
|
- const vpa = that.videoParentAspectRatio;
|
|
|
|
|
- if (vpa > va) {
|
|
|
|
|
- that.videoWidth = (width / (height * vpa)) * 100 + '%';
|
|
|
|
|
- } else {
|
|
|
|
|
- that.videoWidth = '100%';
|
|
|
|
|
- }
|
|
|
|
|
- if (width && height) {
|
|
|
|
|
- that.videoAspectRatio = width / height;
|
|
|
|
|
- }
|
|
|
|
|
- LogUtils.getInstance()
|
|
|
|
|
- .LOGI("setOnVideoSizeChangedListener-->go:" + width + "," + height + "," + sar_num + "," + sar_den);
|
|
|
|
|
- that.getVideoSize();
|
|
|
|
|
- that.hideLoadIng();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- this.mIjkMediaPlayer.setOnVideoSizeChangedListener(mOnVideoSizeChangedListener);
|
|
|
|
|
- let mOnPreparedListener: OnPreparedListener = {
|
|
|
|
|
- onPrepared: () => {
|
|
|
|
|
- if(PreferencesUtil.getBooleanSync(SettingPage.iS_MEMORY_PLAY,true)){
|
|
|
|
|
- this.restorePlaybackPosition()//读取播放记忆功能
|
|
|
|
|
- }
|
|
|
|
|
- if(PreferencesUtil.getBooleanSync(SettingPage.IS_AUTO_RATATE,true)){
|
|
|
|
|
- this.setAutoOrientation()//自动横屏功能
|
|
|
|
|
- }
|
|
|
|
|
- LogUtils.getInstance().LOGI("setOnPreparedListener-->go");
|
|
|
|
|
- this.duration = this.mIjkMediaPlayer.getDuration()
|
|
|
|
|
-
|
|
|
|
|
- // this.videoUrl = this.globalVideoList[this.curIndex].filePath
|
|
|
|
|
- // let srtPath = this.videoUrl.substring(0,this.videoUrl.lastIndexOf('.'))+'.srt'
|
|
|
|
|
- // this.setSubTitleFile(srtPath)
|
|
|
|
|
-
|
|
|
|
|
- //开启投播组件
|
|
|
|
|
- this.isBgPlayOpen = PreferencesUtil.getBooleanSync(SettingPage.IS_BGPLAY_OPEN,true)
|
|
|
|
|
- LogUtils.getInstance().LOGI("onecold isBgPlayOpen-->go ="+this.isBgPlayOpen);
|
|
|
|
|
- if(this.isBgPlayOpen){
|
|
|
|
|
- this.avSessionController.initAvSession(true);
|
|
|
|
|
- LogUtils.getInstance().LOGI("onecold2 isBgPlayOpen-->go ="+this.isBgPlayOpen);
|
|
|
|
|
- this.avSessionController.setAVMetadata(this.globalVideoList[this.curIndex], this.duration);
|
|
|
|
|
- this.setAvSessionListener();
|
|
|
|
|
- this.updateSessionPlayState(true)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- this.mIjkMediaPlayer.setOnPreparedListener(mOnPreparedListener);
|
|
|
|
|
-
|
|
|
|
|
- let mOnTimedTextListener: OnTimedTextListener = {
|
|
|
|
|
- onTimedText: (text: string) => {
|
|
|
|
|
- LogUtil.debug('onecold text = '+text)
|
|
|
|
|
- this.displaySubtitle(text);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- this.mIjkMediaPlayer.setOnTimedTextListener(mOnTimedTextListener)
|
|
|
|
|
-
|
|
|
|
|
- let mOnCompletionListener: OnCompletionListener = {
|
|
|
|
|
- onCompletion: () => {
|
|
|
|
|
-
|
|
|
|
|
- LogUtils.getInstance().LOGI("OnCompletionListener-->go")
|
|
|
|
|
- if(this.playType == 0){//0:连续播放 1:单片重复播放 2:正常播放
|
|
|
|
|
- this.playNext()
|
|
|
|
|
- }else if(this.playType == 1){//1:单片重复播放
|
|
|
|
|
- this.CONTROL_PlayStatus = PlayStatus.INIT
|
|
|
|
|
- that.startPlayOrResumePlay();
|
|
|
|
|
-
|
|
|
|
|
- }else if(this.playType == 2){//2:正常播放
|
|
|
|
|
-
|
|
|
|
|
- that.showRePlay();
|
|
|
|
|
- that.currentTime = that.stringForTime(this.mIjkMediaPlayer.getDuration());
|
|
|
|
|
- that.progressValue = this.PROGRESS_MAX_VALUE;
|
|
|
|
|
- that.slideEnable = false;
|
|
|
|
|
- that.stop();
|
|
|
|
|
- // ToastUtil.showToast('开始重新播放')
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- this.mIjkMediaPlayer.setOnCompletionListener(mOnCompletionListener);
|
|
|
|
|
-
|
|
|
|
|
- let mOnBufferingUpdateListener: OnBufferingUpdateListener = {
|
|
|
|
|
- onBufferingUpdate: (percent: number) => {
|
|
|
|
|
- LogUtils.getInstance().LOGI("OnBufferingUpdateListener-->go:" + percent);
|
|
|
|
|
- let MediaInfo = this.mIjkMediaPlayer.getMediaInfo()
|
|
|
|
|
- LogUtils.getInstance().LOGI('getMediaInfo---' + MediaInfo);
|
|
|
|
|
- let VideoWidth = this.mIjkMediaPlayer.getVideoWidth()
|
|
|
|
|
- LogUtils.getInstance().LOGI('getVideoWidth---' + VideoWidth);
|
|
|
|
|
-
|
|
|
|
|
- let VideoHeight = this.mIjkMediaPlayer.getVideoHeight()
|
|
|
|
|
- LogUtils.getInstance().LOGI('getVideoHeight---' + VideoHeight);
|
|
|
|
|
-
|
|
|
|
|
- let VideoSarNum = this.mIjkMediaPlayer.getVideoSarNum()
|
|
|
|
|
- LogUtils.getInstance().LOGI('getVideoSarNum---' + VideoSarNum);
|
|
|
|
|
-
|
|
|
|
|
- let VideoSarDen = this.mIjkMediaPlayer.getVideoSarDen()
|
|
|
|
|
- LogUtils.getInstance().LOGI('getVideoSarDen---' + VideoSarDen);
|
|
|
|
|
-
|
|
|
|
|
- let AudioSessionId = this.mIjkMediaPlayer.getAudioSessionId()
|
|
|
|
|
- LogUtils.getInstance().LOGI('getAudioSessionId---' + AudioSessionId);
|
|
|
|
|
-
|
|
|
|
|
- let Looping = this.mIjkMediaPlayer.isLooping()
|
|
|
|
|
- LogUtils.getInstance().LOGI('isLooping---' + Looping);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- this.mIjkMediaPlayer.setOnBufferingUpdateListener(mOnBufferingUpdateListener);
|
|
|
|
|
-
|
|
|
|
|
- let mOnSeekCompleteListener: OnSeekCompleteListener = {
|
|
|
|
|
- onSeekComplete: () => {
|
|
|
|
|
- LogUtils.getInstance().LOGI("OnSeekCompleteListener-->go");
|
|
|
|
|
-
|
|
|
|
|
- that.startPlayOrResumePlay();
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- this.mIjkMediaPlayer.setOnSeekCompleteListener(mOnSeekCompleteListener);
|
|
|
|
|
-
|
|
|
|
|
- let mOnInfoListener: OnInfoListener = {
|
|
|
|
|
- onInfo: (what: number, extra: number) => {
|
|
|
|
|
- LogUtils.getInstance().LOGI("OnInfoListener-->go:" + what + "===" + extra);
|
|
|
|
|
- that.hideLoadIng();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- this.mIjkMediaPlayer.setOnInfoListener(mOnInfoListener);
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- let mOnErrorListener: OnErrorListener = {
|
|
|
|
|
- onError: (what: number, extra: number) => {
|
|
|
|
|
- this.stopProgressTask();
|
|
|
|
|
- LogUtils.getInstance().LOGI("OnErrorListener-->go:" + what + "===" + extra)
|
|
|
|
|
- that.hideLoadIng();
|
|
|
|
|
- prompt.showToast({
|
|
|
|
|
- message: getContext().resourceManager.getStringByNameSync("Honey_the_video_is_playing_errant_The_system_is_wandering")
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- this.mIjkMediaPlayer.setOnErrorListener(mOnErrorListener);
|
|
|
|
|
-
|
|
|
|
|
- this.mIjkMediaPlayer.setMessageListener();
|
|
|
|
|
-
|
|
|
|
|
- this.mIjkMediaPlayer.prepareAsync();
|
|
|
|
|
-
|
|
|
|
|
- this.mIjkMediaPlayer.start();
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- private displaySubtitle(text: string) {
|
|
|
|
|
- this.subtitleText = text;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 拉起picker选择文件管理器
|
|
|
|
|
- async callFilePickerSelectFile(): Promise<void> {
|
|
|
|
|
- try {
|
|
|
|
|
- let DocumentSelectOptions = new picker.DocumentSelectOptions();
|
|
|
|
|
- DocumentSelectOptions.maxSelectNumber = 1
|
|
|
|
|
- DocumentSelectOptions.fileSuffixFilters = CommonConstants.VIDEO_SRT_FORMAT
|
|
|
|
|
- let documentPicker = new picker.DocumentViewPicker();
|
|
|
|
|
- documentPicker.select(DocumentSelectOptions).then((DocumentSelectResult) => {
|
|
|
|
|
- Logger.info(TAG,
|
|
|
|
|
- 'DocumentViewPicker.select successfully, DocumentSelectResult uri: ' + JSON.stringify(DocumentSelectResult));
|
|
|
|
|
-
|
|
|
|
|
- if (DocumentSelectResult !== null && DocumentSelectResult !== undefined) {
|
|
|
|
|
-
|
|
|
|
|
- this.saveVideoDatas(DocumentSelectResult)
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- }).catch((err: BusinessError) => {
|
|
|
|
|
- Logger.error(TAG, 'DocumentViewPicker.select failed with err: ' + JSON.stringify(err));
|
|
|
|
|
- });
|
|
|
|
|
- } catch (err) {
|
|
|
|
|
- Logger.error(TAG, 'DocumentViewPicker failed with err: ' + JSON.stringify(err));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- async saveVideoDatas(uris:string[]){
|
|
|
|
|
- if(ArrayUtil.isEmpty(uris))
|
|
|
|
|
- return
|
|
|
|
|
- for(let i=0;i<uris.length;i++){
|
|
|
|
|
- let filePath = getContext(this).filesDir +'/'+ Utility.getMediaNameByUri(uris[i])
|
|
|
|
|
- Logger.info(TAG,'filePath uri: ' + filePath);
|
|
|
|
|
- let file = fileIo.openSync(uris[i], fileIo.OpenMode.READ_ONLY)
|
|
|
|
|
- let file2 = fileIo.openSync(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE)
|
|
|
|
|
- fileIo.copyFileSync(file.fd, file2.fd)
|
|
|
|
|
- fileIo.closeSync(file);
|
|
|
|
|
- fileIo.closeSync(file2);
|
|
|
|
|
- this.setSubTitleFile(filePath)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- //字幕文件
|
|
|
|
|
- private setSubTitleFile(subtitleUrl:string){
|
|
|
|
|
- LogUtil.debug("onecold subtitleUrl =" + subtitleUrl)
|
|
|
|
|
- // 设置字幕文件
|
|
|
|
|
- if (StrUtil.isNotEmpty(subtitleUrl)) {
|
|
|
|
|
- this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "subtitle", '1');
|
|
|
|
|
- this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "subtitle-file", subtitleUrl);
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public async setAvSessionListener() {
|
|
|
|
|
- if (!this.avSessionController) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- this.avSessionController.getAvSession()?.on('play', this.sessionPlayCallback);
|
|
|
|
|
- this.avSessionController.getAvSession()?.on('pause', this.sessionPauseCallback);
|
|
|
|
|
- this.avSessionController.getAvSession()?.on('stop', this.sessionStopCallback);
|
|
|
|
|
- this.avSessionController.getAvSession()?.on('playNext', this.sessionPlayNextCallback);
|
|
|
|
|
- this.avSessionController.getAvSession()?.on('playPrevious', this.sessionPlayPreviousCallback);
|
|
|
|
|
- this.avSessionController.getAvSession()?.on('fastForward', this.sessionFastForwardCallback);
|
|
|
|
|
- this.avSessionController.getAvSession()?.on('rewind', this.sessionRewindCallback);
|
|
|
|
|
- this.avSessionController.getAvSession()?.on('seek', this.sessionSeekCallback);
|
|
|
|
|
- this.avSessionController.getAvSession()?.on('outputDeviceChange', this.sessionOutputDeviceChange)
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- private sessionOutputDeviceChange = async (connectState: avSession.ConnectionState,
|
|
|
|
|
- device: avSession.OutputDeviceInfo) => {
|
|
|
|
|
- let currentDevice: avSession.DeviceInfo = device?.devices?.[0];
|
|
|
|
|
- if (currentDevice.castCategory === avSession.AVCastCategory.CATEGORY_REMOTE &&
|
|
|
|
|
- connectState === avSession.ConnectionState.STATE_CONNECTED) {
|
|
|
|
|
-
|
|
|
|
|
- await this.startCasting();
|
|
|
|
|
-
|
|
|
|
|
- } else if ((currentDevice.castCategory === avSession.AVCastCategory.CATEGORY_REMOTE &&
|
|
|
|
|
- connectState === avSession.ConnectionState.STATE_DISCONNECTED) ||
|
|
|
|
|
- (currentDevice.castCategory === avSession.AVCastCategory.CATEGORY_LOCAL &&
|
|
|
|
|
- connectState === avSession.ConnectionState.STATE_CONNECTED)) {
|
|
|
|
|
- if (device) {
|
|
|
|
|
- this.endCasting();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- private async startCasting() {
|
|
|
|
|
- this.castController = await this.avSessionController.getAvSession()?.getAVCastController();
|
|
|
|
|
- this.setPlaybackStateChangeListener();
|
|
|
|
|
- this.pause();
|
|
|
|
|
- this.initQueueItem();
|
|
|
|
|
- this.prepare();
|
|
|
|
|
- let refToIsCasting: AbstractProperty<boolean> | undefined = AppStorage.ref('isCasting');
|
|
|
|
|
- refToIsCasting?.set(true);
|
|
|
|
|
- this.castSeek = true;
|
|
|
|
|
- this.isCastPlaying = true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- async changeCasting() {
|
|
|
|
|
- this.castController = await this.avSessionController.getAvSession()?.getAVCastController();
|
|
|
|
|
- this.initQueueItem();
|
|
|
|
|
- this.prepare();
|
|
|
|
|
- this.setPlaybackStateChangeListener();
|
|
|
|
|
- this.isCastPlaying = true;
|
|
|
|
|
- this.castSeek = true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public endCasting() {
|
|
|
|
|
- this.avSessionController.getAvSession()?.stopCasting();
|
|
|
|
|
- this.stopCast();
|
|
|
|
|
- this.isCastPlaying = false;
|
|
|
|
|
- let refToIsCasting: AbstractProperty<boolean> | undefined = AppStorage.ref('isCasting');
|
|
|
|
|
- refToIsCasting?.set(false);
|
|
|
|
|
- this.pause();
|
|
|
|
|
- this.setIsPlaying(false);
|
|
|
|
|
- // if (this.curIndex === this.curSource.index) {
|
|
|
|
|
- // this.play
|
|
|
|
|
- // this.seek(this.currentTime * 1000);
|
|
|
|
|
- // this.setIsPlaying(true);
|
|
|
|
|
- // } else {
|
|
|
|
|
- // this.pauseVideo();
|
|
|
|
|
- // this.setIsPlaying(false);
|
|
|
|
|
- // }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public setIsPlaying(isPlayer: boolean) {
|
|
|
|
|
- this.isPlaying = isPlayer;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private setPlaybackStateChangeListener(): void {
|
|
|
|
|
- this.castController?.on('playbackStateChange', 'all', this.playbackStateChangeListener);
|
|
|
|
|
- this.castController?.on('endOfStream', this.reloadCasting);
|
|
|
|
|
- this.castController?.on('playNext', this.playNextCallback);
|
|
|
|
|
- this.castController?.on('playPrevious', this.playPreviousCallback);
|
|
|
|
|
- }
|
|
|
|
|
- private updateSessionPlayState(isPlay: boolean): void {
|
|
|
|
|
- if(!this.isBgPlayOpen)
|
|
|
|
|
- return
|
|
|
|
|
- Logger.info(TAG, `updateIsPlay isPlay: ${isPlay}`);
|
|
|
|
|
- this.setAVSessionPlayState({
|
|
|
|
|
- state: isPlay ? avSession.PlaybackState.PLAYBACK_STATE_PLAY : avSession.PlaybackState.PLAYBACK_STATE_PAUSE,
|
|
|
|
|
- position: {
|
|
|
|
|
- elapsedTime: this.mIjkMediaPlayer.getCurrentPosition(),
|
|
|
|
|
- updateTime: new Date().getTime()
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- private setAVSessionPlayState(playbackState: avSession.AVPlaybackState): void {
|
|
|
|
|
- this.avSessionController.setAvSessionPlayState(playbackState)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private positionChange(position: number) {
|
|
|
|
|
- this.currentTime2 = position / 1000;
|
|
|
|
|
- this.currentStringTime = secondToTime(Math.floor(position / 1000));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private playDurationChange(duration: number) {
|
|
|
|
|
- this.duration = duration;
|
|
|
|
|
- this.durationTime = Math.floor(this.duration / 1000);
|
|
|
|
|
- this.durationStringTime = secondToTime((this.durationTime));
|
|
|
|
|
- }
|
|
|
|
|
- private playbackStateChangeListener = (playbackState: avSession.AVPlaybackState) => {
|
|
|
|
|
- const duration = playbackState?.extras?.duration;
|
|
|
|
|
- if (typeof duration === 'number') {
|
|
|
|
|
- this.playDurationChange(duration as number);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (typeof playbackState?.position?.elapsedTime !== 'undefined') {
|
|
|
|
|
- this.positionChange(playbackState?.position?.elapsedTime);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (playbackState.state === CommonConstants2.PLAYBACK_STATE_PAUSE ||
|
|
|
|
|
- playbackState.state === CommonConstants2.PLAYBACK_STATE_STOP ||
|
|
|
|
|
- playbackState.state === CommonConstants2.PLAYBACK_STATE_PREPARE ||
|
|
|
|
|
- playbackState.state === CommonConstants2.PLAYBACK_STATE_INITIAL) {
|
|
|
|
|
- this.isCastPlaying = false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (playbackState.state === CommonConstants2.PLAYBACK_STATE_PLAY) {
|
|
|
|
|
- this.isCastPlaying = true;
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- private reloadCasting = async () => {
|
|
|
|
|
-
|
|
|
|
|
- let item = this.globalVideoList[this.curIndex];
|
|
|
|
|
- // description.startPosition = 0;
|
|
|
|
|
- this.castItem = {
|
|
|
|
|
- itemId: this.curIndex,
|
|
|
|
|
- description: ({
|
|
|
|
|
- assetId: item.filePath,
|
|
|
|
|
- title: item.name,
|
|
|
|
|
- artist: '',
|
|
|
|
|
- // 网络资源投播,设置mediaUri; 本地资源投播,将本地文件打开后,相关的文件描述符设置到fdSrc
|
|
|
|
|
- mediaUri: item.filePath,
|
|
|
|
|
- // 该字段大写,音频'AUDIO',视频'VIDEO'
|
|
|
|
|
- mediaType: 'VIDEO',
|
|
|
|
|
- mediaSize: item.videoSize,
|
|
|
|
|
- //startPosition为投播当前进度,设置该字段可将本机播放进度同步到远端
|
|
|
|
|
- startPosition: this.mIjkMediaPlayer.getCurrentPosition(),
|
|
|
|
|
- // 投播资源播放时长,设置该字段可将本机播放时长同步到远端显示
|
|
|
|
|
- duration: this.duration,
|
|
|
|
|
- // albumCoverUri: 'https://www.example.jpeg',
|
|
|
|
|
- // albumTitle: '《ExampleAlbum》',
|
|
|
|
|
- appName: '看片神器',
|
|
|
|
|
- // DRM资源,需要配置支持的DRM类型, 以chinaDRM为例。
|
|
|
|
|
- // drmScheme: '3d5e6d35-9b9a-41e8-b843-dd3c6e72c42c',
|
|
|
|
|
- } as GeneratedObjectLiteralInterface_1)
|
|
|
|
|
- };
|
|
|
|
|
- this.prepare();
|
|
|
|
|
- this.isCastPlaying = true;
|
|
|
|
|
-
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- public playNextCallback = (): void => {
|
|
|
|
|
- this.playNext()
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- public playPreviousCallback = (): void => {
|
|
|
|
|
- this.playPrevious()
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- async prepare() {
|
|
|
|
|
- await this.castController?.prepare(this.castItem);
|
|
|
|
|
- await this.castController?.start(this.castItem);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public initQueueItem() {
|
|
|
|
|
- let item = this.globalVideoList[this.curIndex];
|
|
|
|
|
- // let description = this.urlVideoList[this.curIndex];
|
|
|
|
|
- let time = this.currentTime;
|
|
|
|
|
- // description.startPosition = time * 1000;
|
|
|
|
|
- this.castItem = {
|
|
|
|
|
- itemId: this.curIndex,
|
|
|
|
|
- description: {
|
|
|
|
|
- assetId: item.filePath,
|
|
|
|
|
- title: item.name,
|
|
|
|
|
- artist: '',
|
|
|
|
|
- // 网络资源投播,设置mediaUri; 本地资源投播,将本地文件打开后,相关的文件描述符设置到fdSrc
|
|
|
|
|
- mediaUri: item.filePath,
|
|
|
|
|
- // 该字段大写,音频'AUDIO',视频'VIDEO'
|
|
|
|
|
- mediaType: 'VIDEO',
|
|
|
|
|
- mediaSize: item.videoSize,
|
|
|
|
|
- //startPosition为投播当前进度,设置该字段可将本机播放进度同步到远端
|
|
|
|
|
- startPosition: this.mIjkMediaPlayer.getCurrentPosition(),
|
|
|
|
|
- // 投播资源播放时长,设置该字段可将本机播放时长同步到远端显示
|
|
|
|
|
- duration: this.duration,
|
|
|
|
|
- // albumCoverUri: 'https://www.example.jpeg',
|
|
|
|
|
- // albumTitle: '《ExampleAlbum》',
|
|
|
|
|
- appName: '看片神器',
|
|
|
|
|
- // DRM资源,需要配置支持的DRM类型, 以chinaDRM为例。
|
|
|
|
|
- // drmScheme: '3d5e6d35-9b9a-41e8-b843-dd3c6e72c42c',
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- async stopCast() {
|
|
|
|
|
- try {
|
|
|
|
|
- this.castController?.off('playbackStateChange');
|
|
|
|
|
- this.castController?.off('endOfStream');
|
|
|
|
|
- this.castController?.off('playNext');
|
|
|
|
|
- this.castController?.off('playPrevious');
|
|
|
|
|
- this.castController?.off('error');
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- hilog.info(0x0000, TAG, `Failed to setAVCastController. code: ${error.code}, message: ${error.message}`);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private sessionPlayCallback = (): void => {
|
|
|
|
|
- this.playOrPause()
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- private sessionPauseCallback = (): void => {
|
|
|
|
|
- this.playOrPause()
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- private playOrPause(){
|
|
|
|
|
- if (!this.debounce()) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- if (this.CONTROL_PlayStatus === PlayStatus.PLAY) {
|
|
|
|
|
- this.pause();
|
|
|
|
|
- } else {
|
|
|
|
|
- this.startPlayOrResumePlay();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private sessionPlayNextCallback = (): void => {
|
|
|
|
|
- this.playNext()
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- private sessionPlayPreviousCallback = (): void => {
|
|
|
|
|
- this.playPrevious()
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- private sessionStopCallback = (): void => {
|
|
|
|
|
- this.stop()
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- private sessionFastForwardCallback = (time?: number) => {
|
|
|
|
|
- if (!time) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- if (this.mIjkMediaPlayer!=null) {
|
|
|
|
|
- const curPosition = this.mIjkMediaPlayer.getCurrentPosition()
|
|
|
|
|
- let seeTime = curPosition + time* 1000;
|
|
|
|
|
- // 限制 seekValue 在合法范围内
|
|
|
|
|
- if (seeTime < 0) {
|
|
|
|
|
- seeTime = 0;
|
|
|
|
|
- } else if (seeTime > this.duration) {
|
|
|
|
|
- seeTime = this.duration;
|
|
|
|
|
- }
|
|
|
|
|
- Logger.info('onecold seeTime= ' + seeTime)
|
|
|
|
|
- this.setSeekToActionProgress(seeTime)
|
|
|
|
|
- this.seekTo(seeTime +"")
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- private sessionRewindCallback = (time?: number) => {
|
|
|
|
|
- if (!time) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- if (this.mIjkMediaPlayer!=null) {
|
|
|
|
|
- const curPosition = this.mIjkMediaPlayer.getCurrentPosition()
|
|
|
|
|
- let seeTime = curPosition - time* 1000;
|
|
|
|
|
- // 限制 seekValue 在合法范围内
|
|
|
|
|
- if (seeTime < 0) {
|
|
|
|
|
- seeTime = 0;
|
|
|
|
|
- } else if (seeTime > this.duration) {
|
|
|
|
|
- seeTime = this.duration;
|
|
|
|
|
- }
|
|
|
|
|
- Logger.info('onecold seeTime= ' + seeTime)
|
|
|
|
|
- this.setSeekToActionProgress(seeTime)
|
|
|
|
|
- this.seekTo(seeTime +"")
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- private sessionSeekCallback = (seekTime: number) => {
|
|
|
|
|
- if (this.mIjkMediaPlayer!=null) {
|
|
|
|
|
- const curPosition = this.mIjkMediaPlayer.getCurrentPosition()
|
|
|
|
|
- this.seekTo(seekTime+"")
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- private async getFileSize(filePath: string): Promise<number> {
|
|
|
|
|
- try {
|
|
|
|
|
- const stat = await fs.stat(filePath);
|
|
|
|
|
- return stat.size;
|
|
|
|
|
- } catch (err) {
|
|
|
|
|
- console.error('Failed to get file size: ' + err.message);
|
|
|
|
|
- return 0;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- //自动横屏功能
|
|
|
|
|
- private setAutoOrientation(){
|
|
|
|
|
- let VideoWidth = this.mIjkMediaPlayer.getVideoWidth();
|
|
|
|
|
- let VideoHeight = this.mIjkMediaPlayer.getVideoHeight();
|
|
|
|
|
- if(VideoHeight < VideoWidth) { //横屏屏视频
|
|
|
|
|
- this.setOrientation(window.Orientation.USER_ROTATION_LANDSCAPE);
|
|
|
|
|
- this.isLandscape = true;
|
|
|
|
|
- }else{
|
|
|
|
|
- this.setOrientation(window.Orientation.USER_ROTATION_PORTRAIT);
|
|
|
|
|
- this.isLandscape = false;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private async getVideoSize() {
|
|
|
|
|
- if (this.mIjkMediaPlayer==null)
|
|
|
|
|
- return
|
|
|
|
|
- let VideoWidth = this.mIjkMediaPlayer.getVideoWidth();
|
|
|
|
|
- LogUtils.getInstance().LOGI("getVideoWidth---" + VideoWidth);
|
|
|
|
|
-
|
|
|
|
|
- let VideoHeight = this.mIjkMediaPlayer.getVideoHeight();
|
|
|
|
|
- LogUtils.getInstance().LOGI("getVideoHeight---" + VideoHeight);
|
|
|
|
|
- let scale = VideoHeight/VideoWidth//视频的长高比例
|
|
|
|
|
-
|
|
|
|
|
- let screenScale = this.screenHeight/ this.screenWidth//屏幕的长高比例
|
|
|
|
|
- let screenScale2 = (this.screenHeight-this.statusBarHeight)/ this.screenWidth//屏幕的长高比例:竖屏模式下用这个screenScale2 有去掉状态栏高度
|
|
|
|
|
- LogUtils.getInstance().LOGI("screenScale---" + screenScale);
|
|
|
|
|
-
|
|
|
|
|
- if(VideoHeight > VideoWidth){//竖屏视频
|
|
|
|
|
-
|
|
|
|
|
- if(this.isLandscape){
|
|
|
|
|
- this.videoWidth = (1/(screenScale*scale))*100+'%';
|
|
|
|
|
- // this.videoWidth = '26.5%';
|
|
|
|
|
- this.videoHeight = CommonConstants.FULL_PERCENT;;
|
|
|
|
|
- }else{
|
|
|
|
|
- this.videoWidth = CommonConstants.FULL_PERCENT;
|
|
|
|
|
- this.videoHeight = CommonConstants.FULL_PERCENT;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- }else{//横屏视频
|
|
|
|
|
- if(this.isLandscape){
|
|
|
|
|
- if(this.isYesFull){
|
|
|
|
|
- this.videoWidth = '100%';
|
|
|
|
|
- this.videoHeight = '100%';
|
|
|
|
|
- }else{
|
|
|
|
|
- // this.videoWidth = '85.8%';
|
|
|
|
|
- this.videoWidth = (1/(screenScale*scale))*100+'%';
|
|
|
|
|
- this.videoHeight = '100%';
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- }else{
|
|
|
|
|
- this.videoWidth = '100%';
|
|
|
|
|
- // this.videoHeight = '27.5%';
|
|
|
|
|
- this.videoHeight = (scale/screenScale2)*100+'%';
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- private pause() {
|
|
|
|
|
- if (this.mIjkMediaPlayer.isPlaying()) {
|
|
|
|
|
- this.savePlaybackPosition();
|
|
|
|
|
- this.mIjkMediaPlayer.pause();
|
|
|
|
|
- this.setProgress();
|
|
|
|
|
- this.mDestroyPage = true;
|
|
|
|
|
- this.CONTROL_PlayStatus = PlayStatus.PAUSE;
|
|
|
|
|
- this.updateSessionPlayState(false)
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private stop() {
|
|
|
|
|
- this.savePlaybackPosition();
|
|
|
|
|
- this.CONTROL_PlayStatus = PlayStatus.INIT;
|
|
|
|
|
- this.mIjkMediaPlayer.stop();
|
|
|
|
|
- this.mIjkMediaPlayer.release();
|
|
|
|
|
- this.stopProgressTask();
|
|
|
|
|
- this.updateSessionPlayState(false)
|
|
|
|
|
- this.watchStatus();
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- //保持记忆播放功能
|
|
|
|
|
- private savePlaybackPosition() {
|
|
|
|
|
- if (this.mIjkMediaPlayer!=null) {
|
|
|
|
|
- const position = this.mIjkMediaPlayer.getCurrentPosition();
|
|
|
|
|
- // ToastUtil.showToast('保存记忆播放 = ' + position)
|
|
|
|
|
- const duration = this.mIjkMediaPlayer.getDuration();
|
|
|
|
|
- const threshold = 5000; // 阈值,单位为毫秒(这里设为5秒)
|
|
|
|
|
-
|
|
|
|
|
- // 如果播放位置接近视频末尾,则保存 position 为 0
|
|
|
|
|
- const playbackPosition = (duration - position < threshold) ? 0 : position;
|
|
|
|
|
- PreferencesUtil.putSync(this.videoUrl, playbackPosition);
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- //获取记忆播放功能
|
|
|
|
|
- private restorePlaybackPosition() {
|
|
|
|
|
- const position:number = PreferencesUtil.getNumberSync(this.videoUrl, 0);
|
|
|
|
|
- // ToastUtil.showToast('position = ' + position)
|
|
|
|
|
- if (this.mIjkMediaPlayer!=null && position > 0) {
|
|
|
|
|
- // ToastUtil.showToast('seekTo = ' + position)
|
|
|
|
|
- this.seekTo(position +"");
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private seekTo(value: string) {
|
|
|
|
|
- // this.stopProgressTask();
|
|
|
|
|
- this.mIjkMediaPlayer.seekTo(value);
|
|
|
|
|
- // this.startPlayOrResumePlay()
|
|
|
|
|
- // 在这里恢复计时器状态
|
|
|
|
|
- this.setProgress()
|
|
|
|
|
- // this.startProgressTask();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- //下一个
|
|
|
|
|
- private playNext() {
|
|
|
|
|
- if (!this.debounce()) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- if(ArrayUtil.isNotEmpty(this.globalVideoList)){
|
|
|
|
|
- if (this.curIndex == this.globalVideoList.length - 1) {
|
|
|
|
|
- this.curIndex = 0;
|
|
|
|
|
- } else {
|
|
|
|
|
- this.curIndex++;
|
|
|
|
|
- }
|
|
|
|
|
- this.CONTROL_PlayStatus = PlayStatus.INIT;
|
|
|
|
|
- this.stop();
|
|
|
|
|
- this.videoUrl = this.globalVideoList[this.curIndex].filePath;
|
|
|
|
|
- this.name = this.globalVideoList[this.curIndex].name
|
|
|
|
|
- this.startPlayOrResumePlay()
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private playIndex(index:number) {
|
|
|
|
|
- if (!this.debounce()) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- if(ArrayUtil.isNotEmpty(this.globalVideoList)){
|
|
|
|
|
-
|
|
|
|
|
- this.CONTROL_PlayStatus = PlayStatus.INIT;
|
|
|
|
|
- this.stop();
|
|
|
|
|
- this.videoUrl = this.globalVideoList[index].filePath;
|
|
|
|
|
- this.name = this.globalVideoList[index].name
|
|
|
|
|
- this.curIndex = index;
|
|
|
|
|
- this.startPlayOrResumePlay()
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- //上一个
|
|
|
|
|
- private playPrevious() {
|
|
|
|
|
- if (!this.debounce()) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (this.curIndex == 0) {
|
|
|
|
|
- this.curIndex = this.globalVideoList.length-1;
|
|
|
|
|
- } else {
|
|
|
|
|
- this.curIndex--;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- this.CONTROL_PlayStatus = PlayStatus.INIT;
|
|
|
|
|
- this.stop();
|
|
|
|
|
- this.videoUrl = this.globalVideoList[this.curIndex].filePath;
|
|
|
|
|
- this.name = this.globalVideoList[this.curIndex].name
|
|
|
|
|
- this.startPlayOrResumePlay()
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- debounce() {
|
|
|
|
|
- const delay = 600;
|
|
|
|
|
- let cur = new Date().getTime();
|
|
|
|
|
- if (cur - this.last > delay) {
|
|
|
|
|
- this.last = cur;
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * Sets whether the screen is a constant based on the playback status.
|
|
|
|
|
- */
|
|
|
|
|
- watchStatus() {
|
|
|
|
|
- // let windowClass = GlobalContext.getContext().getObject('windowClass') as window.Window;
|
|
|
|
|
- if (this.CONTROL_PlayStatus === PlayStatus.PLAY) {
|
|
|
|
|
- this.windowClass.setWindowKeepScreenOn(true);
|
|
|
|
|
- } else {
|
|
|
|
|
- this.windowClass.setWindowKeepScreenOn(false);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- /**
|
|
|
|
|
- * Volume gesture method onActionStart.
|
|
|
|
|
- *
|
|
|
|
|
- * @param event Gesture event.
|
|
|
|
|
- */
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- onVolumeActionStart(event?: GestureEvent) {
|
|
|
|
|
- if(this.isVideoLock)
|
|
|
|
|
- return
|
|
|
|
|
- if (!event) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- this.positionY = event.offsetY;
|
|
|
|
|
- }
|
|
|
|
|
- /**
|
|
|
|
|
- * Gesture method onActionUpdate.
|
|
|
|
|
- *
|
|
|
|
|
- * @param event Gesture event.
|
|
|
|
|
- */
|
|
|
|
|
- onVolumeActionUpdate(event?: GestureEvent) {
|
|
|
|
|
- if(this.isVideoLock)
|
|
|
|
|
- return
|
|
|
|
|
- if (!event) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- if (this.mIjkMediaPlayer === null) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (!this.brightShow && !this.seekToShow ) {
|
|
|
|
|
- this.volumeShow = true;
|
|
|
|
|
- let changeVolume =(this.positionY - event.offsetY) / this.screenHeight;
|
|
|
|
|
- let volume: number = this.volume;
|
|
|
|
|
- let currentVolume = volume + changeVolume;
|
|
|
|
|
- let volumeMinFlag = currentVolume <= PlayConstants.MIN_VALUE;
|
|
|
|
|
- let volumeMaxFlag = currentVolume > PlayConstants.MAX_VALUE;
|
|
|
|
|
- this.volume = volumeMinFlag ? PlayConstants.MIN_VALUE :
|
|
|
|
|
- (volumeMaxFlag ? PlayConstants.MAX_VALUE : currentVolume);
|
|
|
|
|
- // Logger.info('onecold this.volume = ' + this.volume)
|
|
|
|
|
- this.mIjkMediaPlayer.setVolume(this.volume.toString(),this.volume.toString());
|
|
|
|
|
- this.positionY = event.offsetY;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private lastOffset: number = 0
|
|
|
|
|
- private accumulatedOffset: number = 0;//手势拖动的累计偏移量
|
|
|
|
|
- private initialPosition: number = 0;//初始拖动播放位置
|
|
|
|
|
- private DRAG_SPEED_FACTOR: number = 0.01; // 控制拖动速度的比例
|
|
|
|
|
- //手势拖动快进和快退
|
|
|
|
|
- onSeekToActionStart(event?: GestureEvent) {
|
|
|
|
|
- if(this.isVideoLock)
|
|
|
|
|
- return
|
|
|
|
|
- if (!event) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- // 记录手势开始时的播放位置
|
|
|
|
|
- this.initialPosition = this.mIjkMediaPlayer.getCurrentPosition();
|
|
|
|
|
- this.lastOffset = event.offsetX;
|
|
|
|
|
- this.accumulatedOffset = 0; // 重置累计偏移量
|
|
|
|
|
- // 获取视频总时长
|
|
|
|
|
- const duration = this.mIjkMediaPlayer.getDuration();
|
|
|
|
|
- if (duration <= 5 * 60 * 1000) { // 小于5分钟
|
|
|
|
|
- this.DRAG_SPEED_FACTOR = 0.2;
|
|
|
|
|
- } else if (duration <= 20 * 60 * 1000) { // 大于5分钟小于20分钟
|
|
|
|
|
- this.DRAG_SPEED_FACTOR = 0.1;
|
|
|
|
|
- } else if (duration <= 30 * 60 * 1000) { // 大于20分钟小于30分钟
|
|
|
|
|
- this.DRAG_SPEED_FACTOR = 0.08;
|
|
|
|
|
- } else if (duration <= 40 * 60 * 1000) { // 大于30分钟小于40分钟
|
|
|
|
|
- this.DRAG_SPEED_FACTOR = 0.04;
|
|
|
|
|
- } else if (duration <= 90 * 60 * 1000) { // 大于40分钟小于90分钟
|
|
|
|
|
- this.DRAG_SPEED_FACTOR = 0.012;
|
|
|
|
|
- } else { // 大于90分钟
|
|
|
|
|
- this.DRAG_SPEED_FACTOR = 0.009;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- onSeekToActionUpdate(event?: GestureEvent) {
|
|
|
|
|
- if(this.isVideoLock)
|
|
|
|
|
- return
|
|
|
|
|
- if (!event || this.mIjkMediaPlayer === null) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 当亮度和音量控制未显示时,进行快进/快退操作
|
|
|
|
|
- if (!this.brightShow && !this.volumeShow) {
|
|
|
|
|
- this.seekToShow = true;
|
|
|
|
|
-
|
|
|
|
|
- // 获取视频总时长
|
|
|
|
|
- const duration = this.mIjkMediaPlayer.getDuration();
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- // 计算新的偏移量
|
|
|
|
|
- const newOffsetX = event.offsetX - this.lastOffset;
|
|
|
|
|
- this.lastOffset = event.offsetX;
|
|
|
|
|
-
|
|
|
|
|
- // 累积偏移量
|
|
|
|
|
- this.accumulatedOffset += newOffsetX;
|
|
|
|
|
-
|
|
|
|
|
- // 计算新的播放位置
|
|
|
|
|
- const offsetTime = this.accumulatedOffset * this.DRAG_SPEED_FACTOR * (duration / this.PROGRESS_MAX_VALUE);
|
|
|
|
|
- this.seekValue = this.initialPosition + offsetTime;
|
|
|
|
|
-
|
|
|
|
|
- // 限制 seekValue 在合法范围内
|
|
|
|
|
- if (this.seekValue < 0) {
|
|
|
|
|
- this.seekValue = 0;
|
|
|
|
|
- } else if (this.seekValue > duration) {
|
|
|
|
|
- this.seekValue = duration;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 设置快进/快退进度
|
|
|
|
|
- this.setSeekToActionProgress(this.seekValue);
|
|
|
|
|
-
|
|
|
|
|
- // 更新标志
|
|
|
|
|
- this.isSeekTo = true;
|
|
|
|
|
- this.mDestroyPage = false;
|
|
|
|
|
-
|
|
|
|
|
- LogUtils.getInstance().LOGI("slider-->seekValue: " + this.seekValue);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * Gesture method onActionEnd.
|
|
|
|
|
- */
|
|
|
|
|
- onSeekToActionEnd(event?: GestureEvent) {
|
|
|
|
|
- if(this.isVideoLock)
|
|
|
|
|
- return
|
|
|
|
|
-
|
|
|
|
|
- this.showLoadIng();
|
|
|
|
|
- LogUtils.getInstance().LOGI("slider-->seekValue end:" + this.seekValue);
|
|
|
|
|
- this.seekTo(this.seekValue + "");
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- this.isSeekTo = false;
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- this.volumeShow = false;
|
|
|
|
|
- this.brightShow = false;
|
|
|
|
|
- this.seekToShow = false;
|
|
|
|
|
- this.positionX = PlayConstants.POSITION_X;
|
|
|
|
|
- this.positionY = PlayConstants.POSITION_Y;
|
|
|
|
|
- }, PlayConstants.DISAPPEAR_TIME);
|
|
|
|
|
- }
|
|
|
|
|
- /**
|
|
|
|
|
- * Gesture method onActionUpdate.
|
|
|
|
|
- *
|
|
|
|
|
- * @param event Gesture event.手势拖动设置快进和后退
|
|
|
|
|
- */
|
|
|
|
|
- private setSeekToActionProgress(position:number) {
|
|
|
|
|
- // let position = this.mIjkMediaPlayer.getCurrentPosition();
|
|
|
|
|
- let duration = this.mIjkMediaPlayer.getDuration();
|
|
|
|
|
- let pos = 0;
|
|
|
|
|
- if (duration > 0) {
|
|
|
|
|
- this.slideEnable = true;
|
|
|
|
|
- let curPercent = position / duration;
|
|
|
|
|
- pos = curPercent * 100;
|
|
|
|
|
- if (pos > this.PROGRESS_MAX_VALUE) {
|
|
|
|
|
- this.progressValue = this.PROGRESS_MAX_VALUE
|
|
|
|
|
- } else {
|
|
|
|
|
- this.progressValue = pos;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- // LogUtils.getInstance()
|
|
|
|
|
- // .LOGI("setProgress position:" + position + ",duration:" + duration + ",progressValue:" + pos);
|
|
|
|
|
- this.totalTime = this.stringForTime(duration);
|
|
|
|
|
- if (position > duration) {
|
|
|
|
|
- position = duration;
|
|
|
|
|
- }
|
|
|
|
|
- this.isCurrentTime = true;
|
|
|
|
|
- this.currentTime = this.stringForTime(position);
|
|
|
|
|
- this.isCurrentTime = false
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private initialBright: number = 0; // 手势开始时的初始亮度
|
|
|
|
|
- /**
|
|
|
|
|
- * Bright gesture method onActionStart.
|
|
|
|
|
- *
|
|
|
|
|
- * @param event Gesture event.
|
|
|
|
|
- */
|
|
|
|
|
- onBrightActionStart(event?: GestureEvent) {
|
|
|
|
|
- if(this.isVideoLock)
|
|
|
|
|
- return
|
|
|
|
|
- if (!event) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- this.initialBright = this.bright; // 记录手势开始时的亮度
|
|
|
|
|
- this.positionY = event.offsetY;
|
|
|
|
|
- }
|
|
|
|
|
- /**
|
|
|
|
|
- * Gesture method onActionUpdate.
|
|
|
|
|
- *
|
|
|
|
|
- * @param event Gesture event.手势拖动设置屏幕亮度值
|
|
|
|
|
- */
|
|
|
|
|
- onBrightActionUpdate(event?: GestureEvent) {
|
|
|
|
|
- if(this.isVideoLock)
|
|
|
|
|
- return
|
|
|
|
|
- if (!event) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- if (!this.seekToShow && !this.volumeShow) {
|
|
|
|
|
- // this.brightShow = true;
|
|
|
|
|
- // // Logger.info('onecold onBrightActionUpdate screenWidth = ' + this.screenWidth)
|
|
|
|
|
- // // Logger.info(' onecold onBrightActionUpdate screenHeight = ' + this.screenHeight)
|
|
|
|
|
- // let changeBright = (this.positionY - event.offsetY) / this.screenHeight;
|
|
|
|
|
- // let bright: number = this.bright;
|
|
|
|
|
- // let currentBright = bright + changeBright;
|
|
|
|
|
- // let brightMinFlag = currentBright <= PlayConstants.MIN_VALUE;
|
|
|
|
|
- // let brightMaxFlag = currentBright > PlayConstants.MAX_VALUE;
|
|
|
|
|
- // this.bright = brightMinFlag ? PlayConstants.MIN_VALUE :
|
|
|
|
|
- // (brightMaxFlag ? PlayConstants.MAX_VALUE : currentBright);
|
|
|
|
|
- // // Logger.info('onecold this.bright = ' + this.bright)
|
|
|
|
|
- // this.setBright()
|
|
|
|
|
- // this.positionY = event.offsetY;
|
|
|
|
|
-
|
|
|
|
|
- this.brightShow = true;
|
|
|
|
|
-
|
|
|
|
|
- // 计算亮度变化
|
|
|
|
|
- let changeBright = (this.positionY - event.offsetY) / this.screenHeight;
|
|
|
|
|
- let currentBright = this.initialBright + changeBright;
|
|
|
|
|
-
|
|
|
|
|
- // 确保亮度在允许的范围内
|
|
|
|
|
- if (currentBright < PlayConstants.MIN_VALUE) {
|
|
|
|
|
- currentBright = PlayConstants.MIN_VALUE;
|
|
|
|
|
- } else if (currentBright > PlayConstants.MAX_VALUE) {
|
|
|
|
|
- currentBright = PlayConstants.MAX_VALUE;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 更新亮度值
|
|
|
|
|
- this.bright = currentBright;
|
|
|
|
|
- this.setBright();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- /**
|
|
|
|
|
- * Setting the brightness.设置屏幕亮度值
|
|
|
|
|
- */
|
|
|
|
|
- setBright() {
|
|
|
|
|
-
|
|
|
|
|
- // this.windowClass.setWindowBrightness(this.bright);
|
|
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- let promise = this.windowClass.setWindowBrightness(this.bright);
|
|
|
|
|
- promise.then(() => {
|
|
|
|
|
- console.info('Succeeded in setting the brightness.');
|
|
|
|
|
- }).catch((err: BusinessError) => {
|
|
|
|
|
- console.error('Failed to set the brightness. Cause: ' + JSON.stringify(err));
|
|
|
|
|
- });
|
|
|
|
|
- } catch (exception) {
|
|
|
|
|
- console.error('Failed to set the brightness. Cause: ' + JSON.stringify(exception));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * Gesture method onActionEnd.
|
|
|
|
|
- */
|
|
|
|
|
- onActionEnd() {
|
|
|
|
|
- if(this.isVideoLock)
|
|
|
|
|
- return
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- this.volumeShow = false;
|
|
|
|
|
- this.brightShow = false;
|
|
|
|
|
- this.seekToShow = false;
|
|
|
|
|
- this.positionX = PlayConstants.POSITION_X;
|
|
|
|
|
- this.positionY = PlayConstants.POSITION_Y;
|
|
|
|
|
- }, PlayConstants.DISAPPEAR_TIME);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-//视频气泡窗口的布局
|
|
|
|
|
-@Builder
|
|
|
|
|
-function customPopupBuilder(dataBu: BubbleBean) {
|
|
|
|
|
- List() {
|
|
|
|
|
- ForEach(dataBu.data, (item: string, index: number) => {
|
|
|
|
|
- ListItem() {
|
|
|
|
|
- Row(){
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- Text(item).padding({ top:12,bottom:12,right:10 ,left:10}).textAlign(TextAlign.Start).width("100%")
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- }.onClick(() => {
|
|
|
|
|
- dataBu.onItemClick?.(index)
|
|
|
|
|
- })
|
|
|
|
|
- })
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .width(72)
|
|
|
|
|
- .divider({
|
|
|
|
|
- strokeWidth:1,
|
|
|
|
|
- color:"#22FFFFFF"
|
|
|
|
|
- })
|
|
|
|
|
-}
|
|
|