提交 1831072e authored 作者: dokieyang's avatar dokieyang

Update version:1.0.2

1. refactor superPlayer,move it to example
上级 08ad5d2f
差异被折叠。
group 'com.tencent.vod.flutter'
apply from:'config.gradle'
version '1.0.1'
version '1.0.2'
buildscript {
repositories {
......@@ -52,16 +52,8 @@ android {
}
}
/**
* 判断客户是否有自定义liteavSdk版本,如果未定义则默认使用config.gradle配置的最新版本。
* 这里判断,不为null、不为空字符串
*/
def liteavSdk = rootProject.ext.liteavSdk
if(rootProject.ext.liteavSdkCustom) {
liteavSdk = rootProject.ext.liteavSdkCustom
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
implementation liteavSdk
implementation rootProject.ext.liteavSdk
}
\ No newline at end of file
......@@ -503,7 +503,11 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC
void setToken(String token) {
if (mVodPlayer != null) {
mVodPlayer.setToken(token);
if(TextUtils.isEmpty(token)) {
mVodPlayer.setToken(null);
} else {
mVodPlayer.setToken(token);
}
}
}
......
......@@ -90,14 +90,6 @@ super_player:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
```
如果需要更换sdk中依赖的liteav更新包,可以在android的build.gradle中指定rootProject.ext.liteavSdkCustom依赖
```groovy
rootProject.ext.liteavSdkCustom="com.tencent.liteav:LiteAVSDK_Player:latest.release"
```
如果不定义该值,或者赋值为空字符串和null,则默认使用player最新版本
### iOS 配置[](id:iOS_config)
在 iOS 的`Info.plist`中增加如下配置:
......
......@@ -19,26 +19,13 @@ SDK 早期版本只有 TXLivePlayer 一个 Class 承载直播和点播功能,
## 对接攻略
### 步骤1:申请视频播放能力License和集成
集成播放器前,需要[注册腾讯云账户](https://cloud.tencent.com/login),注册成功后申请视频播放能力License, 然后通过下面方式集成,建议在应用启动时进行。
如果没有集成license,播放过程中可能会出现异常。
```dart
String licenceURL = ""; // 获取到的 licence url
String licenceKey = ""; // 获取到的 licence key
SuperPlayerPlugin.setGlobalLicense(licenceURL, licenceKey);
```
### 步骤2: 创建 Player
### step 1: 创建 Player
视频云 SDK 中的 TXLivePlayer 模块负责实现直播播放功能。对应于 Flutter 是 TXLivePlayerController
```dart
TXLivePlayerController controller = TXLivePlayerController();
```
### 步骤3: 渲染 View
### step 2: 渲染 View
接下来我们要给播放器的视频画面找个地方来显示,Flutter 系统中使用 Widget 作为基本的界面渲染单位,所以您只需要准备一个 Widget 并调整好布局就可以了。你可以直接使用 TXPlayerVideo 或者继承它来显示,也可以参考源码实现自定义视图。
```dart
......@@ -86,7 +73,7 @@ TXLivePlayerController controller = TXLivePlayerController();
3. 将该id通过channel机制传递给dart侧,dart侧就能够通过 `Texture` 这个widget来使用纹理了,参数就是id
4. flutter engine调用 `copyPixelBuffer` 拿到具体的纹理数据,然后交由底层进行gpu渲染
### 步骤4: 启动播放
### step 3: 启动播放
```dart
String flvUrl = "http://liteavapp.qcloud.com/live/liteavdemoplayerstreamid_demo1080p.flv";
await _controller.play("flvUrl", playType: TXPlayType.LIVE_FLV);
......@@ -102,7 +89,7 @@ await _controller.play("flvUrl", playType: TXPlayType.LIVE_FLV);
> **关于 HLS(m3u8)**
> 在 App 上我们不推荐使用 HLS 这种播放协议播放直播视频源(虽然它很适合用来做点播),因为延迟太高,在 App 上推荐使用 LIVE_FLV 或者 LIVE_RTMP 播放协议。
### 步骤5: 暂停播放
### step 5: 暂停播放
对于直播播放而言,并没有真正意义上的暂停,所谓的直播暂停,只是**画面冻结****关闭声音**,而云端的视频源还在不断地更新着,所以当您调用 resume 的时候,会从最新的时间点开始播放,这跟点播是有很大不同的(点播播放器的暂停和继续与播放本地视频文件时的表现相同)。
```dart
......@@ -112,14 +99,13 @@ _controller.pause();
_controller.resume();
```
### 步骤6: 结束播放
### step 6: 结束播放
```dart
// 停止播放
_controller.stop();
```
<h3 id="Message">步骤7: 消息接收</h3>
<h3 id="Message">step 7: 消息接收</h3>
此功能可以在推流端将一些自定义 message 随着音视频线路直接下发到观众端,适用场景例如:
(1)冲顶大会:推流端将<strong>题目</strong>下发到观众端,可以做到“音-画-题”完美同步。
(2)秀场直播:推流端将<strong>歌词</strong>下发到观众端,可以在播放端实时绘制出歌词特效,因而不受视频编码的降质影响。
......@@ -136,7 +122,7 @@ _controller.onPlayerEventBroadcast.listen((event) {//订阅事件分发
});
```
### 步骤8: 清晰度无缝切换
### step 7: 清晰度无缝切换
日常使用中,网络情况在不断发生变化。在网络较差的情况下,最好适度降低画质,以减少卡顿;反之,网速比较好,可以观看更高画质。
传统切流方式一般是重新播放,会导致切换前后画面衔接不上、黑屏、卡顿等问题。使用无缝切换方案,在不中断直播的情况下,能直接切到另条流上。
......@@ -150,7 +136,7 @@ _controller.switchStream("http://5815.liveplay.myqcloud.com/live/5815_62fe94d692
>清晰度无缝切换功能需要在后台配置 PTS 对齐,如您需要可 [提交工单](https://console.cloud.tencent.com/workorder) 申请使用。
### 步骤9: 直播回看
### step 8: 直播回看
时移功能是腾讯云推出的特色能力,可以在直播过程中,随时观看回退到任意直播历史时间点,并能在此时间点一直观看直播。非常适合游戏、球赛等互动性不高,但观看连续性较强的场景。
```dart
......
......@@ -9,7 +9,7 @@
## 通过本文你可以学会
* 如何集成腾讯云视立方 Flutter 超级播放器SDK
* 如何使用超级播放器 SDK 进行点播播放
* 如何使用超级播放器组件进行点播播放
## 基础知识
......@@ -50,14 +50,6 @@ flutter pub upgrade
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
```
如果需要更换sdk中依赖的liteav更新包,可以在android的build.gradle中指定rootProject.ext.liteavSdkCustom依赖
```groovy
rootProject.ext.liteavSdkCustom="com.tencent.liteav:LiteAVSDK_Player:latest.release"
```
如果不定义该值,或者赋值为空字符串和null,则默认使用player最新版本
### iOS 配置[](id:iOS_config)
在 iOS 的`Info.plist`中增加如下配置:
......@@ -129,7 +121,7 @@ _controller.onSimplePlayerEventBroadcast.listen((event) {
```dart
Widget _getPlayArea() {
return Container(
height: 230,
height: 220,
child: SuperPlayerView(_controller),
);
}
......
......@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:super_player/super_player.dart';
import 'package:super_player_example/ui/demo_inputdialog.dart';
import 'superplayer/demo_superplayer_lib.dart';
/// flutter superplayer demo
class DemoSuperplayer extends StatefulWidget {
......@@ -12,7 +13,7 @@ class DemoSuperplayer extends StatefulWidget {
class _DemoSuperplayerState extends State<DemoSuperplayer> {
List<SuperPlayerModel> videoModels = [];
bool _isFullScreen = false;
SuperPlayerController _controller;
late SuperPlayerController _controller;
@override
void initState() {
......@@ -78,7 +79,7 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
Widget _getPlayArea() {
return Container(
height: 230,
height: 220,
child: SuperPlayerView(_controller),
);
}
......@@ -128,7 +129,7 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
model.videoURL = url;
} else if (appId != 0 && fileId.isNotEmpty) {
model.videoId = new SuperPlayerVideoId();
model.videoId.fileId = fileId;
model.videoId!.fileId = fileId;
} else {
EasyLoading.showError("请输入播放地址!");
return;
......@@ -151,7 +152,7 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
SuperPlayerModel model = SuperPlayerModel();
model.appId = 1500005830;
model.videoId = new SuperPlayerVideoId();
model.videoId.fileId = "8602268011437356984";
model.videoId!.fileId = "8602268011437356984";
model.title = "云点播";
model.playAction = playAction;
models.add(model);
......@@ -159,35 +160,35 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
model = SuperPlayerModel();
model.appId = 1252463788;
model.videoId = new SuperPlayerVideoId();
model.videoId.fileId = "5285890781763144364";
model.videoId!.fileId = "5285890781763144364";
model.playAction = playAction;
models.add(model);
model = SuperPlayerModel();
model.appId = 1252463788;
model.videoId = new SuperPlayerVideoId();
model.videoId.fileId = "4564972819219071568";
model.videoId!.fileId = "4564972819219071568";
model.playAction = playAction;
models.add(model);
model = SuperPlayerModel();
model.appId = 1252463788;
model.videoId = new SuperPlayerVideoId();
model.videoId.fileId = "4564972819219071668";
model.videoId!.fileId = "4564972819219071668";
model.playAction = playAction;
models.add(model);
model = SuperPlayerModel();
model.appId = 1252463788;
model.videoId = new SuperPlayerVideoId();
model.videoId.fileId = "4564972819219071679";
model.videoId!.fileId = "4564972819219071679";
model.playAction = playAction;
models.add(model);
model = SuperPlayerModel();
model.appId = 1252463788;
model.videoId = new SuperPlayerVideoId();
model.videoId.fileId = "4564972819219081699";
model.videoId!.fileId = "4564972819219081699";
model.playAction = playAction;
models.add(model);
......@@ -203,7 +204,7 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
setState(() {
if (videoModels.isNotEmpty) {
_controller.playWithModel(videoModels[0]);
playCurrentModel(videoModels[0]);
} else {
EasyLoading.showError("video list request error");
}
......
......@@ -15,7 +15,7 @@ class DemoTXLivePlayer extends StatefulWidget {
class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingObserver{
TXLivePlayerController _controller;
late TXLivePlayerController _controller;
double _aspectRatio = 0;
double _progress = 0.0;
int _volume = 100;
......@@ -36,7 +36,7 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
if(event["event"] == TXVodPlayEvent.PLAY_EVT_PLAY_PROGRESS) {
_progress = event["EVT_PLAY_PROGRESS"].toDouble();
_maxLiveProgressTime = _progress >= _maxLiveProgressTime ? _progress : _maxLiveProgressTime;
progressSliderKey.currentState.updatePorgess(1, _maxLiveProgressTime);
progressSliderKey.currentState?.updatePorgess(1, _maxLiveProgressTime);
}else if (event["event"] == TXVodPlayEvent.PLAY_EVT_PLAY_BEGIN || event["event"] == TXVodPlayEvent.PLAY_EVT_RCV_FIRST_I_FRAME) {//首帧出现
_isStop = false;
......@@ -63,7 +63,7 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
});
_controller.onPlayerState.listen((event) {//订阅状态变化
debugPrint("播放状态 ${event.name}");
debugPrint("播放状态 ${event!.name}");
});
await SuperPlayerPlugin.setConsoleEnabled(true);
......
......@@ -15,7 +15,7 @@ class DemoTXVodPlayer extends StatefulWidget {
class _DemoTXVodlayerState extends State<DemoTXVodPlayer>
with WidgetsBindingObserver {
TXVodPlayerController _controller;
late TXVodPlayerController _controller;
double _aspectRatio = 0;
double _currentProgress = 0.0;
bool _isMute = false;
......@@ -37,19 +37,19 @@ class _DemoTXVodlayerState extends State<DemoTXVodPlayer>
_controller = TXVodPlayerController();
_controller.onPlayerState.listen((val) {
debugPrint("播放状态 ${val.name}");
debugPrint("播放状态 ${val?.name}");
});
_controller.onPlayerEventBroadcast.listen((event) async {
//订阅状态变化
if (event["event"] == TXVodPlayEvent.PLAY_EVT_PLAY_BEGIN || event["event"] == TXVodPlayEvent.PLAY_EVT_RCV_FIRST_I_FRAME) {
EasyLoading.dismiss();
_supportedBitrates = await _controller.getSupportedBitrates();
_supportedBitrates = (await _controller.getSupportedBitrates())!;
} else if (event["event"] == TXVodPlayEvent.PLAY_EVT_PLAY_PROGRESS) {
_currentProgress = event[TXVodPlayEvent.EVT_PLAY_PROGRESS].toDouble();
double videoDuration = event[TXVodPlayEvent.EVT_PLAY_DURATION].toDouble(); // 总播放时长,转换后的单位 秒
progressSliderKey.currentState.updatePorgess(_currentProgress/videoDuration, videoDuration);
progressSliderKey.currentState?.updatePorgess(_currentProgress/videoDuration, videoDuration);
}
});
......@@ -294,7 +294,7 @@ class _DemoTXVodlayerState extends State<DemoTXVodPlayer>
),
new GestureDetector(
onTap: () async {
TXPlayerState state = _controller.playState;
TXPlayerState? state = _controller.playState;
if (state != TXPlayerState.disposed &&
state != TXPlayerState.stopped) {
enableHardware = !enableHardware;
......
......@@ -37,7 +37,7 @@ class _MyAppState extends State<MyApp> {
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String platformVersion;
String? platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
platformVersion = await SuperPlayerPlugin.platformVersion;
......@@ -51,7 +51,7 @@ class _MyAppState extends State<MyApp> {
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
_platformVersion = platformVersion!;
});
}
......
part of SuperPlayer;
part of demo_super_player_lib;
/// v2 request data parser
class PlayInfoParserV2 implements PlayInfoParser {
......@@ -64,19 +64,19 @@ class PlayInfoParserV2 implements PlayInfoParser {
}
int version = root['version'];
if (version == 2) {
coverUrl = root['coverInfo']['coverUrl'];
coverUrl = root['coverInfo']['coverUrl'] ?? "";
Map<String, dynamic> videInfoRoot = root['videoInfo'];
defaultVideoClassification =
root['playerInfo']['defaultVideoClassification'];
root['playerInfo']['defaultVideoClassification'] ?? "";
_parseVideoClassificationList(root['playerInfo']);
imageSpriteInfo = _parseImageSpriteInfo(root['imageSpriteInfo']);
keyFrameDescInfo = _parseKeyFrameDescInfo(root['keyFrameDescInfo']);
duration = videInfoRoot['sourceVideo']['duration'];
name = videInfoRoot['basicInfo']['name'];
duration = videInfoRoot['sourceVideo']['duration'] ?? 0;
name = videInfoRoot['basicInfo']['name'] ?? "";
_parseMastPlayInfo(videInfoRoot);
_parseTranscodeList(videInfoRoot);
......@@ -86,7 +86,7 @@ class PlayInfoParserV2 implements PlayInfoParser {
}
}
List<PlayKeyFrameDescInfo>? _parseKeyFrameDescInfo(Map<String,dynamic> keyFrameDescInfo) {
List<PlayKeyFrameDescInfo>? _parseKeyFrameDescInfo(dynamic keyFrameDescInfo) {
if(null != keyFrameDescInfo && keyFrameDescInfo.isNotEmpty) {
List<dynamic> keyFrameDescList = keyFrameDescInfo['keyFrameDescList'];
if(keyFrameDescList.isNotEmpty) {
......@@ -104,7 +104,7 @@ class PlayInfoParserV2 implements PlayInfoParser {
return null;
}
PlayImageSpriteInfo? _parseImageSpriteInfo(Map<String,dynamic> imageSpriteInfo) {
PlayImageSpriteInfo? _parseImageSpriteInfo(dynamic imageSpriteInfo) {
if(null != imageSpriteInfo && imageSpriteInfo.isNotEmpty) {
List<dynamic> imageSpriteList = imageSpriteInfo['imageSpriteList'];
if(imageSpriteList.isNotEmpty) {
......@@ -124,17 +124,17 @@ class PlayInfoParserV2 implements PlayInfoParser {
}
void _parseVideoClassificationList(Map<String, dynamic> playerInfoRoot) {
List<dynamic> videoClassificationRoot = playerInfoRoot['videoClassification'];
List<VideoClassification> classList = [];
if(null != videoClassificationRoot) {
if(null != playerInfoRoot['videoClassification']) {
List<dynamic> videoClassificationRoot = playerInfoRoot['videoClassification'];
for(Map<String, dynamic> object in videoClassificationRoot) {
VideoClassification classification = new VideoClassification();
classification.id =object["id"];
classification.name = object["name"];
List<int> definitionList = [];
List<dynamic> array = object['definitionList'];
if(null != array) {
if(null != object['definitionList']) {
List<dynamic> array = object['definitionList'];
for(int definition in array) {
definitionList.add(definition);
}
......@@ -148,16 +148,16 @@ class PlayInfoParserV2 implements PlayInfoParser {
void _parseMastPlayInfo(Map<String, dynamic> videInfoRoot) {
Map<String, dynamic> masterPlayRoot = videInfoRoot['masterPlayList'];
if (null != masterPlayRoot) {
if (null != videInfoRoot['masterPlayList']) {
Map<String, dynamic> masterPlayRoot = videInfoRoot['masterPlayList'];
masterPlayList = PlayInfoStream();
masterPlayList?.url = masterPlayRoot['url'];
}
}
void _parseTranscodeList(Map<String, dynamic> videInfoRoot) {
List<dynamic> transcodeListRoot = videInfoRoot['transcodeList'];
if (null != transcodeListRoot) {
if (null != videInfoRoot['transcodeList']) {
List<dynamic> transcodeListRoot = videInfoRoot['transcodeList'];
List<PlayInfoStream> streamList = _parseStreamList(transcodeListRoot);
for(PlayInfoStream stream in streamList) {
if(videoClassificationList.isNotEmpty) {
......
part of SuperPlayer;
part of demo_super_player_lib;
/// v4 request data parser
class PlayInfoParserV4 implements PlayInfoParser {
......@@ -50,52 +50,52 @@ class PlayInfoParserV4 implements PlayInfoParser {
Map<String, dynamic> media = root['media'];
mRequestContext = root['context'];
if (media.isNotEmpty) {
Map<String, dynamic> basicInfo = media['basicInfo'];
if (null != basicInfo) {
name = basicInfo['name'];
description = basicInfo['description'];
coverUrl = basicInfo['coverUrl'];
duration = basicInfo['duration'];
if (null != media['basicInfo']) {
Map<String, dynamic> basicInfo = media['basicInfo'];
name = basicInfo['name'] ?? "";
description = basicInfo['description'] ?? "";
coverUrl = basicInfo['coverUrl'] ?? "";
duration = basicInfo['duration'] ?? "";
}
String audioVideoType = media['audioVideoType'];
if (audioVideoType == 'AdaptiveDynamicStream') {
Map<String, dynamic> streamingInfo = media['streamingInfo'];
if (null != streamingInfo) {
Map<String, dynamic> plainOutputRoot = streamingInfo['plainOutput'];
if (null != plainOutputRoot) {
_url = plainOutputRoot['url'];
if (null != media['streamingInfo']) {
Map<String, dynamic> streamingInfo = media['streamingInfo'];
if (null != streamingInfo['plainOutput']) {
Map<String, dynamic> plainOutputRoot = streamingInfo['plainOutput'];
_url = plainOutputRoot['url'] ?? "";
_parseSubStreams(plainOutputRoot['subStreams']);
}
List<dynamic> drmoutInfo = streamingInfo['drmOutput'];
if (null != drmoutInfo) {
if (null != streamingInfo['drmOutput']) {
List<dynamic> drmoutInfo = streamingInfo['drmOutput'];
encryptedStreamingInfoList = [];
for (Map<String, dynamic> drmout in drmoutInfo) {
EncryptedStreamingInfo info = new EncryptedStreamingInfo();
drmType = drmout['type'];
drmType = drmout['type'] ?? "";
info.drmType = drmType;
info.url = drmout['url'];
encryptedStreamingInfoList.add(info);
_parseSubStreams(drmout['subStreams']);
}
}
token = streamingInfo["drmToken"];
token = streamingInfo["drmToken"] ?? "";
}
} else if (audioVideoType == 'Transcode') {
Map<String, dynamic> transcodeInfo = media['transcodeInfo'];
if (transcodeInfo.isNotEmpty) {
_url = transcodeInfo['url'];
_url = transcodeInfo['url'] ?? "";
}
} else if (audioVideoType == 'Original') {
Map<String, dynamic> originalInfo = media['originalInfo'];
if (originalInfo.isNotEmpty) {
_url = originalInfo['url'];
_url = originalInfo['url'] ?? "";
}
}
Map<String, dynamic> imageSpriteInfoJson = media['imageSpriteInfo'];
if (null != imageSpriteInfoJson) {
if (null != media['imageSpriteInfo']) {
Map<String, dynamic> imageSpriteInfoJson = media['imageSpriteInfo'];
imageSpriteInfo = PlayImageSpriteInfo();
imageSpriteInfo?.webVttUrl = imageSpriteInfoJson['webVttUrl'];
imageSpriteInfo?.webVttUrl = imageSpriteInfoJson['webVttUrl'] ?? "";
List<String> imageUrls = imageSpriteInfoJson['imageUrls'];
imageSpriteInfo?.imageUrls = imageUrls;
}
......@@ -104,10 +104,11 @@ class PlayInfoParserV4 implements PlayInfoParser {
}
}
_parseSubStreams(List<dynamic> substreams) {
_parseSubStreams(dynamic substreams) {
if (null != substreams) {
List<dynamic> substreamList = substreams;
resolutionNameList = [];
for (Map<String, dynamic> substream in substreams) {
for (Map<String, dynamic> substream in substreamList) {
ResolutionName resolutionName = ResolutionName();
resolutionName.width = substream['width'];
resolutionName.height = substream['height'];
......@@ -119,8 +120,8 @@ class PlayInfoParserV4 implements PlayInfoParser {
}
_parseKeyFrameDescList(Map<String, dynamic> media) {
Map<String, dynamic> keyFrameDescInfoJson = media['keyFrameDescInfo'];
if (null != keyFrameDescInfoJson) {
if (null != media['keyFrameDescInfo']) {
Map<String, dynamic> keyFrameDescInfoJson = media['keyFrameDescInfo'];
keyFrameDescInfo = [];
List<Map<String, dynamic>> keyFrameDescList = keyFrameDescInfoJson['keyFrameDescList'];
for (Map<String, dynamic> keyFrameDesc in keyFrameDescList) {
......
part of SuperPlayer;
part of demo_super_player_lib;
/// play info parser interface
abstract class PlayInfoParser {
......
part of SuperPlayer;
part of demo_super_player_lib;
/// request handler with tencent fileId
class PlayInfoProtocol {
......
part of SuperPlayer;
part of demo_super_player_lib;
/// request data handler
class SuperVodDataLoader {
......
part of SuperPlayer;
part of demo_super_player_lib;
/// colors resource
class ColorResource {
static const COLOR_MAIN_THEME = 0xFFFF4C58;
......
part of SuperPlayer;
part of demo_super_player_lib;
/// string resource
class StringResource {
......
library demo_super_player_lib;
import 'dart:async';
import 'dart:convert';
import 'dart:core';
import 'dart:io';
import 'dart:math';
import 'package:auto_orientation/auto_orientation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:super_player/super_player.dart';
part 'superplayer_observer.dart';
part 'superplayer_controller.dart';
part 'cgi/play_info_parser_v2.dart';
part 'cgi/play_info_parser_v4.dart';
part 'cgi/playinfo_parser.dart';
part 'cgi/playinfo_protocol.dart';
part 'cgi/super_vod_data_loader.dart';
part 'model/superplayer_define.dart';
part 'model/superplayer_model.dart';
part 'tools/video_quality_utils.dart';
part 'ui/superplayer_bottom_view.dart';
part 'ui/superplayer_quality_view.dart';
part 'ui/superplayer_title_view.dart';
part 'ui/superplayer_widget.dart';
part 'common/color_resource.dart';
part 'common/string_resource.dart';
\ No newline at end of file
part of SuperPlayer;
part of demo_super_player_lib;
enum SuperPlayerState {
INIT, // 初始状态
......
part of SuperPlayer;
part of demo_super_player_lib;
/// superplayer play controller
class SuperPlayerController {
static const TAG = "SuperPlayerController";
......@@ -51,7 +50,7 @@ class SuperPlayerController {
void _initVodPlayer() async {
_vodPlayerController = new TXVodPlayerController();
await _vodPlayerController?.initialize();
_vodPlayerController?.onPlayerEventBroadcast.listen((event) async {
_vodPlayerController?.onPlayerEventBroadcast?.listen((event) async {
int eventCode = event['event'];
switch (eventCode) {
case TXVodPlayEvent.PLAY_EVT_VOD_PLAY_PREPARED: // vodPrepared
......
part of SuperPlayer;
part of demo_super_player_lib;
/// superplayer's bridge between widget and controller
class _SuperPlayerObserver {
......
part of SuperPlayer;
part of demo_super_player_lib;
/// video quality utils
class VideoQualityUtils {
......
part of SuperPlayer;
part of demo_super_player_lib;
/// slider
class VideoBottomView extends StatefulWidget {
......
part of SuperPlayer;
part of demo_super_player_lib;
class QualityListView extends StatefulWidget {
final List<VideoQuality>? _qualityList;
......
part of SuperPlayer;
part of demo_super_player_lib;
class _VideoTitleView extends StatefulWidget {
......
part of SuperPlayer;
part of demo_super_player_lib;
final double topBottomOffset = -2;
......@@ -493,7 +493,9 @@ class SuperPlayerFullScreenState extends State<SuperPlayerFullScreenView> {
@override
Widget build(BuildContext context) {
return WillPopScope(
child: SuperPlayerView(widget._playController, viewKey: widget.key),
child: Scaffold(
body: SuperPlayerView(widget._playController, viewKey: widget.key),
),
onWillPop: _onFullScreenWillPop,
);
}
......
......@@ -36,12 +36,12 @@ class _DemoBitrateCheckboxState extends State<DemoBitrateCheckbox> {
Text("码率$s", style: TextStyle(color: Colors.white),),
Theme(data: ThemeData(
unselectedWidgetColor: Colors.white,),
child: Radio(
child: Radio<int> (
value: e["index"],
groupValue: this.widget.index,
onChanged: (value) {
setState(() {
this.widget.index = value;
this.widget.index = value!;
});
},
),
......
import 'package:flutter/material.dart';
import 'demo_define.dart';
class DemoExpansionPanelList extends StatefulWidget {
......@@ -8,13 +7,11 @@ class DemoExpansionPanelList extends StatefulWidget {
}
class _DemoExpansionPanelListState extends State<DemoExpansionPanelList> {
List<int> mList; //组成一个int类型数组,用来控制索引
List<ExpandStateBean> expandStateList; //开展开的状态列表,ExpandStateBean是自定义的类
List<int> mList = []; //组成一个int类型数组,用来控制索引
List<ExpandStateBean> expandStateList = []; //开展开的状态列表,ExpandStateBean是自定义的类
//构造方法,调用这个类的时候自动执行
_DemoExpansionPanelListState(){
mList=new List();
expandStateList=new List();
//遍历两个List进行赋值
for(int i=0;i<1;i++){
mList.add(i);
......
......@@ -9,7 +9,7 @@ class DemoInputDialog extends StatefulWidget {
int appId = 0;
String fileId = "";
DemoInputDialogFinishCallback callback;
bool showFileEdited;
bool showFileEdited = true;
DemoInputDialog(this.url, this.appId, this.fileId, this.callback, {bool showFileEdited = true}) : super () {this.showFileEdited = showFileEdited;}
......@@ -18,9 +18,9 @@ class DemoInputDialog extends StatefulWidget {
}
class _DemoInputDialogState extends State<DemoInputDialog> {
TextEditingController _urlController;
TextEditingController _appIdController;
TextEditingController _fileIdController;
late TextEditingController _urlController;
late TextEditingController _appIdController;
late TextEditingController _fileIdController;
@override
void initState() {
......
......@@ -49,10 +49,10 @@ class VideoSliderState extends State<VideoSliderView> {
isSliding = false;
_currentProgress = value;
if (widget._controller is TXVodPlayerController) {
TXVodPlayerController controller = widget._controller;
TXVodPlayerController controller = widget._controller as TXVodPlayerController;
controller.seek(_currentProgress * _videoDuration);
} else if (widget._controller is TXLivePlayerController) {
TXLivePlayerController controller = widget._controller;
TXLivePlayerController controller = widget._controller as TXLivePlayerController;
controller.seek(_currentProgress * _videoDuration);
}
......
......@@ -15,7 +15,7 @@ class TreePage extends StatefulWidget {
}
class _TreePageState extends State<TreePage> {
List<TreeData> _datas = List();
List<TreeData> _datas = [];
ScrollController _scrollController = ScrollController();
int _panelIndex = 0; //展开下标
List<IconData> _icons = [
......@@ -153,7 +153,7 @@ class _TreePageState extends State<TreePage> {
return DemoTXLivePlayer();
}else if (i == 1) {
return DemoTXVodPlayer();
} else if(i == 2) {
} else {
return DemoSuperplayer();
}
}
......
......@@ -75,7 +75,7 @@ packages:
name: flutter_easyloading
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.3"
version: "3.0.5"
flutter_spinkit:
dependency: transitive
description:
......@@ -148,7 +148,7 @@ packages:
path: ".."
relative: true
source: path
version: "1.0.1"
version: "1.0.2"
term_glyph:
dependency: transitive
description:
......
......@@ -6,7 +6,8 @@ description: Demonstrates how to use the super_player plugin.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
environment:
sdk: ">=2.7.0 <3.0.0"
sdk: '>=2.12.0 <3.0.0'
flutter: ">=1.20.0"
dependencies:
flutter:
......
......@@ -19,7 +19,7 @@ void main() {
expect(
find.byWidgetPredicate(
(Widget widget) => widget is Text &&
widget.data.startsWith('Running on:'),
widget.data!.startsWith('Running on:'),
),
findsOneWidget,
);
......
......@@ -578,7 +578,11 @@ static const int uninitialized = -1;
- (void)setToken:(NSString *)token
{
if(_txVodPlayer != nil) {
_txVodPlayer.token = token;
if(token && token.length > 0) {
_txVodPlayer.token = token;
} else {
_txVodPlayer.token = nil;
}
}
}
......
......@@ -4,7 +4,7 @@
#
Pod::Spec.new do |s|
s.name = 'super_player'
s.version = '1.0.1'
s.version = '1.0.2'
s.summary = 'player plugin.'
s.description = <<-DESC
player plugin.
......@@ -17,7 +17,7 @@ player plugin.
s.public_header_files = 'Classes/**/*.h'
s.dependency 'Flutter'
s.dependency 'TXLiteAVSDK_Player'
s.platform = :ios, '8.0'
s.platform = :ios, '9.0'
s.static_framework = true
# Flutter.framework does not contain a i386 slice.
......
......@@ -2,37 +2,17 @@
library SuperPlayer;
import 'dart:async';
import 'dart:convert';
import 'dart:core';
import 'dart:io';
import 'dart:math';
import 'dart:ui';
import 'package:auto_orientation/auto_orientation.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
part 'Core/superplayer_plugin.dart';
part 'Core/tools/log_utils.dart';
part 'Core/txliveplayer_controller.dart';
part 'Core/txvodplayer_controller.dart';
part 'Core/txplayer_controller.dart';
part 'Core/txplayer_define.dart';
part 'Core/superplayer_plugin.dart';
part 'Core/txplayer_widget.dart';
part 'Core/txplayer_controller.dart';
part 'Core/txvodplayer_config.dart';
part 'Core/tools/video_quality_utils.dart';
part 'Core/tools/log_utils.dart';
part 'Core/superplayer/cgi/super_vod_data_loader.dart';
part 'Core/superplayer/cgi/play_info_parser_v2.dart';
part 'Core/superplayer/cgi/play_info_parser_v4.dart';
part 'Core/superplayer/cgi/playinfo_parser.dart';
part 'Core/superplayer/cgi/playinfo_protocol.dart';
part 'Core/superplayer/superplater_observer.dart';
part 'Core/superplayer/superplayer_controller.dart';
part 'Core/superplayer/model/superplayer_define.dart';
part 'Core/superplayer/model/superplayer_model.dart';
part 'Core/superplayer/ui/superplayer_widget.dart';
part 'Core/superplayer/ui/superplayer_bottom_view.dart';
part 'Core/superplayer/ui/superplayer_quality_view.dart';
part 'Core/superplayer/ui/superplayer_title_view.dart';
part 'Core/common/string_resource.dart';
part 'Core/common/color_resource.dart';
\ No newline at end of file
part 'Core/txvodplayer_controller.dart';
\ No newline at end of file
......@@ -8,13 +8,6 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.8.2"
auto_orientation:
dependency: "direct main"
description:
name: auto_orientation
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.2.1"
boolean_selector:
dependency: transitive
description:
......
name: super_player
description: player plugin.
version: 1.0.1
version: 1.0.2
author:
homepage:
......@@ -12,8 +12,6 @@ dependencies:
flutter:
sdk: flutter
auto_orientation: ^2.0.0
dev_dependencies:
flutter_test:
sdk: flutter
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论