## 阅读对象

本文档部分内容为腾讯云专属能力，使用前请开通 [腾讯云](https://cloud.tencent.com/) 相关服务，未注册用户可注册账号 [免费试用](https://cloud.tencent.com/login)。

## 通过本文你可以学会
* 如何集成腾讯云 Flutter 播放器SDK
* 如何使用播放器 SDK 进行点播播放
* 如何使用播放器 SDK 底层能力实现更多功能

## 基础知识
本文主要介绍视频云 SDK 的点播播放功能，在此之前，先了解如下一些基本知识会大有裨益：

- **直播和点播**
  直播（LIVE）的视频源是主播实时推送的。因此，主播停止推送后，播放端的画面也会随即停止，而且由于是实时直播，所以播放器在播直播 URL 的时候是没有进度条的。

点播（VOD）的视频源是云端的一个视频文件，只要未被从云端移除，视频就可以随时播放， 播放中您可以通过进度条控制播放位置，腾讯视频和优酷土豆等视频网站上的视频观看就是典型的点播场景。

- **协议的支持**
  通常使用的点播协议如下，现在比较流行的是 HLS（以“http”打头，以“.m3u8”结尾）的点播地址：
  ![](https://mc.qcloudimg.com/static/img/4b42a00bb7ce2f58f362f35397734177/image.jpg)

## 特别说明
视频云 SDK **不会对播放地址的来源做限制**，即您可以用它来播放腾讯云或非腾讯云的播放地址。但视频云 SDK 中的播放器只支持 FLV 、RTMP 和 HLS（m3u8）三种格式的直播地址，以及 MP4、HLS（m3u8）和 FLV 三种格式的点播地址。

## SDK集成[](id:stepone)

### 步骤1：集成SDK开发包[](id:step1)

下载和集成SDK开发包，请参考[集成指引](./集成指引.md)。

### 步骤2：创建controller[](id:step2)

```dart
TXVodPlayerController _controller = TXVodPlayerController();
```

### 步骤3：设置监听事件[](id:step3)

```dart
// 监听视频宽高变化，设置合适的宽高比例,也可自行设置宽高比例，视频纹理也会根据比例进行相应拉伸
_controller.onPlayerNetStatusBroadcast.listen((event) async {
  double w = (event["VIDEO_WIDTH"]).toDouble();
  double h = (event["VIDEO_HEIGHT"]).toDouble();

  if (w > 0 && h > 0) {
    setState(() {
      _aspectRatio = 1.0 * w / h;
    });
  }
});
```

### 步骤4：添加布局[](id:step4)
```dart
@override
Widget build(BuildContext context) {
return Container(
  decoration: BoxDecoration(
      image: DecorationImage(
        image: AssetImage("images/ic_new_vod_bg.png"),
        fit: BoxFit.cover,
      )),
  child: Scaffold(
      backgroundColor: Colors.transparent,
      appBar: AppBar(
        backgroundColor: Colors.transparent,
        title: const Text('点播'),
      ),
      body: SafeArea(
          child: Container(
            height: 150,
            color: Colors.black,
            child: Center(
              child: _aspectRatio > 0
                  ? AspectRatio(
                aspectRatio: _aspectRatio,
                child: TXPlayerVideo(controller: _controller),
              ) : Container(),
            ),
          ))));
}
```

### 步骤5：播放器初始化[](id:step5)

```dart
// 初始化播放器，分配共享纹理
await _controller.initialize();
```

### 步骤6：启动播放[](id:step6)
::: 通过url方式
TXVodPlayerController 内部会自动识别播放协议，您只需要将您的播放 URL 传给 startVodPlay 函数即可。
```dart
// 播放视频资源
String _url =
    "http://1400329073.vod2.myqcloud.com/d62d88a7vodtranscq1400329073/59c68fe75285890800381567412/adp.10.m3u8";
await _controller.startVodPlay(_url);
```
:::
::: 通过field方式
```dart
// 通过fileId播放必须填写 psign， psign 即播放器签名，签名介绍和生成方式参见链接：https://cloud.tencent.com/document/product/266/42436
TXPlayInfoParams params = TXPlayInfoParams(appId: 1252463788,
        fileId: "4564972819220421305", psign: "psignxxxxxxx");
await _controller.startVodPlayWithParams(params);
```
在 [媒资管理](https://console.cloud.tencent.com/vod/media) 找到对应的视频文件。在文件名下方可以看到 FileId。

通过 FileId 方式播放，播放器会向后台请求真实的播放地址。如果此时网络异常或 FileId 不存在，则会收到`TXLiveConstants.PLAY_ERR_GET_PLAYINFO_FAIL`事件，反之收到`TXLiveConstants.PLAY_EVT_GET_PLAYINFO_SUCC`表示请求成功。
:::
</dx-tabs>

### 步骤7：结束播放[](id:step7)
结束播放时**记得调用controller的销毁方法**，尤其是在下次 startVodPlay 之前，否则可能会产生大量的内存泄露以及闪屏问题。
```dart
@override
void dispose() {
  _controller.dispose();
  super.dispose();
}
```

## 基础功能使用

### 1、播放控制

#### 开始播放

```dart
// 开始播放
_controller.startVodPlay(url)
```

#### 暂停播放

```dart
// 暂停播放
_controller.pause();
```

#### 恢复播放

```dart
// 恢复播放
_controller.resume();
```

#### 结束播放

```dart
// 结束播放
_controller.stopPlay(true);
```

#### 结束播放器

```dart
// 释放controller
_controller.dispose();
```

#### 调整进度（Seek）

当用户拖拽进度条时，可调用 seek 从指定位置开始播放，播放器 SDK 支持精准 seek。

```dart
double time = 600; // double，单位为 秒
// 调整进度
_controller.seek(time);
```

#### 从指定时间开始播放

首次调用 startVodPlay 之前，支持从指定时间开始播放。

```dart
double startTimeInSecond = 60; // 单位：秒
_controller.setStartTime(startTimeInSecond);   // 设置开始播放时间
_controller.startVodPlay(url);
```

### 2、变速播放

点播播放器支持变速播放，通过接口`setRate`设置点播播放速率来完成，支持快速与慢速播放，如0.5X、1.0X、1.2X、2X等。

```dart
// 设置1.2倍速播放
_controller.setRate(1.2); 
```

### 3、循环播放

```dart
// 设置循环播放
_controller.setLoop(true);
// 获取当前循环播放状态
_controller.isLoop(); 
```

### 4、静音设置

```dart
// 设置静音，true 表示开启静音， false 表示关闭静音
_controller.setMute(true);
```

### 5 、贴片广告

播放器SDK支持在界面添加图片贴片，用于广告宣传等。实现方式如下：

* 将`autoPlay`为 NO，此时播放器会正常加载，但视频不会立刻开始播放。
* 在播放器加载出来后、视频尚未开始时，即可在播放器界面查看图片贴片广告。
* 待达到广告展示结束条件时，使用resume接口启动视频播放。

```dart
_controller.setAutoPlay(false);  // 设置为非自动播放
_controller.startVodPlay(url);    // startVodPlay 后会加载视频，加载成功后不会自动播放
// ......
// 在播放器界面上展示广告
// ......  
_controller.resume();  // 广告展示完调用 resume 开始播放视频
```

### 8、HTTP-REF

TXVodPlayConfig 中的 headers 可以用来设置 HTTP 请求头，例如常用的防止 URL 被到处拷贝的 Referer 字段（腾讯云可以提供更加安全的签名防盗链方案），以及用于验证客户端身份信息的 Cookie 字段。

```dart
FTXVodPlayConfig playConfig = FTXVodPlayConfig();
Map<String, String> httpHeaders = {'Referer': 'Referer Content'};
playConfig.headers = httpHeaders;
_controller.setConfig(playConfig);
```

### 9、硬件加速

对于蓝光级别（1080p）的画质，简单采用软件解码的方式很难获得较为流畅的播放体验，所以如果您的场景是以游戏直播为主，一般都推荐开启硬件加速。

软解和硬解的切换需要在切换之前先 **stopPlay**，切换之后再 **startVodPlay**，否则会产生比较严重的花屏问题。

```dart
 _controller.stopPlay(true);
 _controller.enableHardwareDecode(true); 
 _controller.startVodPlay(url);
```

### 10、清晰度设置

SDK 支持 HLS 的多码率格式，方便用户切换不同码率的播放流，从而达到播放不同清晰的目标。在收到 PLAY_EVT_PLAY_BEGIN 事件后，可以通过下面方法进行清晰度设置。

```dart
List _supportedBitrates = (await _controller.getSupportedBitrates())!;; //获取多码率数组
int index = _supportedBitrates[i];  // 指定要播的码率下标
_controller.setBitrateIndex(index);  // 切换码率到想要的清晰度
```

在播放过程中，可以随时通过`_controller.setBitrateIndex(int)`切换码率。切换过程中，会重新拉取另一条流的数据，SDK 针对腾讯云的多码率文件做过优化，可以做到切换无卡顿。

### 11、码流自适应

SDK 支持 HLS 的多码流自适应，开启相关能力后播放器能够根据当前带宽，动态选择最合适的码率播放。在收到 PLAY_EVT_PLAY_BEGIN 事件后，可以通过下面方法开启码流自适应。

```dart
_controller.setBitrateIndex(-1); //index 参数传入-1
```

在播放过程中，可以随时通过 `_controller.setBitrateIndex(int)` 切换其它码率，切换后码流自适应也随之关闭。

### 12、开启平滑切换码率

在启动播放前，通过开启平滑切换码率，在播放过程中切换码率，可以达到无缝平滑切换不同清晰度。对比关闭平滑切换码率，切换过程比较耗耗时、体验更好，可以根据需求进行设置。

```dart
FTXVodPlayConfig playConfig = FTXVodPlayConfig();
/// 设为true，可平滑切换码率, 设为false时，可提高多码率地址打开速度
playConfig.smoothSwitchBitrate = true;
_controller.setConfig(playConfig);
```

### 13、播放进度监听

点播播放中的进度信息分为2种：**加载进度**和**播放进度**，SDK 目前是以事件通知的方式将这两个进度实时通知出来的。

通过`onPlayerEventBroadcast`接口监听播放器事件，进度通知会通过 **PLAY_EVT_PLAY_PROGRESS** 事件回调到您的应用程序。

```dart
_controller.onPlayerEventBroadcast.listen((event) async {
  if(event["event"] == TXVodPlayEvent.PLAY_EVT_PLAY_PROGRESS) {// 更多详细请查看iOS或者安卓原生SDK状态码
    // 可播放时长，即加载进度, 单位是毫秒
    double playableDuration = event[TXVodPlayEvent.EVT_PLAYABLE_DURATION_MS].toDouble();
    // 播放进度, 单位是秒
    int progress = event[TXVodPlayEvent.EVT_PLAY_PROGRESS].toInt();
    // 视频总长, 单位是秒
    int duration = event[TXVodPlayEvent.EVT_PLAY_DURATION].toInt();
  }
});
```

### 14、播放网速监听

通过`onPlayerNetStatusBroadcast`接口监听播放器的网络状态，如： `NET_STATUS_NET_SPEED`。

```dart
_controller.onPlayerNetStatusBroadcast.listen((event) {
	(event[TXVodNetEvent.NET_STATUS_NET_SPEED]).toDouble();
});
```

### 15、获取视频分辨率

播放器 SDK 通过 URL 字符串播放视频，URL 中本身不包含视频信息。为获取相关信息，需要通过访问云端服务器加载到相关视频信息，因此 SDK 只能以事件通知的方式将视频信息发送到您的应用程序中.

**可以通过下面两种方法获取分辨率信息**

方法1：通过`onPlayerNetStatusBroadcast`的`NET_STATUS_VIDEO_WIDTH`和`NET_STATUS_VIDEO_HEIGHT`获取视频的宽和高

方法2：在收到播放器的PLAY_EVT_VOD_PLAY_PREPARED 事件回调后，直接调用 `getWidth()`和`getHeight()` 获取当前宽高。

```dart
 _controller.onPlayerNetStatusBroadcast.listen((event) {
  double w = (event[TXVodNetEvent.NET_STATUS_VIDEO_WIDTH]).toDouble();
  double h = (event[TXVodNetEvent.NET_STATUS_VIDEO_HEIGHT]).toDouble();
});

// 获取视频宽高，需要在收到播放器的PLAY_EVT_VOD_PLAY_PREPARED 事件回调后才返回值
_controller.getWidth();
_controller.getHeight();
```

### 16、播放缓冲大小

在视频正常播放时，控制提前从网络缓冲的最大数据大小。如果不配置，则走播放器默认缓冲策略，保证流畅播放。

```dart
FTXVodPlayConfig playConfig = FTXVodPlayConfig();
playConfig.maxBufferSize = 10;  ///  播放时最大缓冲大小。单位：MB
_controller.setConfig(playConfig);
```

### 17、视频本地缓存[](id:cache)

在短视频播放场景中，视频文件的本地缓存是很刚需的一个特性，对于普通用户而言，一个已经看过的视频再次观看时，不应该再消耗一次流量。

- **格式支持：**SDK 支持 HLS(m3u8) 和 MP4 两种常见点播格式的缓存功能。
- **开启时机：**SDK 并不默认开启缓存功能，对于用户回看率不高的场景，也并不推荐您开启此功能。
- **开启方式：**全局生效，在使用播放器开启。开启此功能需要配置两个参数：本地缓存目录及缓存大小。

```dart
//设置播放引擎的全局缓存目录和缓存大小，//单位MB
SuperPlayerPlugin.setGlobalMaxCacheSize(200);
//设置播放引擎的全局缓存目录
SuperPlayerPlugin.setGlobalCacheFolderPath("postfixPath");
```

##  高级功能使用

### 1、视频预播放

#### 步骤1：视频预播放使用

在短视频播放场景中，视频预播放功能对于流畅的观看体验很有帮助：在观看当前视频的同时，在后台加载即将要播放的下一个视频 ，这样一来，当用户真正切换到下一个视频时，已经不需要从头开始加载了，而是可以做到立刻播放。

预播放视频会有很好的秒开效果，但有一定的性能开销，如果业务同时有较多的视频预加载需求，建议结合 [视频预下载](#download) 一起使用。

这就是视频播放中无缝切换的背后技术支撑，您可以使用 TXVodPlayerController 中的 setAutoPlay 开关来实现这个功能，具体做法如下：
![](https://qcloudimg.tencent-cloud.cn/raw/f43ea6105d9f80c4162241ca0605b8f0.png)

```dart
// 播放视频 A: 如果将 autoPlay 设置为 true， 那么 startVodPlay 调用会立刻开始视频的加载和播放
String urlA = "http://1252463788.vod2.myqcloud.com/xxxxx/v.f10.mp4";
controller.setAutoPlay(isAutoPlay: true);
controller.startVodPlay(urlA);

// 在播放视频 A 的同时，预加载视频 B，做法是将 setAutoPlay 设置为 false
String urlB = "http://1252463788.vod2.myqcloud.com/xxxxx/v.f20.mp4";
controller.setAutoPlay(isAutoPlay: false);
controller.startVodPlay(urlB); // 不会立刻开始播放，而只会开始加载视频
```

等到视频 A 播放结束，自动（或者用户手动切换到）视频 B 时，调用 resume 函数即可实现立刻播放。

>! 设置了 autoPlay 为 false 之后，调用 resume 之前需要保证视频 B 已准备完成，即需要在监听到视频 B 的 PLAY_EVT_VOD_PLAY_PREPARED （2013 ，播放器已准备完成，可以播放）事件后调用。


```dart
controller.onPlayerEventBroadcast.listen((event) async {//订阅状态变化
  if(event["event"] == TXVodPlayEvent.PLAY_EVT_PLAY_END) {
    await _controller_A.stop();
    await _controller_B.resume();
  }
});
```

#### 步骤2：视频预播放缓冲配置

- 设置较大的缓冲可以更好的应对网络的波动，达到流畅播放的目的。
- 设置较小的缓冲可以帮助节省流量消耗。 

##### 预播放缓冲大小

此接口针对预加载场景（即在视频启播前，且设置 player 的 AutoPlay 为 false），用于控制启播前阶段的最大缓冲大小。

```dart
TXVodPlayConfig config = new TXVodPlayConfig();
config.setMaxPreloadSize(2);  // 预播放最大缓冲大小。单位：MB, 根据业务情况设置去节省流量
mVodPlayer.setConfig(config);  // 把config 传给 mVodPlayer
```

##### 播放缓冲大小 

在视频正常播放时，控制提前从网络缓冲的最大数据大小。如果不配置，则走播放器默认缓冲策略，保证流畅播放。

```dart
FTXVodPlayConfig config = FTXVodPlayConfig();
config.maxBufferSize = 10; // 播放时最大缓冲大小。单位：MB
_controller.setPlayConfig(config); // 把config 传给 controller
```

[](id:download)

### 2、视频预下载

不需要创建播放器实例，预先下载视频部分内容，使用播放器时，可以加快视频启播速度，提供更好的播放体验。

在使用播放服务前，请确保先设置好 [视频缓存](#cache)。

使用示例：

```dart
//设置播放引擎的全局缓存目录和缓存大小
SuperPlayerPlugin.setGlobalMaxCacheSize(200);
// 该缓存路径默认设置到app沙盒目录下，postfixPath只需要传递相对缓存目录即可，不需要传递整个绝对路径。
// Android 平台：视频将会缓存到sdcard的Android/data/your-pkg-name/files/testCache 目录。 
// iOS 平台：视频将会缓存到沙盒的Documents/testCache 目录。
SuperPlayerPlugin.setGlobalCacheFolderPath("postfixPath");

String palyrl = "http://****";
//启动预下载
int taskId = await TXVodDownloadController.instance.startPreLoad(palyrl, 3, 1920*1080,
  onCompleteListener:(int taskId,String url) {
    print('taskID=${taskId} ,url=${url}');
  }, onErrorListener: (int taskId, String url, int code, String msg) {
    print('taskID=${taskId} ,url=${url}, code=${code} , msg=${msg}');
  } 
);

//取消预下载
TXVodDownloadController.instance.stopPreLoad(taskId);
```

fileId预下载使用示例:

```dart
TXVodDownloadController.instance.startPreload(TXPlayInfoParams(appId: 0, fileId: "your fileId"), 1, 720 * 1080,
onStartListener: (taskId, fileId, url, params) {
  // TXVodDownloadController will call this block for callback taskId and videoInfo
},
onCompleteListener: (taskId, url) {
  // preDownload complete
},
onErrorListener: (taskId, url, code, msg) {
  // preDownload error
});
```

### 3、视频下载

视频下载支持用户在有网络的条件下下载视频，随后在无网络的环境下观看。同时播放器 SDK 提供本地加密能力，下载后的本地视频仍为加密状态，仅可通过指定播放器对视频进行解密播放，可有效防止下载后视频的非法传播，保护视频安全。

由于 HLS 流媒体无法直接保存到本地，因此也无法通过播放本地文件的方式实现 HLS 下载到本地后播放，对于该问题，您可以通过基于`TXVodDownloadController`的视频下载方案实现 HLS 的离线播放。

> -  `TXVodDownloadController` 暂不支持缓存 MP4 和 FLV 格式的文件，仅支持缓存非嵌套 HLS 格式文件。
> -  播放器 SDK 已支持 MP4 和 FLV 格式的本地文件播放。

[](id:offline1)

#### 步骤1：准备工作

`TXVodDownloadController`被设计为单例，因此您不能创建多个下载对象。用法如下：

```dart
// 该缓存路径默认设置到app沙盒目录下，postfixPath只需要传递相对缓存目录即可，不需要传递整个绝对路径。
// Android 平台：视频将会缓存到sdcard的Android/data/your-pkg-name/files/testCache 目录。 
// iOS 平台：视频将会缓存到沙盒的Documents/testCache 目录。
SuperPlayerPlugin.setGlobalCacheFolderPath("postfixPath");
```

[](id:offline2)

#### 步骤2:  开始下载

开始下载有 [Fileid](#fileid) 和 [URL](#url) 两种方式，具体操作如下：
<dx-tabs>

::: Fileid 方式[](id:fileid)
Fileid 下载至少需要传入 AppID、 Fileid 和 qualityId。带签名视频需传入 pSign，userName 不传入具体值时，默认为“default”。

**注意：加密视频只能通过Fileid下载，psign参数必须填写。**

```dart
// QUALITY_240P  240p
// QUALITY_360P  360P
// QUALITY_480P  480p
// QUALITY_540P  540p
// QUALITY_720P  720p
// QUALITY_1080P 1080p
// QUALITY_2K    2k
// QUALITY_4K    4k
// quality参数可以自定义，取分辨率宽高最小值(如分辨率为1280*720, 期望下载此分辨率的流，quality传入 QUALITY_720P)
// 播放器 SDK 会选择小于或等于传入分辨率的流进行下载
TXVodDownloadMedialnfo medialnfo = TXVodDownloadMedialnfo();
TXVodDownloadDataSource dataSource = TXVodDownloadDataSource();
dataSource.appId = 1252463788;
dataSource.fileId = "4564972819220421305";
dataSource.quality = DownloadQuality.QUALITY_480P;
dataSource.pSign = "pSignxxxx";
medialnfo.dataSource = dataSource;
TXVodDownloadController.instance.startDonwload(medialnfo);
```
:::

::: URL 方式[](id:url)
至少需要传入下载地址 URL，不支持嵌套 HLS 格式，仅支持单码流的HLS下载。userName 不传入具体值时，默认为"default"。

```dart
TXVodDownloadMedialnfo medialnfo = TXVodDownloadMedialnfo();
medialnfo.url = "http://1500005830.vod2.myqcloud.com/43843ec0vodtranscq1500005830/00eb06a88602268011437356984/video_10_0.m3u8";
TXVodDownloadController.instance.startDonwload(medialnfo);
```

:::

</dx-tabs>

[](id:offline3)

#### 步骤3：任务信息 

在接收任务信息前，需要先设置回调 listener。

```dart
TXVodDownloadController.instance.setDownloadObserver((event, info) {

}, (errorCode, errorMsg, info) {

});
```

可能收到的任务event事件有：

| 事件                                                  | 说明                                                         |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| EVENT_DOWNLOAD_START       | 任务开始，表示 SDK 已经开始下载                              |
| EVENT_DOWNLOAD_PROGRESS    | 任务进度，下载过程中，SDK 会频繁回调此接口，您可以通过`mediaInfo.getProgress()` 获取当前进度 |
| EVENT_DOWNLOAD_STOP        | 任务停止，当您调用 `stopDownload` 停止下载，收到此消息表示停止成功 |
| EVENT_DOWNLOAD_FINISH      | 下载完成，收到此回调表示已全部下载。此时下载文件可以给 TXVodPlayer 播放 |

当回调 downlodOnErrorListener 方法的时候，代表下载错误，下载过程中遇到网络断开会回调此接口，同时下载任务停止。

由于 downloader 可以同时下载多个任务，所以回调接口里带上了`TXVodDownloadMedialnfo`对象，您可以访问 URL 或 dataSource 判断下载源，同时还可以获取到下载进度、文件大小等信息。

[](id:offline4)

#### 步骤4：中断下载

停止下载请调用`TXVodDownloadController.instance.stopDownload()`方法，参数为开始下载传入的`TXVodDownloadMedialnfo`对象。**SDK 支持断点续传**，当下载目录没有发生改变时，下次下载同一个文件时会从上次停止的地方重新开始。


[](id:offline5)
#### 步骤5：管理下载

获取所有用户账户的下载列表信息, 也可获取指定用户账户的下载列表信息。

```dart
// 获取所有用户的下载列表信息
// 可根据下载信息中的 userName 区分不同用户的下载列表信息
List<TXVodDownloadMedialnfo> downloadInfoList = await TXVodDownloadController.instance.getDownloadList();
// 获取默认“default”用户已经下载完成的视频
List<TXVodDownloadMedialnfo> defaultUserDownloadList = [];
for(TXVodDownloadMedialnfo mediaInfo in downloadInfoList) {
  if("default" == mediaInfo.userName && mediaInfo.downloadState == TXVodPlayEvent.EVENT_DOWNLOAD_FINISH) {
    defaultUserDownloadList.add(mediaInfo);
  }
}
```

获取某个 Fileid 相关下载信息，包括当前下载状态，获取当前下载进度，判断是否下载完成等，需要传入 AppID、 Fileid 和 qualityId。

```dart
// 获取某个视频相关下载信息
TXVodDownloadMedialnfo medialnfo = TXVodDownloadMedialnfo();
medialnfo.dataSource = TXVodDownloadDataSource();
medialnfo.dataSource!.appId = 1500005830;
medialnfo.dataSource!.fileId = "8602268011437356984";
// fileId下载必须传入quality。quality也可以通过CommonUtils.getDownloadQualityBySize(width, height)来获取
medialnfo.dataSource!.quality = DownloadQuality.QUALITY_480P;
TXVodDownloadMedialnfo downloadInfo = await TXVodDownloadController.instance.getDownloadInfo(medialnfo);
int? duration = downloadInfo.duration;	// 获取总时长
int? playableDuration = downloadInfo.playableDuration; // 获取已下载的可播放时长
double? progress = downloadInfo.progress;	// 获取下载进度
String? playPath = downloadInfo.playPath; // 获取离线播放路径，传给播放器即可离线播放
int? downloadState = downloadInfo.downloadState; // 获取下载状态，具体参考STATE_xxx常量
```

获取某个 URL 相关下载信息，需要传入 URL 信息。目前url下载不支持嵌套m3u8和mp4下载。

```dart
TXVodDownloadMedialnfo medialnfo = TXVodDownloadMedialnfo();
medialnfo.url = "http://1253131631.vod2.myqcloud.com/26f327f9vodgzp1253131631/f4bdff799031868222924043041/playlist.m3u8";
TXVodDownloadController.instance.getDownloadInfo(medialnfo);
```

```dart
// 删除下载信息
bool result = await TXVodDownloadController.instance.deleteDownloadMediaInfo(medialnfo);
```


[](id:offline6)

#### 步骤6:  播放离线视频

通过以上步骤获取到的mediaInfo的downloadState为EVENT_DOWNLOAD_FINISH，并且mediaInfo的playPath有值，则代表获取视频缓存完成，可以直接传给controller进行播放，代码如下：

```dart
String cacheVideoUrl = cacheMediaInfo.playPath!;
vodPlayerController.startVodPlay(cacheVideoUrl);
```


### 4、加密播放

视频加密方案主要用于在线教育等需要对视频版权进行保护的场景。如果要对您的视频资源进行加密保护，就不仅需要在播放器上做改造，还需要对视频源本身进行加密转码，亦需要您的后台和终端研发工程师都参与其中。在 [视频加密解决方案](https://cloud.tencent.com/document/product/266/45552) 中您会了解到全部细节内容。

在腾讯云控制台提取到appId， 加密视频的fileId 和 psign后，可以通过下面的方式进行播放：

```dart
// 通过fileId播放必须填写 psign， psign 即播放器签名，签名介绍和生成方式参见链接：https://cloud.tencent.com/document/product/266/42436
TXPlayInfoParams params = TXPlayInfoParams(appId: 1252463788,
        fileId: "4564972819220421305", psign: "psignxxxxxxx");
_controller.startVodPlayWithParams(params);
```

### 5、播放器配置 

在调用 statPlay 之前可以通过 setConfig 对播放器进行参数配置，例如：设置播放器连接超时时间、设置进度回调间隔、设置缓存文件个数等配置，TXVodPlayConfig 支持配置的详细参数请单击 [基础配置接口](https://cloud.tencent.com/document/product/881/67113#.E5.9F.BA.E7.A1.80.E9.85.8D.E7.BD.AE.E6.8E.A5.E5.8F.A3) 了解。使用示例：

```dart
FTXVodPlayConfig config = FTXVodPlayConfig();
// 如果不配置preferredResolution，则在播放多码率视频的时候优先播放720 * 1280分辨率的码率
config.preferredResolution = 720 * 1280;
config.enableAccurateSeek = true;  // 设置是否精确 seek，默认 true
config.progressInterval = 200;  // 设置进度回调间隔，单位毫秒
config.maxBufferSize = 50;  // 最大预加载大小，单位 MB
_controller.setPlayConfig(config);
```

##### 启播时指定分辨率

播放 HLS 的多码率视频源，如果你提前知道视频流的分辨率信息，可以在启播前优先指定播放的视频分辨率。 播放器会查找小于或等于偏好分辨率的流进行启播，启播后没有必要再通过 setBitrateIndex 切换到需要的码流。

```dart
FTXVodPlayConfig config = FTXVodPlayConfig();
// 传入参数为视频宽和高的乘积(宽 *  高），可以自定义值传入，默认 720 * 1280
config.preferredResolution = 720 * 1280;
_controller.setPlayConfig(config);
```

##### 设置播放进度回调时间间隔

```dart
FTXVodPlayConfig config = FTXVodPlayConfig();
config.progressInterval = 200;  // 设置进度回调间隔，单位毫秒
_controller.setPlayConfig(config);
```

[](id:listening)

## 播放器事件监听

您可以通过 `TXVodPlayerController` 的 `onPlayerEventBroadcast` 来监听播放器的播放事件，来向您的应用程序同步信息。

### 播放事件通知（onPlayerEventBroadcast）


| 事件 ID                                   | 数值 | 含义说明                                                   |
| ----------------------------------------- | ---- | ---------------------------------------------------------- |
| PLAY\_EVT\_PLAY\_BEGIN                    | 2004 | 视频播放开始                                               |
| PLAY\_EVT\_PLAY\_PROGRESS                 | 2005 | 视频播放进度，会通知当前播放进度、加载进度 和总体时长      |
| PLAY\_EVT\_PLAY\_LOADING                  | 2007 | 视频播放 loading，如果能够恢复，之后会有 LOADING\_END 事件 |
| PLAY\_EVT\_VOD\_LOADING\_END              | 2014 | 视频播放 loading 结束，视频继续播放                        |
| VOD_PLAY_EVT_SEEK_COMPLETE | 2019 | Seek 完成，10.3版本开始支持                                |

#### 结束事件

| 事件 ID                 | 数值  | 含义说明                                               |
| :---------------------- | :---- | :----------------------------------------------------- |
| PLAY_EVT_PLAY_END       | 2006  | 视频播放结束                                           |
| PLAY_ERR_NET_DISCONNECT | -2301 | 网络断连,且经多次重连亦不能恢复,更多重试请自行重启播放 |
| PLAY_ERR_HLS_KEY        | -2305 | HLS 解密 key 获取失败                                  |

#### 警告事件

如下的这些事件您可以不用关心，它只是用来告知您 SDK 内部的一些事件。

| 事件 ID                           | 数值 | 含义说明                                                     |
| :-------------------------------- | :--- | :----------------------------------------------------------- |
| PLAY_WARNING_VIDEO_DECODE_FAIL    | 2101 | 当前视频帧解码失败                                           |
| PLAY_WARNING_AUDIO_DECODE_FAIL    | 2102 | 当前音频帧解码失败                                           |
| PLAY_WARNING_RECONNECT            | 2103 | 网络断连, 已启动自动重连 (重连超过三次就直接抛送 PLAY_ERR_NET_DISCONNECT 了) |
| PLAY_WARNING_HW_ACCELERATION_FAIL | 2106 | 硬解启动失败，采用软解                                       |

#### 连接事件

连接服务器的事件，主要用于测定和统计服务器连接时间：

| 事件 ID                    | 数值 | 含义说明                                                     |
| :------------------------- | :--- | :----------------------------------------------------------- |
| PLAY_EVT_VOD_PLAY_PREPARED | 2013 | 播放器已准备完成，可以播放。设置了 autoPlay 为 false 之后，需要在收到此事件后，调用 resume 才会开始播放 |
| PLAY_EVT_RCV_FIRST_I_FRAME | 2003 | 网络接收到首个可渲染的视频数据包（IDR）                      |


#### 画面事件

以下事件用于获取画面变化信息：

| 事件 ID                       | 数值 | 含义说明         |
| ----------------------------- | ---- | ---------------- |
| PLAY\_EVT\_CHANGE\_RESOLUTION | 2009 | 视频分辨率改变   |
| PLAY\_EVT\_CHANGE\_ROTATION   | 2011 | MP4 视频旋转角度 |

#### 视频信息事件

| 事件 ID                                    | 数值 | 含义说明             |
| :----------------------------------------- | :--- | :------------------- |
| PLAY_EVT_GET_PLAYINFO_SUCC | 2010 | 成功获取播放文件信息 |

如果通过 fileId 方式播放且请求成功（接口：startVodPlay(TXPlayerAuthBuilder authBuilder)），SDK 会将一些请求信息通知到上层。您可以在收到`TXLiveConstants.PLAY_EVT_GET_PLAYINFO_SUCC`事件后，解析 param 获取视频信息。

| 视频信息                                    | 含义说明                                          |
| ------------------------------------------- | ------------------------------------------------- |
| EVT\_PLAY\_COVER\_URL                       | 视频封面地址                                      |
| EVT\_PLAY\_URL                              | 视频播放地址                                      |
| EVT\_PLAY\_DURATION                         | 视频时长                                          |
| EVT_TIME                                    | 事件发生时间                                      |
| EVT_UTC_TIME                                | UTC 时间                                          |
| EVT_DESCRIPTION                             | 事件说明                                          |
| EVT_PLAY_NAME                               | 视频名称                                          |
| EVT_IMAGESPRIT_WEBVTTURL     | 雪碧图 web vtt 描述文件下载 URL，10.2版本开始支持 |
| EVT_IMAGESPRIT_IMAGEURL_LIST | 雪碧图图片下载URL，10.2版本开始支持               |
| EVT_DRM_TYPE                 | 加密类型，10.2版本开始支持                        |


通过 onPlayerEventBroadcast 获取视频播放过程信息示例：

```dart
_controller.onPlayerEventBroadcast.listen((event) async {
  if (event["event"] == TXVodPlayEvent.PLAY_EVT_PLAY_BEGIN || event["event"] == TXVodPlayEvent.PLAY_EVT_RCV_FIRST_I_FRAME) {
  // code ...
  } else if (event["event"] == TXVodPlayEvent.PLAY_EVT_PLAY_PROGRESS) {
  // code ...
  }
});
```

[](id:status)

### 播放状态反馈（onPlayerNetStatusBroadcast）

状态反馈每0.5秒都会被触发一次，目的是实时反馈当前的推流器状态，它就像汽车的仪表盘，可以告知您目前 SDK 内部的一些具体情况，以便您能对当前视频播放状态等有所了解。

<table>
<tr><th>评估参数</th><th>含义说明</th></tr>
<tr>
<td>NET_STATUS_CPU_USAGE</td><td>当前瞬时 CPU 使用率</td>
</tr><tr>
<td>NET_STATUS_VIDEO_WIDTH</td><td>视频分辨率 - 宽</td>
</tr><tr>
<td>NET_STATUS_VIDEO_HEIGHT</td><td>视频分辨率 - 高</td>
</tr><tr>
<td>NET_STATUS_NET_SPEED</td><td>当前的网络数据接收速度</td>
</tr><tr>
<td>NET_STATUS_VIDEO_FPS</td><td>当前流媒体的视频帧率</td>
</tr><tr>
<td>NET_STATUS_VIDEO_BITRATE</td><td>当前流媒体的视频码率，单位 kbps</td>
</tr><tr>
<td>NET_STATUS_AUDIO_BITRATE</td><td>当前流媒体的音频码率，单位 kbps</td>
</tr><tr>
<td>NET_STATUS_VIDEO_CACHE</td><td>缓冲区（jitterbuffer）大小，缓冲区当前长度为0，说明离卡顿就不远了</td>
</tr><tr>
<td>NET_STATUS_SERVER_IP</td><td>连接的服务器 IP</td>
</tr></table>

通过 onNetStatus 获取视频播放过程信息示例：

```dart
_controller.onPlayerNetStatusBroadcast.listen((event) async {
  int videoWidth = event[TXVodNetEvent.NET_STATUS_VIDEO_WIDTH];
});
```


### 视频播放状态反馈

视频播放状态会在每一次播放状态切换的时候进行通知。

事件通过枚举类TXPlayerState来传递事件

| 状态 | 含义   |
| ------ | ------ |
| paused | 暂停播放 |
| failed | 播放失败 |
| buffering | 缓冲中 |
| playing | 播放中 |
| stopped | 停止播放 |
| disposed | 控件释放了 |


通过 onPlayerState 获取视频播放状态示例：

```dart
_controller.onPlayerState.listen((val) { });
```

### 系统音量监听

为了方便监控视频播放音量，SDK在flutter层做了对原生层的音量变化通知进行了事件封装，可以直接通过 SuperPlayerPlugin 来监听当前设备的音量变化。

通过 onEventBroadcast 获取设备音量状态示例：

```dart
SuperPlayerPlugin.instance.onEventBroadcast.listen((event) {
  int eventCode = event["event"];
});
```

相关事件含义如下：

| 状态 | 值 | 含义   |
| ------ |------ | ------ |
| EVENT_VOLUME_CHANGED | 1 | 音量发生变化 |
| EVENT_AUDIO_FOCUS_PAUSE | 2 | 失去音量输出播放焦点，仅使用安卓 |
| EVENT_AUDIO_FOCUS_PLAY | 3 | 获得音量输出焦点，仅使用安卓 |

### 画中画事件监听

由于SDK使用的画中画是基于系统提供的画中画能力，进入画中画之后，提供了一系列通知来帮助用户对当前界面做响应的调整。

| 状态 | 值 | 含义   |
| ------ |------ | ------ |
| EVENT_PIP_MODE_ALREADY_ENTER | 1 | 已经进入画中画模式 |
| EVENT_PIP_MODE_ALREADY_EXIT | 2 | 已经退出画中画模式 |
| EVENT_PIP_MODE_REQUEST_START | 3 | 开始请求进入画中画模式 |
| EVENT_PIP_MODE_UI_STATE_CHANGED | 4 | pip UI状态发生变动，仅在android 31以上生效 |
| EVENT_IOS_PIP_MODE_RESTORE_UI | 5 | 重置UI，仅在IOS生效 |
| EVENT_IOS_PIP_MODE_WILL_EXIT | 6 | 将要退出画中画，仅在IOS生效 |

使用 onExtraEventBroadcast 监听画中画事件的示例如下：

```dart
SuperPlayerPlugin.instance.onExtraEventBroadcast.listen((event) {
  int eventCode = event["event"];
});
```









