提交 082fc31c authored 作者: kongdywang's avatar kongdywang

update docs and fix bug

上级 09e36fb3
差异被折叠。
......@@ -123,6 +123,14 @@ public class FTXDownloadManager implements MethodChannel.MethodCallHandler, ITXV
String fileId = call.argument("fileId");
TXVodDownloadMediaInfo mediaInfo = parseMediaInfoFromInfo(quality, videoUrl, appId, fileId);
result.success(buildMapFromDownloadMediaInfo(mediaInfo));
} else if (call.method.equals("deleteDownloadMediaInfo")) {
Integer quality = call.argument("quality");
String videoUrl = call.argument("url");
Integer appId = call.argument("appId");
String fileId = call.argument("fileId");
TXVodDownloadMediaInfo mediaInfo = parseMediaInfoFromInfo(quality, videoUrl, appId, fileId);
boolean deleteResult = TXVodDownloadManager.getInstance().deleteDownloadMediaInfo(mediaInfo);
result.success(deleteResult);
}
}
......
差异被折叠。
## 环境准备
- Flutter 2.0 及以上版本。
- Android 端开发:
- Android Studio 3.5及以上版本。
- App 要求 Android 4.1及以上版本设备。
- iOS 端开发:
- Xcode 11.0及以上版本。
- osx 系统版本要求 10.11 及以上版本
- 请确保您的项目已设置有效的开发者签名。
## example下载
可在 [example项目地址](https://github.com/LiteAVSDK/Player_Flutter) ,通过git或者源码下载的方式,将项目下载到本地。
### 项目运行
使用编译器打开项目,可以使用以下命令来获取flutter依赖包
```yaml
flutter packages get
```
### 集成视频播放 License
若您已获得相关 License 授权,需在 [腾讯云视立方控制台](https://console.cloud.tencent.com/vcube) 获取 License URL 和 License Key:
![](https://qcloudimg.tencent-cloud.cn/raw/9b4532dea04364dbff3e67773aab8c95.png)
若您暂未获得 License 授权,需先参见 [视频播放License](https://cloud.tencent.com/document/product/881/74588) 获取相关授权。
集成播放器前,需要 [注册腾讯云账户](https://cloud.tencent.com/login) ,注册成功后申请视频播放能力 License, 然后通过下面方式集成,建议在应用启动时进行。
如果没有集成 License,播放过程中可能会出现异常。
```dart
String licenceURL = ""; // 获取到的 licence url
String licenceKey = ""; // 获取到的 licence key
SuperPlayerPlugin.setGlobalLicense(licenceURL, licenceKey);
```
### 项目运行
相关环境配置准备好之后,可以使用编译器自带的运行能力,将项目打包运行到对应设备上。
也可以使用如下命令运行:
```shell
flutter run
```
然后根据命令提示进行操作。
### 运行常见问题
- 如果在编译运行过程中,flutter无法运行起来,可以使用如下命令,根据提示检查自己的环境配置:
```shell
flutter doctor
```
- 如果在IOS设备运行,提示找不到接口、方法等错误提示,可以在IOS项目目录下,使用以下命令更新依赖:
```shell
rm -rf Pods
rm -rf Podfile.lock
pod update
```
- 仅支持Android和iOS平台。另外:iOS端暂不支持在模拟器上运行播放视频,您需要iPhone真机运行。
......@@ -541,8 +541,8 @@ _controller.setConfig(config);
| progressInterval | int | Progress callback interval in ms. If it is not set, the SDK will call back the progress once every 0.5 seconds |
| maxBufferSize | int | Maximum size of playback buffer in MB. The setting will affect `playableDuration`. The greater the value, the more the data that is buffered in advance |
| maxPreloadSize | int | Maximum preload buffer size in MB |
| firstStartPlayBufferTime | int | Duration of the video data that needs to be loaded during the first buffering in ms. Default value: 100 ms |
| nextStartPlayBufferTime | int | Minimum buffered data size to stop buffering (secondary buffering for insufficient buffered data or progress bar drag buffering caused by `seek`) in ms. Default value: 250 ms |
| firststartVodPlayBufferTime | int | Duration of the video data that needs to be loaded during the first buffering in ms. Default value: 100 ms |
| nextstartVodPlayBufferTime | int | Minimum buffered data size to stop buffering (secondary buffering for insufficient buffered data or progress bar drag buffering caused by `seek`) in ms. Default value: 250 ms |
| overlayKey | String | HLS security hardening encryption and decryption key |
| overlayIv | String | HLS security hardening encryption and decryption IV |
| extInfoMap | Map | Some special configuration items |
......
## 环境准备
- Flutter 2.0 及以上版本。
- Android 端开发:
- Android Studio 3.5及以上版本。
- App 要求 Android 4.1及以上版本设备。
- iOS 端开发:
- Xcode 11.0及以上版本。
- osx 系统版本要求 10.11 及以上版本
- 请确保您的项目已设置有效的开发者签名。
## SDK 下载
腾讯云视立方 Flutter 播放器项目的地址是 [Player Flutter](https://github.com/LiteAVSDK/Player_Flutter)
## 快速集成
### 在项目的 pubspec.yaml 中添加依赖
支持基于LiteAVSDK Player 或Professional 版本集成,你可以根据项目需要进行集成。
1. 集成 LiteAVSDK_Player 版本最新版本,默认情况下也是集成此版本。在`pubspec.yaml`中增加配置:
```yaml
super_player:
git:
url: https://github.com/LiteAVSDK/Player_Flutter
path: Flutter
```
集成 LiteAVSDK_Professional 最新版本,则`pubspec.yaml`中配置改为:
```yaml
super_player:
git:
url: https://github.com/LiteAVSDK/Player_Flutter
path: Flutter
ref: Professional
```
如果需要集成指定播放器版本的SDK,可以指定通过ref 依赖的tag来指定到对应版本,如下所示:
```yaml
super_player:
git:
url: https://github.com/LiteAVSDK/Player_Flutter
path: Flutter
ref: release_player_v1.0.6
# release_player_v1.0.6 表示将集成Android端TXLiteAVSDK_Player_10.6.0.11182 版本,iOS端集成TXLiteAVSDK_Player_10.6.11821版本
```
更多归档的tag请参考 [release列表](https://github.com/LiteAVSDK/Player_Flutter/releases)
2. 集成之后,可以通过代码编辑器自带的UI界面来获取flutter依赖,也可以直接使用如下命令获取
```yaml
flutter packages get
```
3. 使用过程中,可以通过以下命令来更新现有flutter依赖:
```dart
flutter pub upgrade
```
### 添加原生配置
#### Android 端配置
1. 在 Android 的`AndroidManifest.xml`中增加如下配置:
```xml
<!--网络权限-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--存储-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
```
2. 确保 Android 目录下的 `build.gradle` 使用了mavenCenter,能够成功下载到依赖
```groovy
repositories {
mavenCentral()
}
```
3. 如果需要更新原生SDK依赖版本,可手动删除 Android 目录下的 `build` 文件夹,也可以使用如下命令强制刷新
```shell
./gradlew build
```
4. 如果需要使用 Android 画中画功能,需要集成 example 组件内 android 目录下的 `FTXFlutterPipActivity.java`,以确保画中画能力正常使用
#### iOS 端配置
注意:**iOS端目前暂不支持模拟器运行调试,建议在真机下进行开发调试**
1. 在 iOS 的`Info.plist`中增加如下配置:
```xml
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
```
2. iOS 原生采用`pod`方式进行依赖,编辑`podfile`文件,指定你的播放器 SDK 版本,默认集成的是 Player 版SDK。
```xml
pod 'TXLiteAVSDK_Player' //Player版
```
Professional 版 SDK 集成:
```
pod 'TXLiteAVSDK_Professional' //Professional版
```
如果不指定版本,默认会安装最新的`TXLiteAVSDK_Player`最新版本。
3. 部分情况下(如:发布了新版本),需要强制更新iOS播放器依赖,可以在iOS目录下使用如下命令进行更新:
```shell
rm -rf Pods
rm -rf Podfile.lock
pod update
```
## 集成视频播放 License
若您已获得相关 License 授权,需在 [腾讯云视立方控制台](https://console.cloud.tencent.com/vcube) 获取 License URL 和 License Key:
![](https://qcloudimg.tencent-cloud.cn/raw/9b4532dea04364dbff3e67773aab8c95.png)
若您暂未获得 License 授权,需先参见 [视频播放License](https://cloud.tencent.com/document/product/881/74588) 获取相关授权。
集成播放器前,需要 [注册腾讯云账户](https://cloud.tencent.com/login) ,注册成功后申请视频播放能力 License, 然后通过下面方式集成,建议在应用启动时进行。
如果没有集成 License,播放过程中可能会出现异常。
```dart
String licenceURL = ""; // 获取到的 licence url
String licenceKey = ""; // 获取到的 licence key
SuperPlayerPlugin.setGlobalLicense(licenceURL, licenceKey);
```
## 深度定制开发指引
腾讯云播放器 SDK Flutter 插件对原生播放器能力进行了封装, 如果您要进行深度定制开发,建议采用如下方法:
- 基于点播播放,接口类为`TXVodPlayerController` 或直播播放,接口类为`TXLivePlayerController`,进行定制开发,项目中提供了定制开发 Demo,可参考 example 工程里的`DemoTXVodPlayer``DemoTXLivePlayer`
- 播放器组件`SuperPlayerController` 对点播和直播进行了封装,同时提供了简单的 UI 交互, 由于此部分代码在 example 目录。如果您有对播放器组件定制化的需求,您可以进行如下操作:
把播放器组件相关的代码,代码目录:`exmple/lib/superplayer`,复制到您的项目中,进行定制化开发。
## 常见问题
1. iOS端运行,出现 `No visible @interface for 'TXLivePlayer' declares the selector 'startLivePlay:type:'`等类似找不到接口错误。
可以使用如下命令,更新IOS SDK:
```shell
rm -rf Pods
rm -rf Podfile.lock
pod update
```
2. 同时集成tencent_trtc_cloud 和 flutter 播放器出现SDK 或 符号冲突
常见异常日志:`java. lang.RuntimeException: Duplicate class com.tencent.liteav.TXLiteAVCode found in modules classes.jar`
此时需要集成flutter 播放器的 Professional 版本,让tencent_trtc_cloud 和 flutter 播放器共同依赖于同一个版的 LiteAVSDK_Professional。注意确保依赖的LiteAVSDK_Professional 的版本必须一样。
如:依赖Android 端TXLiteAVSDK_Professional_10.3.0.11196 和 iOS 端TXLiteAVSDK_Professional to 10.3.12231 版本,依赖声明如下:
```xml
tencent_trtc_cloud:2.3.8
super_player:
git:
url: https://github.com/LiteAVSDK/Player_Flutter
path: Flutter
ref: release_pro_v1.0.3.11196_12231
```
3. 需要同时使用多个播放器实例的时候,频繁切换播放视频,画面呈现模糊。
​ 在每个播放器组件容器销毁的时候,调用播放器的`dispose`方法,将播放器释放
4. 其余通用flutter依赖问题
- 执行`flutter doctor`命令检查运行环境,直到出现”No issues found!“。
- 执行`flutter pub get`确保所有依赖的组件都已更新成功。
## 更多功能
你可以通过运行项目中的example体验完整功能,[example运行指引](example运行指引.md)
播放器SDK官网提供了iOS、Android和Web 端的Demo体验,[请点击这里](https://cloud.tencent.com/document/product/881/20204)
......@@ -29,9 +29,22 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
fontSize: 16, color: Colors.grey
);
void aa() async {
// List<TXVodDownloadMedialnfo> downloadInfoList = await TXVodDownloadController.instance.getDownloadList();
// bool result = await TXVodDownloadController.instance.deleteDownloadMediaInfo(medialnfo);
}
@override
void initState() {
super.initState();
TXVodDownloadMedialnfo medialnfo = TXVodDownloadMedialnfo();
medialnfo.url = "http://1500005830.vod2.myqcloud.com/43843ec0vodtranscq1500005830/00eb06a88602268011437356984/video_10_0.m3u8";
TXVodDownloadController.instance.startDonwload(medialnfo);
_controller = SuperPlayerController(context);
FTXVodPlayConfig config = FTXVodPlayConfig();
// 如果不配置preferredResolution,则在播放多码率视频的时候优先播放720 * 1280分辨率的码率
......@@ -290,7 +303,7 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
@override
void dispose() {
// must invoke when page exit.
_controller.releasePlayer();
// _controller.releasePlayer();
simpleEventSubscription?.cancel();
// restore page brightness
SuperPlayerPlugin.restorePageBrightness();
......
......@@ -84,7 +84,8 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
}
});
// only register listen once
_pipSubscription = SuperPlayerPlugin.instance.onExtraEventBroadcast.listen((event) {
_pipSubscription =
SuperPlayerPlugin.instance.onExtraEventBroadcast.listen((event) {
int eventCode = event["event"];
if (eventCode == TXVodPlayEvent.EVENT_PIP_MODE_ALREADY_EXIT) {
// exit floatingMode
......@@ -130,7 +131,8 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
print('$eventCode');
}
});
_volumeSubscription = SuperPlayerPlugin.instance.onEventBroadcast.listen((event) {
_volumeSubscription =
SuperPlayerPlugin.instance.onEventBroadcast.listen((event) {
int eventCode = event["event"];
if (_isFloatingMode && _isPlaying) {
if (eventCode == TXVodPlayEvent.EVENT_AUDIO_FOCUS_PAUSE) {
......
......@@ -31,7 +31,6 @@
_eventSink = [FTXPlayerEventSinkQueue new];
_eventChannel = [FlutterEventChannel eventChannelWithName:@"cloud.tencent.com/txvodplayer/download/event" binaryMessenger:[registrar messenger]];
[_eventChannel setStreamHandler:self];
NSLog(@"dokie initWithRegistrar");
[[TXVodDownloadManager shareInstance] setDelegate:self];
// 设置下载存储路径
NSString *cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
......@@ -115,6 +114,14 @@
TXVodDownloadMediaInfo *mediaInfo = [self parseMediaInfoFromInfo:quality url:videoUrl appId:appIdNum fileId:fileId];
NSDictionary *resultDic = [self buildMapFromDownloadMediaInfo:mediaInfo];
result(resultDic);
} else if([@"deleteDownloadMediaInfo" isEqualToString:call.method]) {
NSNumber *quality = args[@"quality"];
NSString *videoUrl = args[@"url"];
NSNumber *appIdNum = args[@"appId"];
NSString *fileId = args[@"fileId"];
TXVodDownloadMediaInfo *mediaInfo = [self parseMediaInfoFromInfo:quality url:videoUrl appId:appIdNum fileId:fileId];
[[TXVodDownloadManager shareInstance] deleteDownloadMediaInfo:mediaInfo];
result(@(TRUE));
}
}
......
......@@ -65,12 +65,12 @@ class SuperPlayerPlugin {
}
/// 开关log输出
static Future<int?> setConsoleEnabled(bool enabled) async {
static Future<void> setConsoleEnabled(bool enabled) async {
return await _channel.invokeMethod('setConsoleEnabled', {"enabled": enabled});
}
/// 释放播放器资源
static Future<int?> releasePlayer(int? playerId) async {
static Future<void> releasePlayer(int? playerId) async {
return await _channel.invokeMethod('releasePlayer', {"playerId": playerId});
}
......@@ -131,12 +131,12 @@ class SuperPlayerPlugin {
}
/// 释放音频焦点,只用于安卓端
static Future<double> abandonAudioFocus() async {
static Future<void> abandonAudioFocus() async {
return await _channel.invokeMethod("abandonAudioFocus");
}
/// 请求获得音频焦点,只用于安卓端
static Future<double> requestAudioFocus() async {
static Future<void> requestAudioFocus() async {
return await _channel.invokeMethod("requestAudioFocus");
}
......
......@@ -377,4 +377,9 @@ class TXLivePlayerController extends ChangeNotifier implements ValueListenable<T
double? videoTop = 0;
double? videoRight = 0;
double? videoBottom = 0;
@override
TXPlayerValue? playerValue() {
return _value;
}
}
......@@ -9,6 +9,7 @@ abstract class TXPlayerController {
double? get videoTop;
double? get videoRight;
double? get videoBottom;
TXPlayerValue? playerValue();
Future<void> initialize({bool? onlyAudio});
Future<void> setAutoPlay({bool? isAutoPlay});
......
......@@ -4,12 +4,24 @@ part of SuperPlayer;
class TXPlayerValue {
final TXPlayerState state;
TXPlayerValue.uninitialized() : this(state: TXPlayerState.stopped);
/// 当前视频纹理的旋转角度
final int degree;
TXPlayerValue({required this.state});
TXPlayerValue.uninitialized() : this();
TXPlayerValue copyWith({TXPlayerState? state}) {
return TXPlayerValue(state: state ?? this.state);
TXPlayerValue({
this.state = TXPlayerState.stopped,
this.degree = 0,
});
TXPlayerValue copyWith({
TXPlayerState? state,
int? degree,
}) {
return TXPlayerValue(
state: state ?? this.state,
degree: degree ?? this.degree
);
}
}
......@@ -63,6 +75,7 @@ abstract class TXVodPlayEvent {
static const PLAY_WARNING_SHAKE_FAIL = 3003; // RTMP 服务器握手失败(仅播放 RTMP 地址时会抛送)
static const PLAY_WARNING_READ_WRITE_FAIL = 3005; // RTMP 读/写失败
static const PLAY_WARNING_SPEAKER_DEVICE_ABNORMAL = 1205; // 播放设备异常
static const VOD_PLAY_EVT_SEEK_COMPLETE = 2019; // Seek 完成
static const EVT_UTC_TIME = "EVT_UTC_TIME"; // UTC时间
static const EVT_BLOCK_DURATION = "EVT_BLOCK_DURATION"; // 卡顿时间
......
......@@ -84,7 +84,17 @@ class TXPlayerVideoState extends State<TXPlayerVideo> {
);
});
} else {
return _textureId == -1 ? Container() : Texture(textureId: _textureId);
return _textureId == -1 ? Container() : _buildRotate();
}
}
Widget _buildRotate() {
var degree = widget.controller.playerValue()?.degree;
var quarterTurns = ( degree! / 90).floor();
if (quarterTurns == 0 || !Platform.isIOS) {
return Texture(textureId: _textureId);
} else {
return RotatedBox(quarterTurns: quarterTurns, child: Texture(textureId: _textureId));
}
}
......
......@@ -107,6 +107,11 @@ class TXVodDownloadController {
_downlodOnErrorListener = downlodOnErrorListener;
}
/// 删除下载任务
Future<bool> deleteDownloadMediaInfo(TXVodDownloadMedialnfo medialnfo) async {
return await _methodChannel.invokeMethod("deleteDownloadMediaInfo", medialnfo.toJson());
}
TXVodDownloadMedialnfo _getDownloadInfoFromMap(Map<dynamic, dynamic> map) {
TXVodDownloadMedialnfo medialnfo = TXVodDownloadMedialnfo();
medialnfo.playPath = map["playPath"];
......
......@@ -88,6 +88,7 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
videoBottom = event["videoBottom"];
}
}
value = _value!.copyWith(degree: map['EVT_KEY_VIDEO_ROTATION'] ?? 0);
break;
case TXVodPlayEvent.PLAY_EVT_VOD_PLAY_PREPARED: //点播加载完成
break;
......@@ -428,6 +429,11 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
super.dispose();
}
@override
TXPlayerValue? playerValue () {
return _value;
}
@override
get value => _value;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论