HarmonyOS 调用pipController.startPiP()失败,报文1300013,错误码上说【不要在非全屏窗口下启动画中画】是什么意思?

let pipController: PiPWindow.PiPController | undefined = undefined;
// 开发者应使用该mXComponentController初始化XComponent: XComponent( {id: 'video', type: 'surface', controller: mXComponentController} ),
// 保证XComponent的内容可以被迁移到画中画窗口。
let mXComponentController: XComponentController = new XComponentController();
let config: PiPWindow.PiPConfiguration = {
  context: getContext(this),
  componentController: mXComponentController,
  navigationId: this.navId,
  templateType: PiPWindow.PiPTemplateType.VIDEO_PLAY,
  contentWidth: this.videoSize.width as number,
  contentHeight: this.videoSize.height as number,
  controlGroups: [PiPWindow.VideoPlayControlGroup.FAST_FORWARD_BACKWARD],
  // customUIController: nodeController, // 可选,如果需要在画中画显示内容上方展示自定义UI,可设置该参数。
};

let promise: Promise<PiPWindow.PiPController> = PiPWindow.create(config);
promise.then((data: PiPWindow.PiPController) => {
  pipController = data;
  console.info(`Succeeded in creating pip controller. Data:${data}`);
  let promise : Promise<void> = pipController.startPiP();
  promise.then(() => {
    console.info(`Succeeded in starting pip.`);
  }).catch((err: BusinessError) => {
    console.error(`Failed to start pip. Cause:${err.code}, message:${err.message}`);
  });
}).catch((err: BusinessError) => {
  console.error(`Failed to create pip controller. Cause:${err.code}, message:${err.message}`);

调用pipController.startPiP()失败,报文1300013,错误码上说【不要在非全屏窗口下启动画中画】是什么意思?

HarmonyOS
2天前
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
Heiang

参考demo:

// Page1.ets
// 该页面用于展示画中画功能的基本使用
import { BuilderNode, FrameNode, NodeController, Size, UIContext, PiPWindow } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
import media from '@ohos.multimedia.media';

export class AVPlayerDemo {
  private count: number = 0;
  private surfaceID: string = '';
  private url: string = '';
  private avPlayer: media.AVPlayer | undefined;

  // 注册avplayer回调函数。
  setAVPlayerCallback() {
    // seek操作结果回调函数。
    this.avPlayer?.on('seekDone', (seekDoneTime: number) => {
      console.info(`AVPlayer seek succeeded, seek time is ${seekDoneTime}`);
    })
    // error回调监听函数,当avplayer在操作过程中出现错误时,调用reset接口触发重置流程。
    this.avPlayer?.on('error', (err: BusinessError) => {
      console.error(`Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`);
      this.avPlayer?.reset();
    })
    // 状态机变化回调函数。
    this.avPlayer?.on('stateChange', async (state: string, reason: media.StateChangeReason) => {
      switch (state) {
        case 'idle':
          console.info('AVPlayer state idle called.');
          this.avPlayer?.release();
          break;
        case 'initialized':
          console.info('AVPlayer state initialized called.');
          if (this.avPlayer != null && this.avPlayer != undefined) {
            this.avPlayer.surfaceId = this.surfaceID;
          }
          this.avPlayer?.prepare();
          break;
        case 'prepared':
          console.info('AVPlayer state prepared called.');
          if (this.count === 0 || this.count === 1) {
            console.info('AVPlayer start to play.');
            if (this.avPlayer != null && this.avPlayer != undefined) {
              this.avPlayer.surfaceId = this.surfaceID;
            }
            this.avPlayer?.play();
          }
          break;
        case 'playing':
          console.info('AVPlayer state playing called.');
          if (this.avPlayer != null && this.avPlayer != undefined) {
            this.avPlayer.surfaceId = this.surfaceID
          }
          this.avPlayer?.play();
          break;
        case 'paused':
          console.info('AVPlayer state paused called.');
          this.avPlayer?.pause();
          break;
        case 'completed':
          console.info('AVPlayer state paused called.');
          this.avPlayer?.stop();
          break;
        case 'stopped':
          console.info('AVPlayer state stopped called.');
          this.avPlayer?.reset();
          break;
        case 'released':
          console.info('AVPlayer state released called.' + this.surfaceID);
          break;
        default:
          break;
      }
    })
  }

  async avPlayerLiveDemo(count: number, url ?: string, avplayer ?: media.AVPlayer) {
    this.count = count;
    if (url != undefined) {
      this.url = url;
    }
    this.avPlayer = await media.createAVPlayer();
    this.setAVPlayerCallback();
    // this.avPlayer.url = url;
    let fileDescriptor = getContext().resourceManager.getRawFdSync('video1.mp4');
    let avFileDescriptor: media.AVFileDescriptor =
      { fd: fileDescriptor.fd, offset: fileDescriptor.offset, length: fileDescriptor.length };
    this.avPlayer.fdSrc = avFileDescriptor
  }

  destroy() {
    this.avPlayer?.stop()
    this.avPlayer?.release()
    this.avPlayer = undefined
  }

  setSurfaceID(surface_id: string) {
    console.log('setSurfaceID : ' + surface_id);
    this.surfaceID = surface_id;
  }

  getAvPlayer(): media.AVPlayer | undefined {
    return this.avPlayer;
  }

  getSurfaceID(): string {
    return this.surfaceID;
  }

  setUrl(url: string) {
    this.url = url;
  }

  getUrl(): string {
    return this.url
  }

  start() {
    this.avPlayer?.play()
  }

  pause() {
    this.avPlayer?.pause();
  }
}
class Params {
  text: string = '';
  constructor(text: string) {
    this.text = text;
  }
}

// 开发者可以通过@Builder装饰器实现布局构建
@Builder
function buildText(params: Params) {
  Column() {
    Text(params.text)
      .fontSize(20)
      .fontColor(Color.Red)
  }
  .width('100%') // 宽度方向充满画中画窗口
  .height('100%') // 高度方向充满画中画窗口
}

// 开发者可通过继承NodeController实现自定义UI控制器
class TextNodeController extends NodeController {
  private message: string;
  private textNode: BuilderNode<[Params]> | null = null;
  constructor(message: string) {
    super();
    this.message = message;
  }

  // 通过BuilderNode加载自定义布局
  makeNode(context: UIContext): FrameNode | null {
    this.textNode = new BuilderNode(context);
    this.textNode.build(wrapBuilder<[Params]>(buildText), new Params(this.message));
    return this.textNode.getFrameNode();
  }

  // 开发者可自定义该方法实现布局更新
  update(message: string) {
    console.log(`update message: ${message}`);
    if (this.textNode !== null) {
      this.textNode.update(new Params(message));
    }
  }
}

@Component
@Entry
export struct Index {
  private surfaceId: string = ''; // surfaceId,用于关联XComponent与视频播放器
  private mXComponentController: XComponentController = new XComponentController();
  private player?: AVPlayerDemo = undefined;
  private pipController?: PiPWindow.PiPController = undefined;
  private nodeController: TextNodeController = new TextNodeController('this is custom UI');
  navId: string = '';
  build() {
    Column() {
      // XComponent控件,用于播放视频流
      XComponent({ id: 'pipDemo', type: 'surface', controller: this.mXComponentController })
        .onLoad(() => {
          this.surfaceId = this.mXComponentController.getXComponentSurfaceId();
          // 需要设置AVPlayer的surfaceId为XComponentController的surfaceId
          this.player = new AVPlayerDemo();
          this.player.setSurfaceID(this.surfaceId)
          this.player.avPlayerLiveDemo(0,'')
        })
        .onDestroy(() => {
        })
        .size({ width: '100%', height: '800px' })
      Row({ space: 20 }) {
        Button('start') // 启动画中画
          .onClick(() => {
            this.startPip();
          })
          .stateStyles({
            pressed: {
              .backgroundColor(Color.Red);
            },
            normal: {
              .backgroundColor(Color.Blue);
            }
          })
        Button('stop') // 停止画中画
          .onClick(() => {
            this.stopPip();
          })
          .stateStyles({
            pressed: {
              .backgroundColor(Color.Red);
            },
            normal: {
              .backgroundColor(Color.Blue);
            }
          })
        Button('updateSize') // 更新视频尺寸
          .onClick(() => {
            // 此处设置的宽高应为媒体内容宽高,需要通过媒体相关接口或回调获取
            // 例如使用AVPlayer播放视频时,可通过videoSizeChange回调获取媒体源更新后的尺寸
            this.updateContentSize(900, 1600);
          })
          .stateStyles({
            pressed: {
              .backgroundColor(Color.Red);
            },
            normal: {
              .backgroundColor(Color.Blue);
            }
          })
      }
      .size({ width: '100%', height: 60 })
      .justifyContent(FlexAlign.SpaceAround)
    }
    .justifyContent(FlexAlign.Center)
    .height('100%')
    .width('100%')
  }

  startPip() {
    if (!PiPWindow.isPiPEnabled()) {
      console.error(`picture in picture disabled for current OS`);
      return;
    }
    let config: PiPWindow.PiPConfiguration = {
      context: getContext(this),
      componentController: this.mXComponentController,
      // 当前page导航id
      // 1、UIAbility使用Navigation管理页面,需要设置Navigation控件的id属性,并将该id设置给画中画控制器,确保还原场景下能够从画中画窗口恢复到原页面
      // 2、UIAbility使用Router管理页面时(画中画场景不推荐该导航方式),无需设置navigationId。注意:该场景下启动画中画后,不要进行页面切换,否则还原场景可能出现异常
      // 3、UIAbility只有单页面时,无需设置navigationId,还原场景下也能够从画中画窗口恢复到原页面
      navigationId: this.navId,
      templateType: PiPWindow.PiPTemplateType.VIDEO_PLAY, // 对于视频通话、视频会议等场景,需要设置相应的模板类型
      contentWidth: 1920, // 可选,创建画中画控制器时系统可通过XComponent组件大小设置画中画窗口比例
      contentHeight: 1080, // 可选,创建画中画控制器时系统可通过XComponent组件大小设置画中画窗口比例
      controlGroups:[PiPWindow.VideoPlayControlGroup.FAST_FORWARD_BACKWARD], // 可选,对于视频通话、视频会议和视频直播场景,可通过该属性选择对应模板类型下需显示的的控件组
      // customUIController: this.nodeController, // 可选,如果需要在画中画显示内容上方展示自定义UI,可设置该参数。
    };
    // 步骤1:创建画中画控制器,通过create接口创建画中画控制器实例
    let promise : Promise<PiPWindow.PiPController> = PiPWindow.create(config);
    promise.then((controller : PiPWindow.PiPController) => {
      this.pipController = controller;
      // 步骤1:初始化画中画控制器
      this.initPipController();
      // 步骤2:通过startPiP接口启动画中画
      this.pipController.startPiP().then(() => {
        console.info(`Succeeded in starting pip.`);
      }).catch((err: BusinessError) => {
        console.error(`Failed to start pip. Cause:${err.code}, message:${err.message}`);
      });
    }).catch((err: BusinessError) => {
      console.error(`Failed to create pip controller. Cause:${err.code}, message:${err.message}`);
    });
  }

  initPipController() {
    if (!this.pipController) {
      return;
    }
    // 步骤1:通过setAutoStartEnabled接口设置是否需要在应用返回桌面时自动启动画中画,注册stateChange和controlPanelActionEvent回调
    this.pipController.setAutoStartEnabled(false /*or true if necessary*/); // 默认为false
    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);
    });
  }

  onStateChange(state: PiPWindow.PiPState, reason: string) {
    let curState: string = '';
    switch(state) {
      case PiPWindow.PiPState.ABOUT_TO_START:
        curState = "ABOUT_TO_START";
        break;
      case PiPWindow.PiPState.STARTED:
        curState = "STARTED";
        break;
      case PiPWindow.PiPState.ABOUT_TO_STOP:
        curState = "ABOUT_TO_STOP";
        break;
      case PiPWindow.PiPState.STOPPED:
        curState = "STOPPED";
        break;
      case PiPWindow.PiPState.ABOUT_TO_RESTORE:
        curState = "ABOUT_TO_RESTORE";
        break;
      case PiPWindow.PiPState.ERROR:
        curState = "ERROR";
        break;
      default:
        break;
    }
  }

  onActionEvent(event: PiPWindow.PiPActionEventType, status?: number) {
    switch (event) {
      case 'playbackStateChanged':
      // 开始或停止视频
        if (status === 0) {
          // 停止视频
          this.player?.pause()
        } else if (status === 1) {
          // 播放视频
          this.player?.start()
        }
        break;
      case 'nextVideo':
      // 播放上一个视频
        break;
      case 'previousVideo':
      // 播放下一个视频
        break;
      default:
        break;
    }
  }

  // 步骤3:视频内容变化时,向画中画控制器更新视频尺寸信息,用于调整画中画窗口比例
  updateContentSize(width: number, height: number) {
    if (this.pipController) {
      this.pipController.updateContentSize(width, height);
    }
  }

  // 步骤4:当不再需要显示画中画时,通过stopPiP接口关闭画中画
  stopPip() {
    if (this.pipController) {
      let promise : Promise<void> = this.pipController.stopPiP();
      promise.then(() => {
        console.info(`Succeeded in stopping pip.`);
        this.pipController?.off('stateChange'); // 如果已注册stateChange回调,停止画中画时取消注册该回调
        this.pipController?.off('controlPanelActionEvent'); // 如果已注册controlPanelActionEvent回调,停止画中画时取消注册该回调
      }).catch((err: BusinessError) => {
        console.error(`Failed to stop pip. Cause:${err.code}, message:${err.message}`);
      });
    }
  }
}
分享
微博
QQ
微信
回复
2天前
相关问题
HarmonyOS 画中画
103浏览 • 1回复 待解决
HarmonyOS 画中画视频无法播放
207浏览 • 1回复 待解决
webview错误码105 是什么错误
1071浏览 • 1回复 待解决
HarmonyOS 画中画无法指定窗体大小
110浏览 • 1回复 待解决
TiDB Server具体是什么意思
3358浏览 • 1回复 待解决
鸿蒙的signature权限是什么意思
7874浏览 • 1回复 待解决
是什么意思
2406浏览 • 1回复 待解决
HarmonyOS 定位失败 错误码3301200:
232浏览 • 1回复 待解决
HarmonyOS @ohos.PiPWindow开启画中画示例
129浏览 • 1回复 待解决
HarmonyOS 音视频画中画功能demo
188浏览 • 1回复 待解决
MongoDB中的分片是什么意思
3449浏览 • 1回复 待解决
DevEco的日志如下是什么意思
1097浏览 • 0回复 待解决
是什么意思
896浏览 • 1回复 待解决
startAbility跳转失败返回错误码16000001
2324浏览 • 1回复 待解决
鸿蒙提供的画中画功能要怎么实现?
1120浏览 • 1回复 待解决
HarmonyOS available代表什么意思
267浏览 • 1回复 待解决
调用广告接口,返回错误码21800003
754浏览 • 1回复 待解决
提问
该提问已有0人参与 ,帮助了0人