折叠屏或分栏模式下观看视频时，画面拉伸
===================

#### 问题现象

*   折叠屏折叠态下，应用横屏观看视频，视频画面发生拉伸现象。
*   分栏模式下，应用观看视频，视频画面发生拉伸现象。

#### 背景知识

*   [XComponent](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-xcomponent)：提供用于图形绘制和媒体数据写入的Surface，XComponent负责将Surface嵌入到视图中，支持应用自定义Surface位置和大小。
*   [Video](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-media-components-video)：用于播放视频文件并控制其播放状态的组件。Video组件只提供简单的视频播放功能，无法支持复杂的视频播放控制场景。
*   [AVPlayer](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-media-avplayer)：播放管理类，用于管理和播放媒体资源。在调用AVPlayer接口前，需要先通过createAVPlayer()构建一个AVPlayer实例。

#### 问题定位

目前系统提供了Video和AVPlayer两种视频播放组件。可以通过DevEco Testing或代码检查来确认使用的是哪种组件。

*   Video视频组件，建议检查代码中是否设置objectFit视频显示模式为Fill模式，该模式下视频不保持宽高比，会导致画面出现拉伸。
*   若使用的是AVPlayer视频组件，此时建议检查代码VideoScaleType视频缩放模式属性的设置值，该属性设置成VIDEO\_SCALE\_TYPE\_FIT时，会将视频拉伸至与窗口等大，导致画面拉伸。
*   通常AVPlayer会搭配XComponent使用，此时建议检查代码中视频的宽高比与XComponent持有Surface的显示区域的宽高比是否一致，如果宽高比不一致，会导致画面拉伸。

#### 分析结论

*   Video组件视频显示模式设置不正确导致视频画面发生拉伸现象。
*   AVPlayer组件视频缩放模式设置不正确导致视频画面发生拉伸现象。
*   AVPlayer组件中视频的宽高比跟XComponent持有Surface的显示区域的宽高比不一致，导致画面拉伸。

#### 修改建议

*   修改Video视频显示模式[objectFit](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-image#objectfit)属性为Auto或者Contain，确保视频保持宽高比缩放。
*   在横竖屏切换时或在切换到分栏模式时，可以先用avPlayer.on('stateChange')监听视频状态变化，在监听到状态prepared时，获取视频的宽和高，并动态更改XComponent的Surface显示区域的宽高。
    
    import { media } from '@kit.MediaKit';
    import { display } from '@kit.ArkUI';
    
    _// 1.创建视频播放器组件_
    @Entry
    @Component
    struct VideoPlayerDemo {
      private avPlayer: media.AVPlayer | null = null; _// AVPlayer实例_
      private surfaceId: string = ''; _// 播放窗口SurfaceID_
      private xComponentController: XComponentController = new XComponentController();
      private videoWidth: number | undefined = 0;
      private videoHeight: number | undefined = 0;
    
     _ // 2.构建UI布局_
      build() {
        Column() {
         _ // 视频播放窗口组件_
          XComponent({
            id: "XComponent",
            type: XComponentType.SURFACE,
            controller: this.xComponentController
          })
            .onLoad(() => {
              _// 获取SurfaceID并初始化播放器_
              this.surfaceId = this.xComponentController.getXComponentSurfaceId();
              this.initAVPlayer();
            })
            .width('100%')
            .height('100%');
        }
        .width('100%')
        .height('100%');
      }
    
     _ // 3.初始化播放器_
      async initAVPlayer() {
        try {
         _ // 创建AVPlayer实例_
          this.avPlayer = await media.createAVPlayer();
        _  // 设置监听事件_
          this.avPlayer.on('stateChange', async (state: string) => {
            if (state === 'initialized') {
              _// 设置播放窗口_
              this.avPlayer!.surfaceId = this.surfaceId;
              await this.avPlayer!.prepare();
            } else if (state === 'prepared') {
              await this.avPlayer!.play(); _// 自动开始播放_
              _// 获取视频原始宽高_
              this.videoWidth = this.avPlayer?.width;
              this.videoHeight = this.avPlayer?.height;
              this.adjustSurfaceSize();
            }
          });
        _  // 监听屏幕旋转_
          display.on('change', () => {
            this.adjustSurfaceSize();
          });
      _    // 设置播放源（本地文件或网络地址）_
          this.avPlayer.url = 'https://xxx.mp4'; _// 替换为实际地址_
        } catch (error) {
          console.error(\`Player initialization failed: ${error}\`);
        }
      }
    
      private adjustSurfaceSize() {
        if (!this.videoWidth || !this.videoHeight) {
          return;
        }
        _// 获取当前屏幕方向_
        const displayInfo = display.getDefaultDisplaySync();
        const isPortrait = displayInfo.width < displayInfo.height;
        _// 计算保持原始比例的显示尺寸_
        let displayWidth = 0;
        let displayHeight = 0;
        if (isPortrait) {
         _ // 竖屏模式下保持视频宽度，高度按比例计算_
          displayWidth = displayInfo.width;
          displayHeight = displayWidth \* this.videoHeight / this.videoWidth;
        } else {
        _  // 横屏模式下保持视频高度，宽度按比例计算_
          displayHeight = displayInfo.height;
          displayWidth = displayHeight \* this.videoWidth / this.videoHeight;
        }
      _  // 更新XComponent尺寸_
        this.xComponentController.setXComponentSurfaceRect({
          surfaceWidth: displayWidth,
          surfaceHeight: displayHeight
        });
      }
    
      _// 4.组件销毁时释放资源_
      aboutToDisappear() {
        if (this.avPlayer) {
          this.avPlayer.release();
          this.avPlayer = null;
        }
      }
    }