0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

在HarmonyOS中使用AVPlayer播放流媒体

HarmonyOS开发者 来源:HarmonyOS开发者 2025-10-15 11:45 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

一句话总结

HarmonyOS 中,使用 AVPlayer 播放流媒体,不是“能播就行”,而是要“稳、准、快、可控”。

本文带你掌握从创建到释放的全链路操作,覆盖 HLS/DASH/FLV 等主流协议,支持码率切换、轨道选择、自动重试、缓冲监控等高阶能力。

一、前置准备:权限 & 环境配置

1. 添加网络权限

在 module.json5 中添加:

{
"reqPermissions":[
 {
  "name":"ohos.permission.INTERNET"
 }
]
}

否则访问任何网络资源都会失败。

2. 引入 MediaKit 模块

import{ media }from'@kit.MediaKit';

推荐使用 @kit.MediaKit,它是 HarmonyOS 官方提供的多媒体核心库。

二、标准播放流程

顺序不能乱,否则可能收不到事件、无法播放。

async avSetupStreamingMediaVideo() {
 if(this.context == undefined)return;
 // 创建avPlayer实例对象。
 this.avPlayer = await media.createAVPlayer();
 // 创建状态机变化回调函数。
  awaitthis.setAVPlayerCallback((avPlayer: media.AVPlayer) => {
  this.percent = avPlayer.width / avPlayer.height; // 计算并保存视频的宽高比
  this.setVideoWH(); // 调用方法更新视频显示区域的宽高
  this.durationTime =this.getDurationTime(); // 获取视频总时长
   setInterval(() => {// 更新当前时间。
   if(!this.isSwiping) {
    this.currentTime =this.getCurrentTime();
    }
   }, SET_INTERVAL);
  });
 // 设置播放资源。
 this.avPlayer.url ="http://media.iyuns.top:1000/http/720p_1m.mp4";
 //开始播放
  avPlay(): void {
  if(this.avPlayer) {
   try{
    this.avPlayer.play();
    }catch(e) {
     console.error(`${this.tag}: avPlay = ${JSON.stringify(e)}`);
    }
   }
  }

三、核心监听事件详解(缺一不可)

0be55f2a-a8e0-11f0-8c8f-92fbcf53809c.png

示例:监听播放器状态变化和监听播放时间

// 状态机变化回调函数。
 this.avPlayer.on('stateChange',async(state, reason) => {
  if(this.avPlayer==null) {
   console.info(`${this.tag}: avPlayer has not init on state change`);
   return;
   }
 // 时间上报监听函数。
 this.avPlayer.on('timeUpdate',(time:number) =>{
  this.currentTime= time;
  });

四、主流协议支持一览表

0c4fd594-a8e0-11f0-8c8f-92fbcf53809c.png

所有协议均支持 setSource() 直接接入,无需额外封装。

五、高阶功能实战(让你的播放器“聪明”起来)

1. 流媒体缓冲状态

当下载速率低于片源的码率时,会出现卡顿。此时,播放器检测到缓冲区数据不足,会先缓冲一些数据再播放,避免连续卡顿。一次卡顿对应的缓冲事件上报过程为:BUFFERING_START-> BUFFERING_PERCENT 0 -> ... -> BUFFERING_PERCENT 100 -> BUFFERING_END。CACHED_DURATION在卡顿过程和播放过程中都会持续上报,直至下载至资源末尾。

import{ media }from'@kit.MediaKit';
// 类成员定义avPlayer
privateavPlayer: media.AVPlayer|null=null;
// 创建avPlayer实例对象。
this.avPlayer=awaitmedia.createAVPlayer();
// 监听当前bufferingUpdate缓冲状态。
this.avPlayer.on('bufferingUpdate',(infoType : media.BufferingInfoType, value :number) =>{
console.info(`AVPlayer bufferingUpdate, infoType is${infoType}, value is${value}.`);
})

适用于直播、弱网环境下保障连续播放。

2. HLS 多码率切换(自定义清晰度)

当前流媒体HLS协议流支持多码率播放,默认情况下,播放器会根据网络下载速度选择合适的码率。

通过on('availableBitrates')监听当前HLS协议流可用的码率。如果监听的码率列表长度为0,则不支持设置指定码率。

import{ media }from'@kit.MediaKit';
// 类成员定义avPlayer
privateavPlayer: media.AVPlayer|null=null;
// 创建avPlayer实例对象。
this.avPlayer=awaitmedia.createAVPlayer();
// 监听当前HLS协议流可用的码率。
this.avPlayer.on('availableBitrates',(bitrates:Array) =>{
console.info('availableBitrates called, and availableBitrates length is: '+ bitrates.length);
})

通过setBitrate接口设置播放码率。若用户设置的码率不在可用码率中,播放器将选择最小且最接近的码率。该接口只能在prepared/playing/paused/completed状态下调用,可通过监听bitrateDone事件确认是否生效。

import{ media }from'@kit.MediaKit';
// 类成员定义avPlayer
privateavPlayer: media.AVPlayer|null=null;
// 创建avPlayer实例对象。
this.avPlayer=awaitmedia.createAVPlayer();
// 监听码率设置是否生效。
this.avPlayer.on('bitrateDone',(bitrate:number) =>{
console.info('bitrateDone called, and bitrate value is: '+ bitrate);
})
// 设置播放码率。
this.bitrate:number=96000;
this.avPlayer.setBitrate(this.bitrate);

可配合 UI 提供“清晰度选择”按钮。

3. DASH 起播策略设置(首帧更快加载)

为了保证在弱网环境下的播放体验,AVPlayer将默认选择最低的视频分辨率开始播放,随后依据网络状况自动调整。开发者可以根据具体需求,自定义DASH视频的起播策略,包括设定视频的宽度、高度以及色彩格式等参数。

// 自定义起播分辨率:1920×1080
import{ media }from'@kit.MediaKit';
letmediaSource : media.MediaSource= media.createMediaSourceWithUrl("http://test.cn/dash/aaa.mpd", {"User-Agent":"User-Agent-Value"});
letplaybackStrategy : media.PlaybackStrategy= {preferredWidth:1920,preferredHeight:1080};
this.avPlayer.setMediaSource(mediaSource, playbackStrategy);

弱网环境下优先加载低码率,提升首帧速度。

4. DASH 音视频轨道切换(手动选清晰度/语言)

DASH流媒体资源包含多路不同分辨率、码率、采样率、编码格式的音频、视频及字幕资源。默认情况下,AVPlayer会依据网络状况自动切换不同码率的视频轨道。开发者可根据需求选择指定的音视频轨道播放,此时自适应码率切换策略将失效。

设置selectTrack生效的监听事件trackChange。

import{ media }from'@kit.MediaKit';
// 类成员定义avPlayer
privateavPlayer: media.AVPlayer|null=null;
// 创建avPlayer实例对象。
this.avPlayer=awaitmedia.createAVPlayer();
this.avPlayer.on('trackChange',(index:number, isSelect:boolean) =>{
console.info(`trackChange info, index:${index}, isSelect:${isSelect}`);
})
});

调用getTrackDescription获取所有音视频轨道列表。开发者可根据实际需求,基于MediaDescription各字段信息,确定目标轨道索引

// 以获取1080p视频轨道索引为例。
import{ media }from'@kit.MediaKit';
import{BusinessError}from'@kit.BasicServicesKit';
publicvideoTrackIndex:number=0;
// 类成员定义avPlayer
privateavPlayer: media.AVPlayer|null=null;
// 创建avPlayer实例对象。
this.avPlayer=awaitmedia.createAVPlayer();
this.avPlayer.getTrackDescription((error: BusinessError, arrList:Array) =>{
if(arrList !=null) {
 for(leti =0; i < arrList.length; i++) {
      let propertyIndex: Object = arrList[i][media.MediaDescriptionKey.MD_KEY_TRACK_INDEX];
      let propertyType: Object = arrList[i][media.MediaDescriptionKey.MD_KEY_TRACK_TYPE];
      let propertyWidth: Object = arrList[i][media.MediaDescriptionKey.MD_KEY_WIDTH];
      let propertyHeight: Object = arrList[i][media.MediaDescriptionKey.MD_KEY_HEIGHT];
      if (propertyType == media.MediaType.MEDIA_TYPE_VID && propertyWidth == 1920 && propertyHeight == 1080) {
        this.videoTrackIndex = parseInt(propertyIndex?.toString()); // 获取1080p视频轨道索引。
      }
    }
  } else {
    console.error(`getTrackDescription fail, error:${error}`);
  }
});

在音视频播放过程中调用selectTrack选择对应的音视频轨道,或者调用deselectTrack取消选择的音视频轨道。

import{ media }from'@kit.MediaKit';
publicvideoTrackIndex:number=0;
 // 类成员定义avPlayer
privateavPlayer: media.AVPlayer|null=null;
// 创建avPlayer实例对象。
this.avPlayer=awaitmedia.createAVPlayer();
// 切换至目标视频轨道。
this.avPlayer.selectTrack(this.videoTrackIndex);
// 取消选择目标视频轨道。
// this.avPlayer.deselectTrack(this.videoTrackIndex);

适合教育类、影视类 App,让用户自由选择画质/字幕/语音。

六、常见坑位 & 解决方案(避雷手册)

0cab9406-a8e0-11f0-8c8f-92fbcf53809c.png

七、一个简单的开发实例

import{ media } from'@kit.MediaKit';
import{ emitter } from'@kit.BasicServicesKit';
import{ display } from'@kit.ArkUI';
constTIME_ONE =60000;// 1分钟的毫秒数。
constTIME_TWO =1000; // 1秒的毫秒数。
constSET_INTERVAL =1000;// 每秒更新一次当前播放时间。
constSPEED_ZERO: number =0;// 对应1.00x。
constSPEED_ONE: number =1; // 对应1.25x。
constSPEED_TWO: number =2; // 对应1.75x。
constSPEED_THREE: number =3;// 对应2.00x。
constPROPORTION: number =0.99;
let innerEventFalse: emitter.InnerEvent = {
 eventId:1,
 priority: emitter.EventPriority.HIGH
};
let innerEventTrue: emitter.InnerEvent = {
 eventId:2,
 priority: emitter.EventPriority.HIGH
};
let innerEventWH: emitter.InnerEvent = {
 eventId:3,
 priority: emitter.EventPriority.HIGH
};
@Entry
@Component
struct Index {
privateavPlayer: media.AVPlayer |null=null;
privatecontext: Context | undefined = undefined;
publicvideoTrackIndex: number =0;
publicbitrate: number =0;
@StatedurationTime: number =0;
@StatecurrentTime: number =0;
@Statepercent: number =0;
@StateisSwiping: boolean =false;
@Statetag: string ='StreamingMedia';
privatesurfaceId: string ='';
@StatespeedSelect: number = -1;
publicintervalID: number = -1;
@StatewindowWidth: number =300;
@StatewindowHeight: number =300;
@StatesurfaceW: number |null=null;
@StatesurfaceH: number |null=null;
@StateisPaused: boolean =true;
@StateXComponentFlag: boolean =false;
 getDurationTime(): number {
 returnthis.durationTime;
 }
 getCurrentTime(): number {
 returnthis.currentTime;
 }
 timeConvert(time: number): string {
  let min: number = Math.floor(time / TIME_ONE);
  let second: string = ((time % TIME_ONE) / TIME_TWO).toFixed(0);
 // return `${min}:${(+second < TIME_THREE ? '0' : '') + second}`;
    second = second.padStart(2, '0');
    return `${min}:${second}`;
  }
  async msleepAsync(ms: number): Promise {
 returnnew Promise((resolve, reject) => {
   setTimeout(() => {
    resolve(true)
   }, ms)
  })
 }
 async avSetupStreamingMediaVideo() {
 if(this.context == undefined)return;
 // 创建avPlayer实例对象。
 this.avPlayer = await media.createAVPlayer();
 // 创建状态机变化回调函数。
  awaitthis.setAVPlayerCallback((avPlayer: media.AVPlayer) => {
  this.percent = avPlayer.width / avPlayer.height;
  this.setVideoWH();
  this.durationTime =this.getDurationTime();
   setInterval(() => {// 更新当前时间。
   if(!this.isSwiping) {
    this.currentTime =this.getCurrentTime();
    }
   }, SET_INTERVAL);
  });
 // 情况一:HTTP视频播放。
 this.avPlayer.url ="http://media.iyuns.top:1000/http/720p_1m.mp4";
 // 情况二:HLS视频播放。
 // this.avPlayer.url = "http://media.iyuns.top:1000/720-270-480.m3u8";
 // 情况三:DASH视频播放。
 // this.avPlayer.url = "http://media.iyuns.top:1000/dash/720p/720-1/720-1.mpd";
 // 情况四:通过setMediaSource设置自定义头域及播放优选参数实现初始播放参数设置,以流媒体HTTP点播为例。
 /*
  let mediaSource : media.MediaSource = media.createMediaSourceWithUrl("http://media.iyuns.top:1000/http/720p_1m.mp4", {"":""});
  // 设置播放策略,设置为缓冲区数据为20s。
  let playbackStrategy : media.PlaybackStrategy = {preferredBufferDuration: 20};
  // 为avPlayer设置媒体来源和播放策略。
  this.avPlayer.setMediaSource(mediaSource, playbackStrategy);
  * */
 // 情况五:HLS切码率。
 /*
  this.avPlayer.url = "https://upftimae.dailyworkout.cn/videos/course/c800f81a209b5ee7891f1128ed301db/4/master.m3u8";
  let bitrate: number = 0;
  // 监听当前HLS协议流可用的码率。
  this.avPlayer.on('availableBitrates', (bitrates: Array) => {
   console.info('availableBitrates called, and availableBitrates length is: ' + bitrates.length);
   this.bitrate = bitrates[0]; // 保存需要切换的码率。
  })
  // 监听码率设置是否生效。
  this.avPlayer.on('bitrateDone', (bitrate: number) => {
   console.info('bitrateDone called, and bitrate value is: ' + bitrate);
  })
  * */
 // 情况六:DASH切换音视频轨道。
 /*
  this.avPlayer.url = "http://poster-inland.hwcloudtest.cn/AiMaxEngine/ProductionEnvVideo/DASH_SDR_MultiAudio_MultiSubtitle_yinHeHuWeiDui3/DASH_SDR_MultiAudio_MultiSubtitle_yinHeHuWeiDui3.mpd";
  //
  this.avPlayer.getTrackDescription((error: BusinessError, arrList: Array) => {
   if (arrList != null) {
    for (let i = 0; i < arrList.length; i++) {
          let propertyIndex: Object = arrList[i][media.MediaDescriptionKey.MD_KEY_TRACK_INDEX];
          let propertyType: Object = arrList[i][media.MediaDescriptionKey.MD_KEY_TRACK_TYPE];
          let propertyWidth: Object = arrList[i][media.MediaDescriptionKey.MD_KEY_WIDTH];
          let propertyHeight: Object = arrList[i][media.MediaDescriptionKey.MD_KEY_HEIGHT];
          if (propertyType == media.MediaType.MEDIA_TYPE_VID && propertyWidth == 1920 && propertyHeight == 1080) {
            this.videoTrackIndex = parseInt(propertyIndex.toString()); // 获取1080p视频轨道索引。
          }
        }
      } else {
        console.error(`getTrackDescription fail, error:${error}`);
      }
    });
    * */
  }
  // HLS切换码率。
  changeBitrate(bitrate: number) {
    if (this.avPlayer == null) {
      return;
    }
    // 设置播放码率。
    try {
      this.avPlayer.setBitrate(bitrate);
    } catch (error) {
      console.error(`${this.tag}: setBitrate failed, error message is = ${JSON.stringify(error.message)}`);
    }
  }
  // DASH切换音视频轨道。
  changeTrack(track: number) {
    if (this.avPlayer == null) {
      return;
    }
    // 切换至目标视频轨道。
    try {
      this.avPlayer.selectTrack(track);
    } catch (error) {
      console.error(`${this.tag}: selectTrack failed, error message is = ${JSON.stringify(error.message)}`);
    }
    // 取消选择目标视频轨道。
    /*
    try {
      this.avPlayer.deselectTrack(track);
    } catch (error) {
      console.error(`${this.tag}: deselectTrack failed, error message is = ${JSON.stringify(error.message)}`);
    }
    * */
  }
  avPlay(): void {
    if (this.avPlayer) {
      try {
        this.avPlayer.play();
      } catch (e) {
        console.error(`${this.tag}: avPlay = ${JSON.stringify(e)}`);
      }
    }
  }
  avPause(): void {
    if (this.avPlayer) {
      try {
        this.avPlayer.pause();
        console.info(`${this.tag}: avPause==`);
      } catch (e) {
        console.error(`${this.tag}: avPause== ${JSON.stringify(e)}`);
      }
    }
  }
  async avSeek(seekTime: number, mode: SliderChangeMode): Promise {
 if(this.avPlayer) {
  try{
    console.info(`${this.tag}: videoSeek seekTime== ${seekTime}`);
   this.avPlayer.seek(seekTime,2);
   this.currentTime = seekTime;
   }catch(e) {
    console.error(`${this.tag}: videoSeek== ${JSON.stringify(e)}`);
   }
  }
 }
 avSetSpeed(speed: number): void {
 if(this.avPlayer) {
  try{
   this.avPlayer.setSpeed(speed);
    console.info(`${this.tag}: avSetSpeedenum${speed}`);
   }catch(e) {
    console.error(`${this.tag}: avSetSpeed == ${JSON.stringify(e)}`);
   }
  }
 }
// 注册avplayer回调函数。
 async setAVPlayerCallback(callback: (avPlayer: media.AVPlayer) => void, vType?: number): Promise {
 // seek操作结果回调函数。
 if(this.avPlayer ==null) {
   console.error(`${this.tag}: avPlayer has notinit!`);
  return;
  }
 this.avPlayer.on('seekDone', (seekDoneTime) => {
   console.info(`${this.tag}: setAVPlayerCallback AVPlayer seek succeeded, seek timeis${seekDoneTime}`);
  });
 this.avPlayer.on('speedDone', (speed) => {
   console.info(`${this.tag}: setAVPlayerCallback AVPlayer speedDone, speedis${speed}`);
  });
 // error回调监听函数,当avPlayer在操作过程中出现错误时调用reset接口触发重置流程。
 this.avPlayer.on('error', (err) => {
   console.error(`${this.tag}: setAVPlayerCallback Invoke avPlayer failed ${JSON.stringify(err)}`);
  if(this.avPlayer ==null) {
    console.error(`${this.tag}: avPlayer has notiniton error`);
   return;
   }
  this.avPlayer.reset();
  });
 // 状态机变化回调函数。
 this.avPlayer.on('stateChange', async (state, reason) => {
  if(this.avPlayer ==null) {
    console.info(`${this.tag}: avPlayer has notiniton state change`);
   return;
   }
   switch (state) {
    case'idle':// 成功调用reset接口后触发该状态机上报。
     console.info(`${this.tag}: setAVPlayerCallback AVPlayer state idle called.`);
    break;
    case'initialized':// avplayer 设置播放源后触发该状态上报。
     console.info(`${this.tag}: setAVPlayerCallback AVPlayer state initialized called.`);
    if(this.surfaceId) {
     this.avPlayer.surfaceId =this.surfaceId;// 设置显示画面,当播放的资源为纯音频时无需设置。
      console.info(`${this.tag}: setAVPlayerCallbackthis.avPlayer.surfaceId = ${this.avPlayer.surfaceId}`);
     this.avPlayer.prepare();
     }
    break;
    case'prepared':// prepare调用成功后上报该状态机。
     console.info(`${this.tag}: setAVPlayerCallback AVPlayer state prepared called.`);
    this.avPlayer.on('bufferingUpdate', (infoType: media.BufferingInfoType, value: number) => {
      console.info(`${this.tag}: bufferingUpdate called, infoType value: ${infoType}, value:${value}}`);
     })
    this.durationTime =this.avPlayer.duration;
    this.currentTime =this.avPlayer.currentTime;
    this.avPlayer.play();// 调用播放接口开始播放。
     console.info(`${this.tag}:
      setAVPlayerCallback speedSelect: ${this.speedSelect}, duration: ${this.durationTime}`);
    if(this.speedSelect != -1) {
      switch (this.speedSelect) {
       case SPEED_ZERO:
       this.avSetSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_00_X);
       break;
       case SPEED_ONE:
       this.avSetSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_25_X);
       break;
       case SPEED_TWO:
       this.avSetSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_75_X);
       break;
       case SPEED_THREE:
       this.avSetSpeed(media.PlaybackSpeed.SPEED_FORWARD_2_00_X);
       break;
      }
     }
     callback(this.avPlayer);
    break;
    case'playing':// play成功调用后触发该状态机上报。
     console.info(`${this.tag}: setAVPlayerCallback AVPlayer state playing called.`);
    if(this.intervalID != -1) {
      clearInterval(this.intervalID)
     }
    this.intervalID = setInterval(() => {// 更新当前时间。
      AppStorage.setOrCreate('durationTime',this.durationTime);
      AppStorage.setOrCreate('currentTime',this.currentTime);
     },100);
     let eventDataTrue: emitter.EventData = {
     data: {
      'flag':true
      }
     };
     let innerEventTrue: emitter.InnerEvent = {
      eventId:2,
      priority: emitter.EventPriority.HIGH
     };
     emitter.emit(innerEventTrue, eventDataTrue);
    break;
    case'completed':// 播放结束后触发该状态机上报。
     console.info(`${this.tag}: setAVPlayerCallback AVPlayer state completed called.`);
     let eventDataFalse: emitter.EventData = {
     data: {
      'flag':false
      }
     };
     let innerEvent: emitter.InnerEvent = {
      eventId:1,
      priority: emitter.EventPriority.HIGH
     };
     emitter.emit(innerEvent, eventDataFalse);
    if(this.intervalID != -1) {
      clearInterval(this.intervalID)
     }
    this.avPlayer.off('bufferingUpdate')
     AppStorage.setOrCreate('currentTime',this.durationTime);
    break;
    case'released':
     console.info(`${this.tag}: setAVPlayerCallback released called.`);
    break
    case'stopped':
     console.info(`${this.tag}: setAVPlayerCallback AVPlayer state stopped called.`);
    break
    case'error':
     console.error(`${this.tag}: setAVPlayerCallback AVPlayer state error called.`);
    break
    case'paused':
     console.info(`${this.tag}: setAVPlayerCallback AVPlayer state paused called.`);
    break
    default:
     console.info(`${this.tag}: setAVPlayerCallback AVPlayer state unknown called.`);
    break;
   }
  });
 // 时间上报监听函数。
 this.avPlayer.on('timeUpdate', (time: number) => {
  this.currentTime = time;
  });
 }
 aboutToAppear() {
 this.windowWidth = display.getDefaultDisplaySync().width;
 this.windowHeight = display.getDefaultDisplaySync().height;
 if(this.percent >=1) {// 横向视频。
  this.surfaceW = Math.round(this.windowWidth * PROPORTION);
  this.surfaceH = Math.round(this.surfaceW /this.percent);
  }else{// 纵向视频。
  this.surfaceH = Math.round(this.windowHeight * PROPORTION);
  this.surfaceW = Math.round(this.surfaceH *this.percent);
  }
 this.isPaused =true;
 this.context =this.getUIContext().getHostContext();
 }
 aboutToDisappear() {
 if(this.avPlayer ==null) {
   console.info(`${this.tag}: avPlayer has notinitaboutToDisappear`);
  return;
  }
 this.avPlayer.release((err) => {
  if(err ==null) {
    console.info(`${this.tag}: videoRelease release success`);
   }else{
    console.error(`${this.tag}: videoRelease release failed, error messageis= ${JSON.stringify(err.message)}`);
   }
  });
  emitter.off(innerEventFalse.eventId);
 }
 onPageHide() {
 this.avPause();
 this.isPaused =false;
 }
 onPageShow() {
  emitter.on(innerEventTrue, (res: emitter.EventData) => {
  if(res.data) {
   this.isPaused = res.data.flag;
   this.XComponentFlag = res.data.flag;
   }
  });
  emitter.on(innerEventFalse, (res: emitter.EventData) => {
  if(res.data) {
   this.isPaused = res.data.flag;
   }
  });
  emitter.on(innerEventWH, (res: emitter.EventData) => {
  if(res.data) {
   this.windowWidth = res.data.width;
   this.windowHeight = res.data.height;
   this.setVideoWH();
   }
  });
 }
 setVideoWH(): void {
 if(this.percent >=1) {// 横向视频。
  this.surfaceW = Math.round(this.windowWidth * PROPORTION);
  this.surfaceH = Math.round(this.surfaceW /this.percent);
  }else{// 纵向视频。
  this.surfaceH = Math.round(this.windowHeight * PROPORTION);
  this.surfaceW = Math.round(this.surfaceH *this.percent);
  }
 }
@Builder
 CoverXComponent() {
 // ...
 }
 build() {
 // ...
 }
}

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 流媒体
    +关注

    关注

    1

    文章

    200

    浏览量

    17152
  • avplayer
    +关注

    关注

    0

    文章

    5

    浏览量

    1035
  • HarmonyOS
    +关注

    关注

    80

    文章

    2146

    浏览量

    35571

原文标题:【HarmonyOS-媒体技术-AVPlayer】手把手教你用 AVPlayer 实现流媒体播放(ArkTS 详解)

文章出处:【微信号:HarmonyOS_Dev,微信公众号:HarmonyOS开发者】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    基于开源鸿蒙的AVPlayer视频播控开发样例

    开源鸿蒙生态建设中,多媒体能力是构建丰富用户体验的核心要素。本开发样例基于AVPlayer实现,AvPlayer支持流媒体和本地资源解析、
    的头像 发表于 08-21 10:22 2358次阅读
    基于开源鸿蒙的<b class='flag-5'>AVPlayer</b>视频播控开发样例

    鸿蒙开发-视频播放器方案

    HarmonyOS系统中,提供两种视频播放开发的方案: [AVPlayer]:功能较完善的音视频播放ArkTS/JS API,集成了
    发表于 02-19 17:20

    USB MP4流媒体带来的好处

    USB MP4流媒体带来的好处什么是流媒体呢?从硬件角度讲是指一些便携的,播放时不占用播放设备内存,可即时播放的数码设备,例如U盘、MP3、
    发表于 05-24 18:19

    基于流媒体技术的手机视频播放系统的研究与实现

    应用。根据多个市场调查来看,无线流媒体业务己经或者即将成为各大无线营运商的新的业务成长点,用户数将逐年飞速的递增。所以,手机端的流媒体播放器越来越成为新一代手机里面必备的软件之一。本人的主要工作如下:1)综合
    发表于 04-24 09:24

    嵌入式Linux机顶盒流媒体播放器的设计流程是什么?

    、数字化、操作简单的基于计算机网络通讯技术和多媒体应用的网络化流媒体播放器已成为计算机、通信、消费电子产品领域(3C 产业-Computer、Communication、Consumer Electronics)技术发展的主要方向之一。
    发表于 08-22 06:56

    HarmonyOS HiSpark AI Camera】流媒体后视镜

    项目名称:流媒体后视镜试用计划:申请理由本人在车机应用开发领域有五年多的学习和开发经验,曾设计过车机端中控和仪表应用层的开发,对想借助发烧友论坛学习华为海思Hi3516DV300芯片实现流媒体后视镜
    发表于 11-19 20:50

    如何去实现一种嵌入式流媒体播放器的设计?

    一种基于PXA270平台的嵌入式流媒体播放器设计
    发表于 06-04 06:45

    什么是流媒体服务器?

    介绍一下什么是流媒体服务器。  其实流媒体服务器从广义上来说,是属于视频服务器的一种。它主要是将视频或者音频文件进行数据压缩,然后存储等,远程监控及视频应用方面,流媒体服务器都有广泛
    发表于 06-30 09:28

    流媒体播放器QT4.8.5,如何安装phonon呢?

    如题,我需要一款流媒体播放器,看其它帖子qt4.8.5推荐用phonon,但是提供的qt中没有
    发表于 11-28 07:41

    HarmonyOS音频开发指导:使用AVPlayer开发音频播放功能

    播放API,有助于降低开发工作量,实现更佳的音频播放效果。 ● ​​AVPlayer​​:功能较完善的音频、视频播放ArkTS/JS API,集成了
    发表于 10-19 14:26

    基于Directshow的H.264流媒体播放器设计

    H.264视频编解码标准具有高压缩比和优良的网络亲和性,被普遍认为是最有影响力的流媒体视频压缩标准。将Direct-show和H.264两种相结合的流媒体播放器无疑将具有非常优秀的性能
    发表于 03-11 11:36 5814次阅读
    基于Directshow的H.264<b class='flag-5'>流媒体播放</b>器设计

    Symbian平台上实现流媒体播放

    现有基于Symbian OS 的多媒体播放器的相关文献中,讨论了基于Symbian 平台的流媒体播放器移动客户端的设计原理,给出了指导性意见,并在结构、缓冲等方面给出了优化建议,在此基础
    发表于 09-29 15:56 2062次阅读
    Symbian平台上实现<b class='flag-5'>流媒体播放</b>器

    嵌入式流媒体播放系统的设计与实现

    基于推广3G流媒体服务的目的,介绍流媒体工作原理的基础之上,通过设计嵌入式播放终端支持流媒体播放
    发表于 11-03 16:09 61次下载

    IPTV机顶盒的流媒体播放器设计

    介绍了IPTV 机顶盒流媒体播放器的设计过程 ,组成了 IPTV 机顶盒的流媒体播放器。该播放器经测试 ,性能稳定。
    发表于 02-20 10:25 2541次阅读
    IPTV机顶盒的<b class='flag-5'>流媒体播放</b>器设计

    流媒体同步播放器ActiveX控件解析

    目前视频播放器很多,可以播放各种各样的文件和流,但大多只支持一个文件或一个流播放,若要播放多个文件就需手工打开多个播放器。
    发表于 11-01 11:10 0次下载
    多<b class='flag-5'>流媒体</b>同步<b class='flag-5'>播放</b>器ActiveX控件解析