HarmonyOS 请问使用xcomponent和avplayer实现的视频播放,视频的全屏切换与否如何实现,以及视频的不同宽高和比例该如何显示

使用Xcomponent和AVPlayer实现的视频播放:

1、视频区域的位置在页面内是不固定的,可能在列表中,可能在页面的中间,或者顶部,请问此时点击切换成全屏,怎么能让视频区域占满屏幕,不会被页面的其他组件遮挡?切换成全屏不一定是翻转成横屏,也有可能是竖屏的视频,这种该如何判断是否需要翻转屏幕呢?

2、视频的宽高和比例也不是固定的,可能是手机自拍的竖向视频,可能是横向的16:9视频,也有可能是4:3,16:25这种比例的视频,请问这种情况如何让视频是根据视频真正的宽高比来显示,不会被拉伸或者裁剪呢?

HarmonyOS
2025-01-09 16:04:43
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
zxjiu

示例参考如下:

import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
import { AVPlayerDemo } from '../pages/AVPlayerDemo';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
  }

  onDestroy(): void {
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
        return;
      }

      AppStorage.setOrCreate('player', new AVPlayerDemo());
      hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
    });
  }

  onWindowStageDestroy(): void {
    // Main window is destroyed, release UI related resources
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
  }

  onForeground(): void {
    // Ability has brought to foreground
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
  }

  onBackground(): void {
    // Ability has back to background
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
  }
}

Index.ets

import { myVideoSourceDate, VideoSource } from './myVideoSourceDate';
import { VideoComponent } from './VideoComponent';

@Entry
@Component
struct Index {
  private data: myVideoSourceDate = new myVideoSourceDate([]);
  @State isLayoutFullScreen : boolean = false;
  @State fangDaIndex : number = -1;

  aboutToAppear(): void {
    let list: VideoSource[] = [
      new VideoSource('文案0', 'https://xx.***.com/video/mp4/62000/62792m.mp4'),
      new VideoSource('文案0', 'https://xx.***.com/video/mp4/62000/62792m.mp4'),
      new VideoSource('文案0', 'https://xx.***.com/video/mp4/62000/62792m.mp4')
    ];
    console.log('myAppliction is Appear')
    this.data = new myVideoSourceDate(list);
  }

  build() {
    Scroll() {
      Column() {
        List() {
          LazyForEach(this.data, (item: VideoSource,index : number) => {
            ListItem() {
              VideoComponent({item : item, isLayoutFullScreen : this.isLayoutFullScreen, index : index , fangDaIndex : this.fangDaIndex})
                .visibility(this.isLayoutFullScreen && this.fangDaIndex !== index ? Visibility.None : Visibility.Visible)
            }
          }, (item: string) => item)
        }.cachedCount(5).scrollBar(BarState.Off).edgeEffect(this.isLayoutFullScreen ? EdgeEffect.None : EdgeEffect.Spring)
      }
    }
    .edgeEffect(this.isLayoutFullScreen ? EdgeEffect.None : EdgeEffect.Spring)
    .width('100%')
  }
}

VideoComponent.ets

import { AVPlayerDemo } from './AVPlayerDemo';
import { VideoSource } from './myVideoSourceDate';
import window from '@ohos.window';
import { BusinessError } from '@ohos.base';

@Component
export struct VideoComponent {
  @ObjectLink item: VideoSource;
  index: number = -1;
  @Link isLayoutFullScreen: boolean;
  @Link fangDaIndex: number;
  @State bkColor: Color = Color.Red
  mXComponentController: XComponentController = new XComponentController();
  @State player_changed: boolean = false;
  // player: AVPlayerDemo = new AVPlayerDemo();
  player: AVPlayerDemo = AppStorage.get('player') as AVPlayerDemo

  // 设置窗口方向
  setR(orientation: number) {
    window.getLastWindow(getContext(this)).then((win) => {
      win.setPreferredOrientation(orientation).then((data) => {
        console.log('setWindowOrientation: ' + orientation + ' Succeeded. Data: ' + JSON.stringify(data));
      }).catch((err: string) => {
        console.log('setWindowOrientation: Failed. Cause: ' + JSON.stringify(err));
      });
    }).catch((err: string) => {
      console.log('setWindowOrientation: Failed to obtain the top window. Cause: ' + JSON.stringify(err));
    });
  }

  // 设置沉浸式窗口
  setFullScreen(isLayoutFullScreen: boolean) {
    window.getLastWindow(getContext(this)).then((win) => {
      win.setWindowLayoutFullScreen(isLayoutFullScreen, (err: BusinessError) => {
        const errCode: number = err.code;
        if (errCode) {
          console.error('Failed to set the window layout to full-screen mode. Cause:' + JSON.stringify(err));
          return;
        }
        console.info('Succeeded in setting the window layout to full-screen mode.');
      });
    }).catch((err: string) => {
      console.log('setWindowOrientation: Failed to obtain the top window. Cause: ' + JSON.stringify(err));
    });
  }

  build() {
    // 通过显隐控制控制其他listItrem是否展示
    Column() {
      Text(this.item.text)
        .visibility(this.isLayoutFullScreen === false ? Visibility.Visible : Visibility.None)
      Stack() {
        XComponent({ id: 'video_player_id', type: XComponentType.SURFACE, controller: this.mXComponentController })
          .onLoad(() => {
            this.player.setSurfaceID(this.mXComponentController.getXComponentSurfaceId());
            this.player_changed = !this.player_changed;
            this.player.avPlayerLiveDemo(0, this.item.url);
          })
        Row() {
          Button(this.isLayoutFullScreen ? '退出全屏' : '点击全屏')
            .onClick(() => {
              this.fangDaIndex = this.index
              this.isLayoutFullScreen = !this.isLayoutFullScreen;
              this.setR(this.isLayoutFullScreen ? 4 : 1)
              this.setFullScreen(this.isLayoutFullScreen)
            })
            .backgroundColor(this.bkColor)
        }
      }
      .height(this.isLayoutFullScreen ? '100%' : 200)
    }
    .width('100%')
  }
}

AVPlayerDemo.ets

import media from '@ohos.multimedia.media';
import { BusinessError } from '@ohos.base';

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;
  }

  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();
  }
}

myVideoSourceDate.ets

export class myVideoSourceDate implements IDataSource {
  videoList: VideoSource[] = [];

  constructor(videoList: VideoSource[]) {
    this.videoList = videoList;
  }

  totalCount(): number {
    return this.videoList.length;
  }

  getData(index: number): VideoSource {
    return this.videoList[index];
  }

  registerDataChangeListener(listener: DataChangeListener): void {
  }

  unregisterDataChangeListener(listener: DataChangeListener): void {
  }
}

@Observed
export class VideoSource {
  text ?: string;
  url ?: string;

  constructor(text ?: string,url?: string) {
    this.text = text;
    this.url = url;
  }
}
分享
微博
QQ
微信
回复
2025-01-09 17:57:30
相关问题
AVPlayer实现视频播放
1582浏览 • 1回复 待解决
使用AVPlayer实现视频播放
1879浏览 • 1回复 待解决
HarmonyOS Web组件如何实现视频全屏播放
1356浏览 • 1回复 待解决
HarmonyOS 列表视频全屏播放实现
878浏览 • 1回复 待解决
HarmonyOS获取相册视频问题
892浏览 • 1回复 待解决
avplayer播放视频demo
2412浏览 • 1回复 待解决