HarmonyOS 鸿蒙Next中VIDEO组件循环播放

HarmonyOS 鸿蒙Next中VIDEO组件循环播放

Video({
  src: VideoSources[this.Params.id][0], //视频地址
  previewUri: VideoSources[this.Params.id][1],
  currentProgressRate: this.VideoSpeed,
  controller: this.Running_Video_controller
}).controls(false)//控制栏不显示
  .loop(true)//循环播放
  .onStop(() => {
    router.replaceUrl({
      url: pageManager.Running_EndingPage,
      params: {
        running_data: this.runningData
      }
    }, router.RouterMode.Single, (err) => {
      if (err) {
        console.log('路由失败')
      }
    });
  })
  .onFinish(() => {
    this.Running_Video_controller.start()
  })

在使用loop循环播放时,视频的结尾与下一次的开头会有很微弱的停顿闪烁,有什么好的方法解决?


更多关于HarmonyOS 鸿蒙Next中VIDEO组件循环播放的实战教程也可以访问 https://www.itying.com/category-93-b0.html

7 回复

【背景知识】

  • Video组件用于播放视频文件并控制其播放状态,常用于短视频和应用内部视频的列表页面。具体用法请参考Video
  • 播放停止时触发onStop事件(当stop()方法被调用后触发),支持attributeModifier动态设置属性方法。
  • setCurrentTime用于指定视频播放的进度位置,取值范围为[0,duration],单位为秒。从API version 8开始,支持设置视频的跳转模式,视频跳转模式选项详见SeekMode枚举说明

【修改建议】

尝试在onFinish回调事件里边通过setCurrentTimeSeekMode指定视频播放的进度位置,并指定跳转模式,在视频播放结束时直接精准定位到视频0s位置,避免播放状态重置时引起加载状态的显示。示例代码如下:

// 直接定位到起始位置(避免重置)
this.controller.setCurrentTime(0, SeekMode.Accurate) // 精准跳转到视频的0s位置

更多关于HarmonyOS 鸿蒙Next中VIDEO组件循环播放的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


官网弄了个demo改了一下,不卡啊,是你视频有问题吗,测试的日志也很明显,视频到末尾21秒后,下一个就是0,不存在重新加载资源什么的

// xxx.ets
@Entry
@Component
struct VideoCreateComponent {
  // $rawfile('video1.mp4')、$r('app.media.poster1')需要分别替换为开发者所需的视频、图片资源文件
  @State previewUri: Resource = $r('app.media.startIcon');
  @State curRate: PlaybackSpeed = PlaybackSpeed.Speed_Forward_1_00_X;
  @State isAutoPlay: boolean = false;
  @State showControls: boolean = true;
  @State isShortcutKeyEnabled: boolean = false;
  @State showFirstFrame: boolean = false;
  controller: VideoController = new VideoController();
  build() {
    Column() {
      Video({
        src: "https://vd2.bdstatic.com/mda-riadktnbps72zsd6/720p/h264/1757583400236609958/mda-riadktnbps72zsd6.mp4",
        previewUri: this.previewUri, // 设置预览图
        currentProgressRate: this.curRate, // 设置播放速度
        controller: this.controller,
      })
        .width('100%')
        .loop(true)
        .height(600)
        .autoPlay(this.isAutoPlay)
        .controls(this.showControls)
        .enableShortcutKey(this.isShortcutKeyEnabled)
        .onStart(() => {
          console.info('onStart');
        })
        .onPause(() => {
          console.info('onPause');
        })
        .onFinish(() => {
          console.info('onFinish');
        })
        .onError(() => {
          console.info('onError');
        })
        .onStop(() => {
          console.info('onStop');
        })
        .onPrepared((e?: DurationObject) => {
          if (e != undefined) {
            console.info('onPrepared is ' + e.duration);
          }
        })
        .onSeeking((e?: TimeObject) => {
          if (e != undefined) {
            console.info('onSeeking is ' + e.time);
          }
        })
        .onSeeked((e?: TimeObject) => {
          if (e != undefined) {
            console.info('onSeeked is ' + e.time);
          }
        })
        .onUpdate((e?: TimeObject) => {
          if (e != undefined) {
            console.info('onUpdate is ' + e.time);
          }
        })
        .onFullscreenChange((e?: FullscreenObject) => {
          if (e != undefined) {
            console.info('onFullscreenChange is ' + e.fullscreen);
          }
        })


      Row() {
        Button('start').onClick(() => {
          this.controller.start(); // 开始播放
        }).margin(2)
        Button('pause').onClick(() => {
          this.controller.pause(); // 暂停播放
        }).margin(2)
        Button('stop').onClick(() => {
          this.controller.stop(); // 结束播放
        }).margin(2)
        Button('reset').onClick(() => {
          this.controller.reset(); // 重置AVPlayer
        }).margin(2)
        Button('setTime').onClick(() => {
          this.controller.setCurrentTime(10, SeekMode.Accurate); // 精准跳转到视频的10s位置
        }).margin(2)
      }

      Row() {
        Button('rate 0.75').onClick(() => {
          this.curRate = PlaybackSpeed.Speed_Forward_0_75_X; // 0.75倍速播放
        }).margin(5)
        Button('rate 1').onClick(() => {
          this.curRate = PlaybackSpeed.Speed_Forward_1_00_X; // 原倍速播放
        }).margin(5)
        Button('rate 2').onClick(() => {
          this.curRate = PlaybackSpeed.Speed_Forward_2_00_X; // 2倍速播放
        }).margin(5)
      }
    }
  }
}

interface DurationObject {
  duration: number;
}

interface TimeObject {
  time: number;
}

interface FullscreenObject {
  fullscreen: boolean;
}
启用无缝循环参数
在设置.loop(true)的基础上,补充视频填充模式参数,避免因分辨率适配问题导致画面闪烁:

   Video({
     src: this.videoSrc,
     controller: this.controller
   })
   .loop(true)
   .objectFit(ImageFit.Cover) // 优先使用Cover模式填充画面

预加载视频资源
通过.autoPlay(true)和.controls(false)确保视频资源在准备完成后立即播放,减少加载间隙:

   Video({
     src: this.innerResource,
     previewUri: $r('app.media.preview'),
     controller: this.controller
   })
   .autoPlay(true)  // 自动播放减少初始加载延迟
   .controls(false) // 隐藏默认控制条避免UI干扰

可以尝试以下方法

1.提前加载资源:在视频播放前预加载视频文件,减少循环时的加载延迟。可通过VideoController的预加载方法实现:

this.Running_Video_controller.prepare(); // 提前初始化播放资源

2.移除冗余回调:当前的.onFinish(() => { this.Running_Video_controller.start() })可能与loop(true)的自动循环逻辑冲突,导致重复触发。建议删除此回调,仅依赖loop(true)属性。

3.隐藏切换过程:在视频即将结束时,短暂隐藏组件或添加过渡动画覆盖闪烁:

@State isVideoVisible: boolean = true;

Video({ ... })
.visibility(this.isVideoVisible ? Visibility.Visible : Visibility.Hidden)
.onFinish(() => {
this.isVideoVisible = false;
setTimeout(() => { this.isVideoVisible = true; }, 50); // 短暂隐藏再显示
});

建议看一下视频源,特别是片头和片尾的那几帧数据,可以切掉之后再看看。

在HarmonyOS鸿蒙Next中,使用VIDEO组件实现循环播放可通过设置loop属性为true实现。示例代码:

<video src="video.mp4" loop="true"></video>

该属性控制视频播放完成后自动重新开始,无需额外逻辑处理。

在HarmonyOS Next中,可以通过调整视频播放器的缓冲策略来减少循环播放时的停顿闪烁。建议在Video组件中设置autoPlay为true,并确保视频资源已预加载。此外,可以尝试使用onFinish事件中直接调用start()方法,但需注意避免重复触发。检查视频编码格式,确保为流媒体优化格式(如H.264),以减少解码延迟。若问题持续,可考虑使用双Video组件交替播放来实现无缝衔接。

回到顶部