提交 80f476c9 authored 作者: dokieyang's avatar dokieyang

1、fix bug: play with fileId & psign

2、add more features to SuperPlayer panel 3、update sdk version to latest(10.2)
上级 391bd191
.idea/ .idea/
.dart_tool/ .dart_tool/
.packages .packages
\ No newline at end of file pubspec.lock
\ No newline at end of file
差异被折叠。
## 腾讯云播放器SDK Flutter插件 ## 腾讯云播放器SDK Flutter插件
简体中文| [English](./README-EN.md)
## 工程目录结构说明 ## 工程目录结构说明
本目录包含腾讯云播放器SDK Flutter 插件 和 Demo 源代码,主要演示接口如何调用以及最基本的功能。 本目录包含腾讯云播放器SDK Flutter 插件 和 Demo 源代码,主要演示接口如何调用以及最基本的功能。
...@@ -116,7 +118,7 @@ pod 'TXLiteAVSDK_Professional' //Professional版 ...@@ -116,7 +118,7 @@ pod 'TXLiteAVSDK_Professional' //Professional版
### 集成过程中常见问题 ### 集成过程中常见问题
执行`flutter doctor`命令检查运行环境,知道出现”No issues found!“。 执行`flutter doctor`命令检查运行环境,直到出现”No issues found!“。
执行`flutter pub get`确保所有依赖的组件都已更新成功。 执行`flutter pub get`确保所有依赖的组件都已更新成功。
...@@ -175,10 +177,17 @@ class _TestState extends State<Test> { ...@@ -175,10 +177,17 @@ class _TestState extends State<Test> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Scaffold(
height: 220, body: Container(
color: Colors.black, height: 220,
child: AspectRatio(aspectRatio: _aspectRatio, child: TXPlayerVideo(controller: _controller))); color: Colors.black,
child: AspectRatio(aspectRatio: _aspectRatio, child: TXPlayerVideo(controller: _controller))));
}
@override
void dispose() {
_controller.dispose();
super.dispose();
} }
} }
``` ```
...@@ -301,6 +310,13 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> { ...@@ -301,6 +310,13 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
model.title = "腾讯云音视频"; model.title = "腾讯云音视频";
_controller.playWithModel(model); _controller.playWithModel(model);
} }
@override
void dispose() {
// must invoke when page exit.
_controller.releasePlayer();
super.dispose();
}
} }
``` ```
......
...@@ -24,32 +24,11 @@ apply plugin: 'com.android.library' ...@@ -24,32 +24,11 @@ apply plugin: 'com.android.library'
android { android {
//获取local.properties配置文件
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
//获取flutter的sdk路径
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
compileSdkVersion rootProject.ext.compileSdkVersion compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig { defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
} }
dependencies {
compileOnly 'androidx.annotation:annotation:1.2.0'
//此处仅处理因插件项目内报红显示的处理方式
// compileOnly files("$flutterRoot/bin/cache/artifacts/engine/android-arm/flutter.jar")
}
} }
......
...@@ -8,11 +8,6 @@ rootProject.ext { ...@@ -8,11 +8,6 @@ rootProject.ext {
在此处可以更换需要的SDK版本,替换为专业版为 com.tencent.liteav:LiteAVSDK_Professional:latest.release 在此处可以更换需要的SDK版本,替换为专业版为 com.tencent.liteav:LiteAVSDK_Professional:latest.release
其中 latest.release 可指定为自己需要的版本号,例如 "com.tencent.liteav:LiteAVSDK_Player:9.5.29035" ,写成 latest.release 则默认使用最新版本 其中 latest.release 可指定为自己需要的版本号,例如 "com.tencent.liteav:LiteAVSDK_Player:9.5.29035" ,写成 latest.release 则默认使用最新版本
*/ */
// liteavSdk="com.tencent.liteav:LiteAVSDK_Player:latest.release" // liteavSdk="com.tencent.liteav:LiteAVSDK_Player:latest.release"
liteavSdk="com.tencent.liteav:LiteAVSDK_Professional:latest.release" liteavSdk="com.tencent.liteav:LiteAVSDK_Professional:latest.release"
imSdk = 'com.tencent.imsdk:imsdk:4.9.1'
versionCode = 1
versionName = "v1.0"
ndkAbi = 'armeabi'//,'armeabi-v7a', 'arm64-v8a'
aekit_version = '1.0.10-cloud'
} }
\ No newline at end of file
// Copyright (c) 2022 Tencent. All rights reserved.
package com.tencent.vod.flutter; package com.tencent.vod.flutter;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
...@@ -16,7 +17,7 @@ public class FTXBasePlayer { ...@@ -16,7 +17,7 @@ public class FTXBasePlayer {
mPlayerId = mAtomicId.incrementAndGet(); mPlayerId = mAtomicId.incrementAndGet();
} }
public void destory() { public void destroy() {
} }
......
// Copyright (c) 2022 Tencent. All rights reserved.
package com.tencent.vod.flutter;
/**
* 通用事件码
*/
public class FTXEvent {
/*
音量变化
*/
public static final int EVENT_VOLUME_CHANGED = 0x01;
/*
失去音量输出播放焦点
*/
public static final int EVENT_AUDIO_FOCUS_PAUSE = 0x02;
/*
获得音量输出焦点
*/
public static final int EVENT_AUDIO_FOCUS_PLAY = 0x03;
}
// Copyright (c) 2022 Tencent. All rights reserved.
package com.tencent.vod.flutter; package com.tencent.vod.flutter;
import android.app.Activity; import android.app.Activity;
...@@ -87,7 +88,7 @@ public class FTXLivePlayer extends FTXBasePlayer implements MethodChannel.Method ...@@ -87,7 +88,7 @@ public class FTXLivePlayer extends FTXBasePlayer implements MethodChannel.Method
} }
@Override @Override
public void destory() { public void destroy() {
if (mLivePlayer != null) { if (mLivePlayer != null) {
mLivePlayer.stopPlay(true); mLivePlayer.stopPlay(true);
mLivePlayer = null; mLivePlayer = null;
...@@ -203,7 +204,6 @@ public class FTXLivePlayer extends FTXBasePlayer implements MethodChannel.Method ...@@ -203,7 +204,6 @@ public class FTXLivePlayer extends FTXBasePlayer implements MethodChannel.Method
Log.d(TAG, "startPlay:"); Log.d(TAG, "startPlay:");
if (mLivePlayer != null) { if (mLivePlayer != null) {
mLivePlayer.setSurface(mSurface); mLivePlayer.setSurface(mSurface);
mLivePlayer.enableHardwareDecode(true);
mLivePlayer.setPlayListener(this); mLivePlayer.setPlayListener(this);
TXLivePlayConfig config = new TXLivePlayConfig(); TXLivePlayConfig config = new TXLivePlayConfig();
config.setEnableMessage(true); config.setEnableMessage(true);
......
// Copyright (c) 2022 Tencent. All rights reserved.
package com.tencent.vod.flutter; package com.tencent.vod.flutter;
import java.util.LinkedList; import java.util.LinkedList;
......
// Copyright (c) 2022 Tencent. All rights reserved.
package com.tencent.vod.flutter; package com.tencent.vod.flutter;
import android.text.TextUtils; import android.text.TextUtils;
......
// Copyright (c) 2022 Tencent. All rights reserved.
package com.tencent.vod.flutter; package com.tencent.vod.flutter;
import android.graphics.Bitmap; import android.graphics.Bitmap;
...@@ -12,6 +13,7 @@ import com.tencent.rtmp.ITXVodPlayListener; ...@@ -12,6 +13,7 @@ import com.tencent.rtmp.ITXVodPlayListener;
import com.tencent.rtmp.TXBitrateItem; import com.tencent.rtmp.TXBitrateItem;
import com.tencent.rtmp.TXLiveConstants; import com.tencent.rtmp.TXLiveConstants;
import com.tencent.rtmp.TXLivePlayer; import com.tencent.rtmp.TXLivePlayer;
import com.tencent.rtmp.TXPlayInfoParams;
import com.tencent.rtmp.TXPlayerAuthBuilder; import com.tencent.rtmp.TXPlayerAuthBuilder;
import com.tencent.rtmp.TXVodPlayConfig; import com.tencent.rtmp.TXVodPlayConfig;
import com.tencent.rtmp.TXVodPlayer; import com.tencent.rtmp.TXVodPlayer;
...@@ -50,6 +52,9 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC ...@@ -50,6 +52,9 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC
private static final int Uninitialized = -101; private static final int Uninitialized = -101;
private TextureRegistry.SurfaceTextureEntry mSurfaceTextureEntry; private TextureRegistry.SurfaceTextureEntry mSurfaceTextureEntry;
private boolean mEnableHardwareDecode = true;
private boolean mHardwareDecodeFail = false;
public FTXVodPlayer(FlutterPlugin.FlutterPluginBinding flutterPluginBinding) { public FTXVodPlayer(FlutterPlugin.FlutterPluginBinding flutterPluginBinding) {
super(); super();
...@@ -87,7 +92,7 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC ...@@ -87,7 +92,7 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC
@Override @Override
public void destory() { public void destroy() {
if (mVodPlayer != null) { if (mVodPlayer != null) {
mVodPlayer.stopPlay(true); mVodPlayer.stopPlay(true);
mVodPlayer = null; mVodPlayer = null;
...@@ -114,8 +119,8 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC ...@@ -114,8 +119,8 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC
} }
@Override @Override
public void onPlayEvent(TXVodPlayer txVodPlayer, int i, Bundle bundle) { public void onPlayEvent(TXVodPlayer txVodPlayer, int event, Bundle bundle) {
if (i == TXLiveConstants.PLAY_EVT_CHANGE_RESOLUTION) { if (event == TXLiveConstants.PLAY_EVT_CHANGE_RESOLUTION) {
String EVT_PARAM3 = bundle.getString("EVT_PARAM3"); String EVT_PARAM3 = bundle.getString("EVT_PARAM3");
if (!TextUtils.isEmpty(EVT_PARAM3)) { if (!TextUtils.isEmpty(EVT_PARAM3)) {
String[] array = EVT_PARAM3.split(","); String[] array = EVT_PARAM3.split(",");
...@@ -132,14 +137,33 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC ...@@ -132,14 +137,33 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC
bundle.putInt("videoTop", videoTop); bundle.putInt("videoTop", videoTop);
bundle.putInt("videoRight", videoRight); bundle.putInt("videoRight", videoRight);
bundle.putInt("videoBottom", videoBottom); bundle.putInt("videoBottom", videoBottom);
mEventSink.success(getParams(i, bundle)); mEventSink.success(getParams(event, bundle));
return; return;
} }
} }
int width = bundle.getInt(TXLiveConstants.EVT_PARAM1, 0);
int height = bundle.getInt(TXLiveConstants.EVT_PARAM2, 0);
if (!mEnableHardwareDecode || mHardwareDecodeFail) {
setDefaultBufferSizeForSoftDecode(width, height);
}
} else if (event == TXLiveConstants.PLAY_WARNING_HW_ACCELERATION_FAIL) {
mHardwareDecodeFail = true;
} }
mEventSink.success(getParams(i, bundle)); mEventSink.success(getParams(event, bundle));
} }
// surface 的大小默认是宽高为1,当硬解失败时或使用软解时,软解会依赖surface的窗口渲染,不更新会导致只有1px的内容
private void setDefaultBufferSizeForSoftDecode(int width, int height) {
mSurfaceTextureEntry.surfaceTexture().setDefaultBufferSize(width, height);
if (mSurface != null) {
mSurface.release();
}
mSurface = new Surface(mSurfaceTextureEntry.surfaceTexture());
mVodPlayer.setSurface(mSurface);
}
@Override @Override
public void onNetStatus(TXVodPlayer txVodPlayer, Bundle bundle) { public void onNetStatus(TXVodPlayer txVodPlayer, Bundle bundle) {
mNetStatusSink.success(getParams(0, bundle)); mNetStatusSink.success(getParams(0, bundle));
...@@ -151,7 +175,7 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC ...@@ -151,7 +175,7 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC
boolean onlyAudio = call.argument("onlyAudio"); boolean onlyAudio = call.argument("onlyAudio");
long id = init(onlyAudio); long id = init(onlyAudio);
result.success(id); result.success(id);
} else if (call.method.equals("setIsAutoPlay")) { } else if (call.method.equals("setAutoPlay")) {
boolean loop = call.argument("isAutoPlay"); boolean loop = call.argument("isAutoPlay");
setIsAutoPlay(loop); setIsAutoPlay(loop);
result.success(null); result.success(null);
...@@ -160,8 +184,8 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC ...@@ -160,8 +184,8 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC
int r = startPlay(url); int r = startPlay(url);
result.success(r); result.success(r);
} else if (call.method.equals("startPlayWithParams")) { } else if (call.method.equals("startPlayWithParams")) {
int r = startPlayWithParams(call); startPlayWithParams(call);
result.success(r); result.success(null);
} else if (call.method.equals("stop")) { } else if (call.method.equals("stop")) {
Boolean isNeedClear = call.argument("isNeedClear"); Boolean isNeedClear = call.argument("isNeedClear");
int r = stopPlay(isNeedClear); int r = stopPlay(isNeedClear);
...@@ -285,6 +309,7 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC ...@@ -285,6 +309,7 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC
return mSurfaceTextureEntry == null ? -1 : mSurfaceTextureEntry.id(); return mSurfaceTextureEntry == null ? -1 : mSurfaceTextureEntry.id();
} }
void setPlayer(boolean onlyAudio) { void setPlayer(boolean onlyAudio) {
if (!onlyAudio) { if (!onlyAudio) {
mSurfaceTextureEntry = mFlutterPluginBinding.getTextureRegistry().createSurfaceTexture(); mSurfaceTextureEntry = mFlutterPluginBinding.getTextureRegistry().createSurfaceTexture();
...@@ -293,7 +318,6 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC ...@@ -293,7 +318,6 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC
if (mVodPlayer != null) { if (mVodPlayer != null) {
mVodPlayer.setSurface(mSurface); mVodPlayer.setSurface(mSurface);
mVodPlayer.enableHardwareDecode(true);
} }
} }
} }
...@@ -305,43 +329,21 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC ...@@ -305,43 +329,21 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC
return Uninitialized; return Uninitialized;
} }
int startPlayWithParams(MethodCall call) { void startPlayWithParams(MethodCall call) {
if (mVodPlayer != null) { if (mVodPlayer != null) {
TXPlayerAuthBuilder builder = new TXPlayerAuthBuilder();
int appId = call.argument("appId"); int appId = call.argument("appId");
builder.setAppId(appId);
String fileId = call.argument("fileId"); String fileId = call.argument("fileId");
builder.setFileId(fileId); String psign = call.argument("psign");
String timeout = call.argument("timeout"); TXPlayInfoParams playInfoParams = new TXPlayInfoParams(appId, fileId, psign);
if (!timeout.isEmpty()) { mVodPlayer.startPlay(playInfoParams);
builder.setTimeout(timeout);
}
int exper = call.argument("exper");
builder.setExper(exper);
String us = call.argument("us");
if (!us.isEmpty()) {
builder.setUs(us);
}
String sign = call.argument("sign");
if (!sign.isEmpty()) {
builder.setSign(sign);
}
boolean https = call.argument("https");
builder.setHttps(https);
return mVodPlayer.startPlay(builder);
} }
return Uninitialized;
} }
int stopPlay(boolean isNeedClearLastImg) { int stopPlay(boolean isNeedClearLastImg) {
if (mVodPlayer != null) { if (mVodPlayer != null) {
return mVodPlayer.stopPlay(isNeedClearLastImg); return mVodPlayer.stopPlay(isNeedClearLastImg);
} }
mHardwareDecodeFail = false;
return Uninitialized; return Uninitialized;
} }
...@@ -520,6 +522,7 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC ...@@ -520,6 +522,7 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC
boolean enableHardwareDecode(boolean enable) { boolean enableHardwareDecode(boolean enable) {
if (mVodPlayer != null) { if (mVodPlayer != null) {
mEnableHardwareDecode = enable;
return mVodPlayer.enableHardwareDecode(enable); return mVodPlayer.enableHardwareDecode(enable);
} }
return false; return false;
......
差异被折叠。
简体中文| [English](./点播播放器-EN.md)
## SDK 下载 ## SDK 下载
腾讯云视立方 Flutter 超级播放器项目的地址是 [SuperPlayer Flutter](https://github.com/LiteAVSDK/Player_Flutter/tree/main/Flutter) 腾讯云视立方 Flutter 超级播放器项目的地址是 [SuperPlayer Flutter](https://github.com/LiteAVSDK/Player_Flutter/tree/main/Flutter)
...@@ -734,10 +736,10 @@ _controller.onPlayerState.listen((val) { }); ...@@ -734,10 +736,10 @@ _controller.onPlayerState.listen((val) { });
这就是视频播放中无缝切换的背后技术支撑,您可以使用 TXVodPlayerController 中的 isAutoPlay 开关来实现这个功能,具体做法如下: 这就是视频播放中无缝切换的背后技术支撑,您可以使用 TXVodPlayerController 中的 isAutoPlay 开关来实现这个功能,具体做法如下:
![](https://mc.qcloudimg.com/static/img/7331417ebbdfe6306fe96f4b76c8d0ad/image.jpg) ![](https://qcloudimg.tencent-cloud.cn/raw/f43ea6105d9f80c4162241ca0605b8f0.png)
```dart ```dart
// 播放视频 A: 如果将 isAutoPlay 设置为 YES, 那么 startPlay 调用会立刻开始视频的加载和播放 // 播放视频 A: 如果将 isAutoPlay 设置为 true, 那么 startPlay 调用会立刻开始视频的加载和播放
String url_A = "http://1252463788.vod2.myqcloud.com/xxxxx/v.f10.mp4"; String url_A = "http://1252463788.vod2.myqcloud.com/xxxxx/v.f10.mp4";
await _controller_A.setIsAutoPlay(isAutoPlay: true); await _controller_A.setIsAutoPlay(isAutoPlay: true);
await _controller_A.play(url_A); await _controller_A.play(url_A);
......
差异被折叠。
简体中文| [English](./直播播放器-EN.md)
## 基础知识 ## 基础知识
本文主要介绍视频云 SDK 的直播播放功能,在此之前,先了解如下一些基本知识会大有裨益: 本文主要介绍视频云 SDK 的直播播放功能,在此之前,先了解如下一些基本知识会大有裨益:
- **直播和点播** - **直播和点播**
......
差异被折叠。
简体中文| [English](./超级播放器-EN.md)
## SDK 下载 ## SDK 下载
腾讯云视立方 Flutter 超级播放器项目的地址是 [SuperPlayer Flutter](https://github.com/LiteAVSDK/Player_Flutter/tree/main/Flutter) 腾讯云视立方 Flutter 超级播放器项目的地址是 [SuperPlayer Flutter](https://github.com/LiteAVSDK/Player_Flutter/tree/main/Flutter)
......
...@@ -44,3 +44,4 @@ app.*.map.json ...@@ -44,3 +44,4 @@ app.*.map.json
/android/app/debug /android/app/debug
/android/app/profile /android/app/profile
/android/app/release /android/app/release
pubspec.lock
\ No newline at end of file
...@@ -25,13 +25,13 @@ apply plugin: 'com.android.application' ...@@ -25,13 +25,13 @@ apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android { android {
compileSdkVersion 28 compileSdkVersion 31
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.super_player_example" applicationId "com.example.super_player_example"
minSdkVersion 19 minSdkVersion 19
targetSdkVersion 28 targetSdkVersion 31
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
} }
......
...@@ -149,6 +149,7 @@ ...@@ -149,6 +149,7 @@
97C146EC1CF9000F007C117D /* Resources */, 97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */, 9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
54EBAF69D81CC6E332D3F9A7 /* [CP] Embed Pods Frameworks */,
); );
buildRules = ( buildRules = (
); );
...@@ -242,6 +243,23 @@ ...@@ -242,6 +243,23 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
}; };
54EBAF69D81CC6E332D3F9A7 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = { 9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
......
// Copyright (c) 2022 Tencent. All rights reserved.
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:super_player/super_player.dart'; import 'package:super_player/super_player.dart';
...@@ -26,13 +27,7 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> { ...@@ -26,13 +27,7 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
_controller.onSimplePlayerEventBroadcast.listen((event) { _controller.onSimplePlayerEventBroadcast.listen((event) {
String evtName = event["event"]; String evtName = event["event"];
if (evtName == SuperPlayerViewEvent.onStartFullScreenPlay) { if (evtName == SuperPlayerViewEvent.onStartFullScreenPlay) {
setState(() {
_isFullScreen = true;
});
} else if (evtName == SuperPlayerViewEvent.onStopFullScreenPlay) { } else if (evtName == SuperPlayerViewEvent.onStopFullScreenPlay) {
setState(() {
_isFullScreen = false;
});
} else { } else {
print(evtName); print(evtName);
} }
...@@ -122,7 +117,7 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> { ...@@ -122,7 +117,7 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
showDialog( showDialog(
context: context, context: context,
builder: (context) { builder: (context) {
return DemoInputDialog("", 0, "", (String url, int appId, String fileId) { return DemoInputDialog("", 0, "", (String url, int appId, String fileId, String pSign) {
SuperPlayerModel model = new SuperPlayerModel(); SuperPlayerModel model = new SuperPlayerModel();
model.appId = appId; model.appId = appId;
if (url.isNotEmpty) { if (url.isNotEmpty) {
...@@ -130,13 +125,16 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> { ...@@ -130,13 +125,16 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
} else if (appId != 0 && fileId.isNotEmpty) { } else if (appId != 0 && fileId.isNotEmpty) {
model.videoId = new SuperPlayerVideoId(); model.videoId = new SuperPlayerVideoId();
model.videoId!.fileId = fileId; model.videoId!.fileId = fileId;
if (pSign.isNotEmpty) {
model.videoId!.psign = pSign;
}
} else { } else {
EasyLoading.showError("请输入播放地址!"); EasyLoading.showError("请输入播放地址!");
return; return;
} }
playCurrentModel(model); playCurrentModel(model);
}); }, needPisgn: true);
}); });
} }
...@@ -153,14 +151,7 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> { ...@@ -153,14 +151,7 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
model.appId = 1500005830; model.appId = 1500005830;
model.videoId = new SuperPlayerVideoId(); model.videoId = new SuperPlayerVideoId();
model.videoId!.fileId = "8602268011437356984"; model.videoId!.fileId = "8602268011437356984";
model.title = "云点播"; model.title = "云点播(fileId播放)";
model.playAction = playAction;
models.add(model);
model = SuperPlayerModel();
model.appId = 1252463788;
model.videoId = new SuperPlayerVideoId();
model.videoId!.fileId = "5285890781763144364";
model.playAction = playAction; model.playAction = playAction;
models.add(model); models.add(model);
...@@ -215,6 +206,8 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> { ...@@ -215,6 +206,8 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
void dispose() { void dispose() {
// must invoke when page exit. // must invoke when page exit.
_controller.releasePlayer(); _controller.releasePlayer();
// restore page brightness
SuperPlayerPlugin.restorePageBrightness();
super.dispose(); super.dispose();
} }
} }
// Copyright (c) 2022 Tencent. All rights reserved.
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
...@@ -13,10 +14,9 @@ class DemoTXLivePlayer extends StatefulWidget { ...@@ -13,10 +14,9 @@ class DemoTXLivePlayer extends StatefulWidget {
_DemoTXLivelayerState createState() => _DemoTXLivelayerState(); _DemoTXLivelayerState createState() => _DemoTXLivelayerState();
} }
class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingObserver{ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingObserver {
late TXLivePlayerController _controller; late TXLivePlayerController _controller;
double _aspectRatio = 0; double _aspectRatio = 16.0 / 9.0;
double _progress = 0.0; double _progress = 0.0;
int _volume = 100; int _volume = 100;
bool _isMute = false; bool _isMute = false;
...@@ -32,22 +32,31 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO ...@@ -32,22 +32,31 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
_controller = TXLivePlayerController(); _controller = TXLivePlayerController();
_controller.onPlayerEventBroadcast.listen((event) {//订阅事件分发 _controller.onPlayerEventBroadcast.listen((event) {
if(event["event"] == TXVodPlayEvent.PLAY_EVT_PLAY_PROGRESS) { //订阅事件分发
if (event["event"] == TXVodPlayEvent.PLAY_EVT_PLAY_PROGRESS) {
_progress = event["EVT_PLAY_PROGRESS"].toDouble(); _progress = event["EVT_PLAY_PROGRESS"].toDouble();
_maxLiveProgressTime = _progress >= _maxLiveProgressTime ? _progress : _maxLiveProgressTime; _maxLiveProgressTime = _progress >= _maxLiveProgressTime ? _progress : _maxLiveProgressTime;
progressSliderKey.currentState?.updatePorgess(1, _maxLiveProgressTime); progressSliderKey.currentState?.updatePorgess(1, _maxLiveProgressTime);
} else if (event["event"] == TXVodPlayEvent.PLAY_EVT_PLAY_BEGIN ||
}else if (event["event"] == TXVodPlayEvent.PLAY_EVT_PLAY_BEGIN || event["event"] == TXVodPlayEvent.PLAY_EVT_RCV_FIRST_I_FRAME) {//首帧出现 event["event"] == TXVodPlayEvent.PLAY_EVT_RCV_FIRST_I_FRAME) {
//首帧出现
_isStop = false; _isStop = false;
EasyLoading.dismiss(); EasyLoading.dismiss();
}else if (event["event"] == TXVodPlayEvent.PLAY_EVT_STREAM_SWITCH_SUCC) {//切换流成功 } else if (event["event"] == TXVodPlayEvent.PLAY_EVT_STREAM_SWITCH_SUCC) {
//切换流成功
EasyLoading.dismiss(); EasyLoading.dismiss();
if (_url == "http://liteavapp.qcloud.com/live/liteavdemoplayerstreamid_demo1080p.flv") { if (_url == "http://liteavapp.qcloud.com/live/liteavdemoplayerstreamid_demo1080p.flv") {
EasyLoading.showSuccess('切换到1080p!'); EasyLoading.showSuccess('切换到1080p!');
}else { } else {
EasyLoading.showSuccess('切换到480p!'); EasyLoading.showSuccess('切换到480p!');
} }
} else if (event["event"] == TXVodPlayEvent.PLAY_ERR_STREAM_SWITCH_FAIL) {
EasyLoading.dismiss();
EasyLoading.showError("切流失败");
switchUrl();
}else if(event["event"] == TXVodPlayEvent.PLAY_EVT_CHANGE_RESOLUTION) {
LogUtils.w("PLAY_EVT_CHANGE_RESOLUTION", event);
} }
}); });
...@@ -55,14 +64,15 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO ...@@ -55,14 +64,15 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
double w = (event[TXVodNetEvent.NET_STATUS_VIDEO_WIDTH]).toDouble(); double w = (event[TXVodNetEvent.NET_STATUS_VIDEO_WIDTH]).toDouble();
double h = (event[TXVodNetEvent.NET_STATUS_VIDEO_HEIGHT]).toDouble(); double h = (event[TXVodNetEvent.NET_STATUS_VIDEO_HEIGHT]).toDouble();
if(w > 0 && h > 0) { if (w > 0 && h > 0) {
setState(() { setState(() {
_aspectRatio = 1.0 * w / h; _aspectRatio = 1.0 * w / h;
}); });
} }
}); });
_controller.onPlayerState.listen((event) {//订阅状态变化 _controller.onPlayerState.listen((event) {
//订阅状态变化
debugPrint("播放状态 ${event!.name}"); debugPrint("播放状态 ${event!.name}");
}); });
...@@ -98,6 +108,14 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO ...@@ -98,6 +108,14 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
} }
} }
void switchUrl() {
if (_url == "http://liteavapp.qcloud.com/live/liteavdemoplayerstreamid_demo480p.flv") {
_url = "http://liteavapp.qcloud.com/live/liteavdemoplayerstreamid_demo1080p.flv";
} else {
_url = "http://liteavapp.qcloud.com/live/liteavdemoplayerstreamid_demo480p.flv";
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
...@@ -116,7 +134,7 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO ...@@ -116,7 +134,7 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
child: Column( child: Column(
children: [ children: [
Container( Container(
height: 250, height: 220,
color: Colors.black, color: Colors.black,
child: Center( child: Center(
child: _aspectRatio > 0 child: _aspectRatio > 0
...@@ -203,17 +221,8 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO ...@@ -203,17 +221,8 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
EasyLoading.showError('已经停止播放,请重新播放'); EasyLoading.showError('已经停止播放,请重新播放');
return; return;
} }
switchUrl();
if (_url == _controller.switchStream(_url);
"http://liteavapp.qcloud.com/live/liteavdemoplayerstreamid_demo480p.flv") {
_url =
"http://liteavapp.qcloud.com/live/liteavdemoplayerstreamid_demo1080p.flv";
_controller.switchStream(_url);
} else {
_url =
"http://liteavapp.qcloud.com/live/liteavdemoplayerstreamid_demo480p.flv";
_controller.switchStream(_url);
}
EasyLoading.show(status: 'loading...'); EasyLoading.show(status: 'loading...');
}, },
...@@ -241,17 +250,17 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO ...@@ -241,17 +250,17 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
), ),
), ),
new GestureDetector( new GestureDetector(
onTap: () { onTap: () {
onClickVolume(); onClickVolume();
}, },
child: Container( child: Container(
alignment: Alignment.center, alignment: Alignment.center,
child: Text( child: Text(
"调整音量", "调整音量",
style: TextStyle(fontSize: 18, color: Colors.blue), style: TextStyle(fontSize: 18, color: Colors.blue),
),
), ),
), ),
),
], ],
)), )),
Expanded( Expanded(
...@@ -260,9 +269,7 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO ...@@ -260,9 +269,7 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
children: [ children: [
Container( Container(
height: 100, height: 100,
child: IconButton( child: IconButton(icon: new Image.asset('images/addp.png'), onPressed: () => {onPressed()}),
icon: new Image.asset('images/addp.png'),
onPressed: () => {onPressed()}),
) )
], ],
)), )),
...@@ -285,8 +292,7 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO ...@@ -285,8 +292,7 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
showDialog( showDialog(
context: context, context: context,
builder: (context) { builder: (context) {
return DemoInputDialog("", 0, "", return DemoInputDialog("", 0, "", (String url, int appId, String fileId,String pSign) {
(String url, int appId, String fileId) {
_url = url; _url = url;
_controller.stop(); _controller.stop();
if (url.isNotEmpty) { if (url.isNotEmpty) {
......
// Copyright (c) 2022 Tencent. All rights reserved.
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
...@@ -25,6 +26,7 @@ class _MyAppState extends State<MyApp> { ...@@ -25,6 +26,7 @@ class _MyAppState extends State<MyApp> {
super.initState(); super.initState();
initPlatformState(); initPlatformState();
initPlayerLicense(); initPlayerLicense();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
LogUtils.logOpen = true; LogUtils.logOpen = true;
} }
......
// Copyright (c) 2022 Tencent. All rights reserved.
part of demo_super_player_lib; part of demo_super_player_lib;
/// v2 request data parser /// v2 request data parser
...@@ -58,7 +59,6 @@ class PlayInfoParserV2 implements PlayInfoParser { ...@@ -58,7 +59,6 @@ class PlayInfoParserV2 implements PlayInfoParser {
int code = root['code']; int code = root['code'];
String message = root['message']; String message = root['message'];
String warning = root['warning']; String warning = root['warning'];
LogUtils.d(TAG, "_getVodListData,code=$code,message=$message,warning=$warning");
if (code != 0) { if (code != 0) {
return; return;
} }
......
// Copyright (c) 2022 Tencent. All rights reserved.
part of demo_super_player_lib; part of demo_super_player_lib;
/// v4 request data parser /// v4 request data parser
...@@ -95,9 +96,13 @@ class PlayInfoParserV4 implements PlayInfoParser { ...@@ -95,9 +96,13 @@ class PlayInfoParserV4 implements PlayInfoParser {
if (null != media['imageSpriteInfo']) { if (null != media['imageSpriteInfo']) {
Map<String, dynamic> imageSpriteInfoJson = media['imageSpriteInfo']; Map<String, dynamic> imageSpriteInfoJson = media['imageSpriteInfo'];
imageSpriteInfo = PlayImageSpriteInfo(); imageSpriteInfo = PlayImageSpriteInfo();
imageSpriteInfo?.webVttUrl = imageSpriteInfoJson['webVttUrl'] ?? ""; if (imageSpriteInfoJson != null) {
List<String> imageUrls = imageSpriteInfoJson['imageUrls']; imageSpriteInfo?.webVttUrl = imageSpriteInfoJson['webVttUrl'] ?? "";
imageSpriteInfo?.imageUrls = imageUrls; List<String> imageUrls = imageSpriteInfoJson['imageUrls'] == null
? List.empty()
: imageSpriteInfoJson['imageUrls'].cast<String>();
imageSpriteInfo?.imageUrls = imageUrls;
}
} }
_parseKeyFrameDescList(media); _parseKeyFrameDescList(media);
......
// Copyright (c) 2022 Tencent. All rights reserved.
part of demo_super_player_lib; part of demo_super_player_lib;
/// play info parser interface /// play info parser interface
......
// Copyright (c) 2022 Tencent. All rights reserved.
part of demo_super_player_lib; part of demo_super_player_lib;
/// request handler with tencent fileId /// request handler with tencent fileId
...@@ -32,7 +33,7 @@ class PlayInfoProtocol { ...@@ -32,7 +33,7 @@ class PlayInfoProtocol {
int code = root['code']; int code = root['code'];
String message = root['message']; String message = root['message'];
String warning = root['warning']; String warning = root['warning'];
LogUtils.d(TAG, "_getVodListData,code=$code,message=$message,warning=$warning"); LogUtils.d(TAG, "_getVodListData,code=($code, ${PlayInfoProtocol.GETPLAYINFOV4_ERROR_CODE_MAP[code]}),message=$message,warning=$warning");
if (code != 0) { if (code != 0) {
onError(code, message); onError(code, message);
return; return;
...@@ -66,7 +67,7 @@ class PlayInfoProtocol { ...@@ -66,7 +67,7 @@ class PlayInfoProtocol {
return null; return null;
} }
String makeQueryString(String? pcfg, String? psign, String? content) { static String makeQueryString(String? pcfg, String? psign, String? content) {
String result = ""; String result = "";
if (null != pcfg) { if (null != pcfg) {
result += "pcfg=$pcfg&"; result += "pcfg=$pcfg&";
...@@ -137,4 +138,29 @@ class PlayInfoProtocol { ...@@ -137,4 +138,29 @@ class PlayInfoProtocol {
String? getDRMType() { String? getDRMType() {
return null == _playInfoParser ? null : _playInfoParser?.drmType; return null == _playInfoParser ? null : _playInfoParser?.drmType;
} }
static String? getV4ErrorCodeDescription(int errorCode) {
return GETPLAYINFOV4_ERROR_CODE_MAP[errorCode];
}
// getplayinfo/v4错误码
// http状态码 200 403
// 403一般鉴权信息不通过或者请求不合法
// 状态码为200的时候才会有http body
// code错误码[1000-2000)请求有问题,
// code错误码[2000-3000)服务端错误,可发起重试
static Map<int, String> GETPLAYINFOV4_ERROR_CODE_MAP = {
0 : 'success',
1001 : '文件不存在',
1002 : '试看时长不合法',
1003 : 'pcfg不唯一',
1004 : 'license过期',
1005 : '没有自适应码流',
1006 : '请求格式不合法',
1007 : '用户存在',
1008 : '没带防盗链信息',
1009 : 'psign检查失败',
1010 : '其他错误',
2001 : '内部错误',
};
} }
// Copyright (c) 2022 Tencent. All rights reserved.
part of demo_super_player_lib; part of demo_super_player_lib;
/// request data handler /// request data handler
...@@ -13,8 +14,11 @@ class SuperVodDataLoader { ...@@ -13,8 +14,11 @@ class SuperVodDataLoader {
String field = model.videoId != null String field = model.videoId != null
? (model.videoId as SuperPlayerVideoId).fileId ? (model.videoId as SuperPlayerVideoId).fileId
: ""; : "";
String psign = model.videoId != null
? (model.videoId as SuperPlayerVideoId).psign
: "";
var url = _BASE_URL + "/$appId/$field"; var url = _BASE_URL + "/$appId/$field";
var query = makeQueryString(null, null, -1, null); var query = PlayInfoProtocol.makeQueryString(null, psign, null);
if (query != null) { if (query != null) {
url = url + "?" + query; url = url + "?" + query;
} }
...@@ -29,7 +33,7 @@ class SuperVodDataLoader { ...@@ -29,7 +33,7 @@ class SuperVodDataLoader {
int code = root['code']; int code = root['code'];
String message = root['message']; String message = root['message'];
String warning = root['warning']; String warning = root['warning'];
LogUtils.d(TAG, "_getVodListData,code=$code,message=$message,warning=$warning"); LogUtils.d(TAG, "_getVodListData,code=($code, ${PlayInfoProtocol.getV4ErrorCodeDescription(code)}),message=$message,warning=$warning");
if (code != 0) { if (code != 0) {
return; return;
} }
...@@ -80,26 +84,4 @@ class SuperVodDataLoader { ...@@ -80,26 +84,4 @@ class SuperVodDataLoader {
model.title = newTitle; model.title = newTitle;
} }
} }
/// make fileId request url
String makeQueryString(String? timeout, String? us, int exper, String? sign) {
var str = new StringBuffer();
if (timeout != null) {
str.write("t=" + timeout + "&");
}
if (us != null) {
str.write("us=" + us + "&");
}
if (sign != null) {
str.write("sign=" + sign + "&");
}
if (exper >= 0) {
str.write("exper=$exper" + "&");
}
String result = str.toString();
if (result.length > 1) {
result = result.substring(0, result.length - 1);
}
return result;
}
} }
// Copyright (c) 2022 Tencent. All rights reserved.
part of demo_super_player_lib; part of demo_super_player_lib;
/// colors resource /// colors resource
class ColorResource { class ColorResource {
static const COLOR_MAIN_THEME = 0xFFFF4C58; static const COLOR_MAIN_THEME = 0xFFFF4C58;
static const COLOR_GRAY = 0xFFBBBBBB; static const COLOR_GRAY = 0xFFBBBBBB;
static const COLOR_TRANS_BLACK = 0xBB000000; static const COLOR_TRANS_BLACK = 0xBB000000;
static const COLOR_WHITE = 0xFFFFFFFF;
} }
\ No newline at end of file
// Copyright (c) 2022 Tencent. All rights reserved.
part of demo_super_player_lib; part of demo_super_player_lib;
/// string resource /// string resource
...@@ -10,4 +11,9 @@ class StringResource { ...@@ -10,4 +11,9 @@ class StringResource {
static const QUALITY_FHD2 = "超清"; static const QUALITY_FHD2 = "超清";
static const QUALITY_2K = "2K"; static const QUALITY_2K = "2K";
static const QUALITY_4K = "4k"; static const QUALITY_4K = "4k";
static const VOICE_LABEL = "声音";
static const BRIGHTNESS_LABEL = "亮度";
static const MULITIPE_SPEED_PLAY_LABEL = "多倍速播放";
static const HARDWARE_ACCE_LABEL = "硬件加速";
} }
// Copyright (c) 2022 Tencent. All rights reserved.
part of demo_super_player_lib;
/// 样式资源
class ThemeResource {
/// 获得通用进度条样式
static ThemeData getCommonSliderTheme() {
return ThemeData(
sliderTheme: SliderThemeData(
trackHeight: 2,
thumbColor: Color(ColorResource.COLOR_MAIN_THEME),
thumbShape: RoundSliderThumbShape(enabledThumbRadius: 4),
overlayColor: Colors.white,
overlayShape: RoundSliderOverlayShape(overlayRadius: 10),
activeTrackColor: Color(ColorResource.COLOR_MAIN_THEME),
inactiveTrackColor: Color(ColorResource.COLOR_GRAY),
));
}
static TextStyle getCommonLabelTextStyle() {
return TextStyle(fontSize: 14, color: Colors.white);
}
static TextStyle getCheckedLabelTextStyle() {
return TextStyle(fontSize: 14, color: Color(ColorResource.COLOR_MAIN_THEME));
}
static TextStyle getCommonTextStyle() {
return TextStyle(fontSize: 13, color: Colors.white);
}
static TextStyle getCheckedTextStyle() {
return TextStyle(fontSize: 13, color: Color(ColorResource.COLOR_MAIN_THEME));
}
}
// Copyright (c) 2022 Tencent. All rights reserved.
library demo_super_player_lib; library demo_super_player_lib;
import 'dart:async'; import 'dart:async';
...@@ -8,6 +9,7 @@ import 'dart:math'; ...@@ -8,6 +9,7 @@ import 'dart:math';
import 'package:auto_orientation/auto_orientation.dart'; import 'package:auto_orientation/auto_orientation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:super_player/super_player.dart'; import 'package:super_player/super_player.dart';
...@@ -25,5 +27,8 @@ part 'ui/superplayer_bottom_view.dart'; ...@@ -25,5 +27,8 @@ part 'ui/superplayer_bottom_view.dart';
part 'ui/superplayer_quality_view.dart'; part 'ui/superplayer_quality_view.dart';
part 'ui/superplayer_title_view.dart'; part 'ui/superplayer_title_view.dart';
part 'ui/superplayer_widget.dart'; part 'ui/superplayer_widget.dart';
part 'ui/superplayer_cover_view.dart';
part 'ui/superplayer_more_view.dart';
part 'common/color_resource.dart'; part 'common/color_resource.dart';
part 'common/string_resource.dart'; part 'common/string_resource.dart';
\ No newline at end of file part 'common/theme_resource.dart';
\ No newline at end of file
// Copyright (c) 2022 Tencent. All rights reserved.
part of demo_super_player_lib; part of demo_super_player_lib;
enum SuperPlayerState { enum SuperPlayerState {
......
// Copyright (c) 2022 Tencent. All rights reserved.
part of demo_super_player_lib; part of demo_super_player_lib;
class PlayInfoStream { class PlayInfoStream {
......
// Copyright (c) 2022 Tencent. All rights reserved.
part of demo_super_player_lib; part of demo_super_player_lib;
/// superplayer play controller /// superplayer play controller
class SuperPlayerController { class SuperPlayerController {
...@@ -32,6 +33,7 @@ class SuperPlayerController { ...@@ -32,6 +33,7 @@ class SuperPlayerController {
bool _isMultiBitrateStream = false; // 是否是多码流url播放 bool _isMultiBitrateStream = false; // 是否是多码流url播放
bool _changeHWAcceleration = false; // 切换硬解后接收到第一个关键帧前的标记位 bool _changeHWAcceleration = false; // 切换硬解后接收到第一个关键帧前的标记位
bool _isFullScreen = false; bool _isFullScreen = false;
bool _isOpenHWAcceleration = true;
final BuildContext _context; final BuildContext _context;
int currentDuration = 0; int currentDuration = 0;
...@@ -42,6 +44,7 @@ class SuperPlayerController { ...@@ -42,6 +44,7 @@ class SuperPlayerController {
double startPos = 0; double startPos = 0;
double videoWidth = 0; double videoWidth = 0;
double videoHeight = 0; double videoHeight = 0;
double currentPlayRate = 1.0;
SuperPlayerController(this._context) { SuperPlayerController(this._context) {
_initVodPlayer(); _initVodPlayer();
...@@ -89,7 +92,16 @@ class SuperPlayerController { ...@@ -89,7 +92,16 @@ class SuperPlayerController {
} }
break; break;
case TXVodPlayEvent.PLAY_EVT_PLAY_LOADING: // PLAY_EVT_PLAY_LOADING case TXVodPlayEvent.PLAY_EVT_PLAY_LOADING: // PLAY_EVT_PLAY_LOADING
_updatePlayerState(SuperPlayerState.LOADING); if (playerState == SuperPlayerState.PAUSE) {
_updatePlayerState(SuperPlayerState.PAUSE);
} else {
_updatePlayerState(SuperPlayerState.LOADING);
}
break;
case TXVodPlayEvent.PLAY_EVT_VOD_LOADING_END:
if (playerState == SuperPlayerState.LOADING) {
_updatePlayerState(SuperPlayerState.PLAYING);
}
break; break;
case TXVodPlayEvent.PLAY_EVT_PLAY_BEGIN: // PLAY_EVT_PLAY_BEGIN case TXVodPlayEvent.PLAY_EVT_PLAY_BEGIN: // PLAY_EVT_PLAY_BEGIN
if (_needToPause) { if (_needToPause) {
...@@ -107,6 +119,7 @@ class SuperPlayerController { ...@@ -107,6 +119,7 @@ class SuperPlayerController {
seek(_seekPos); seek(_seekPos);
_changeHWAcceleration = false; _changeHWAcceleration = false;
} }
_updatePlayerState(SuperPlayerState.PLAYING); _updatePlayerState(SuperPlayerState.PLAYING);
_observer?.onRcvFirstIframe(); _observer?.onRcvFirstIframe();
break; break;
...@@ -114,25 +127,19 @@ class SuperPlayerController { ...@@ -114,25 +127,19 @@ class SuperPlayerController {
_updatePlayerState(SuperPlayerState.END); _updatePlayerState(SuperPlayerState.END);
break; break;
case TXVodPlayEvent.PLAY_EVT_PLAY_PROGRESS: case TXVodPlayEvent.PLAY_EVT_PLAY_PROGRESS:
dynamic progress = event[TXVodPlayEvent.EVT_PLAY_PROGRESS_MS]; dynamic progress = event[TXVodPlayEvent.EVT_PLAY_PROGRESS];
dynamic duration = event[TXVodPlayEvent.EVT_PLAY_DURATION_MS]; dynamic duration = event[TXVodPlayEvent.EVT_PLAY_DURATION];
if(null != progress) { if (null != progress) {
currentDuration = (progress / 1000).toInt(); // 当前时间,转换后的单位 秒 currentDuration = progress.toInt(); // 当前时间,转换后的单位 秒
} }
if(null != duration) { if (null != duration) {
videoDuration = (duration / 1000).toInt(); // 总播放时长,转换后的单位 秒 videoDuration = duration.toInt(); // 总播放时长,转换后的单位 秒
} }
if (videoDuration != 0) { if (videoDuration != 0) {
_observer?.onPlayProgress(currentDuration, videoDuration); _observer?.onPlayProgress(currentDuration, videoDuration);
} }
break; break;
} }
if (eventCode < 0) {
_stopPlay();
_updatePlayerState(SuperPlayerState.PAUSE);
_observer?.onError(SuperPlayerCode.VOD_PLAY_FAIL, event[TXVodPlayEvent.EVT_DESCRIPTION]);
_addSimpleEvent(SuperPlayerViewEvent.onSuperPlayerError);
}
_eventStreamController.add(event); _eventStreamController.add(event);
}); });
_vodPlayerController?.onPlayerNetStatusBroadcast.listen((event) { _vodPlayerController?.onPlayerNetStatusBroadcast.listen((event) {
...@@ -164,10 +171,10 @@ class SuperPlayerController { ...@@ -164,10 +171,10 @@ class SuperPlayerController {
void playWithModel(SuperPlayerModel videoModel) { void playWithModel(SuperPlayerModel videoModel) {
this.videoModel = videoModel; this.videoModel = videoModel;
_playAction = videoModel.playAction; _playAction = videoModel.playAction;
resetPlayer();
if (_playAction == SuperPlayerModel.PLAY_ACTION_AUTO_PLAY || _playAction == SuperPlayerModel.PLAY_ACTION_PRELOAD) { if (_playAction == SuperPlayerModel.PLAY_ACTION_AUTO_PLAY || _playAction == SuperPlayerModel.PLAY_ACTION_PRELOAD) {
_playWithModelInner(videoModel); _playWithModelInner(videoModel);
} else { } else {
resetPlayer();
_observer?.onNewVideoPlay(); _observer?.onNewVideoPlay();
} }
} }
...@@ -267,17 +274,17 @@ class SuperPlayerController { ...@@ -267,17 +274,17 @@ class SuperPlayerController {
if (null != _vodPlayerController) { if (null != _vodPlayerController) {
await _vodPlayerController?.setStartTime(startPos); await _vodPlayerController?.setStartTime(startPos);
if (_playAction == SuperPlayerModel.PLAY_ACTION_PRELOAD) { if (_playAction == SuperPlayerModel.PLAY_ACTION_PRELOAD) {
await _vodPlayerController?.setIsAutoPlay(isAutoPlay: false); await _vodPlayerController?.setAutoPlay(isAutoPlay: false);
_playAction = SuperPlayerModel.PLAY_ACTION_AUTO_PLAY; _playAction = SuperPlayerModel.PLAY_ACTION_AUTO_PLAY;
} else if (_playAction == SuperPlayerModel.PLAY_ACTION_AUTO_PLAY || } else if (_playAction == SuperPlayerModel.PLAY_ACTION_AUTO_PLAY ||
_playAction == SuperPlayerModel.PLAY_ACTION_MANUAL_PLAY) { _playAction == SuperPlayerModel.PLAY_ACTION_MANUAL_PLAY) {
await _vodPlayerController?.setIsAutoPlay(isAutoPlay: true); await _vodPlayerController?.setAutoPlay(isAutoPlay: true);
} }
String drmType = "plain"; String drmType = "plain";
if (_currentProtocol != null) { if (_currentProtocol != null) {
LogUtils.d(TAG, "TOKEN: ${_currentProtocol!.getToken()}"); LogUtils.d(TAG, "TOKEN: ${_currentProtocol!.getToken()}");
await _vodPlayerController?.setToken(_currentProtocol!.getToken()); await _vodPlayerController?.setToken(_currentProtocol!.getToken());
if(_currentProtocol!.getDRMType() != null && _currentProtocol!.getDRMType()!.isNotEmpty) { if (_currentProtocol!.getDRMType() != null && _currentProtocol!.getDRMType()!.isNotEmpty) {
drmType = _currentProtocol!.getDRMType()!; drmType = _currentProtocol!.getDRMType()!;
} }
} else { } else {
...@@ -286,14 +293,14 @@ class SuperPlayerController { ...@@ -286,14 +293,14 @@ class SuperPlayerController {
if (videoModel!.videoId != null && videoModel!.appId != 0) { if (videoModel!.videoId != null && videoModel!.appId != 0) {
Uri uri = Uri.parse(url); Uri uri = Uri.parse(url);
String query = uri.query; String query = uri.query;
if(query == null || query.isEmpty) { if (query == null || query.isEmpty) {
query = ""; query = "";
} else { } else {
query = query + "&"; query = query + "&";
if (query.contains("spfileid") || query.contains("spdrmtype") || query.contains("spappid")) { if (query.contains("spfileid") || query.contains("spdrmtype") || query.contains("spappid")) {
LogUtils.d(TAG, "url contains superplay key. $query"); LogUtils.d(TAG, "url contains superplay key. $query");
} }
query += "spfileid=${videoModel!.videoId!.fileId}""&spdrmtype=$drmType&spappid=${videoModel!.appId}"; query += "spfileid=${videoModel!.videoId!.fileId}" "&spdrmtype=$drmType&spappid=${videoModel!.appId}";
} }
} }
LogUtils.d(TAG, "play url:$url"); LogUtils.d(TAG, "play url:$url");
...@@ -316,11 +323,11 @@ class SuperPlayerController { ...@@ -316,11 +323,11 @@ class SuperPlayerController {
} }
/// 继续播放视频 /// 继续播放视频
void resume() { void resume() {
if (playerType == SuperPlayerType.VOD) { if (playerType == SuperPlayerType.VOD) {
_needToResume = true; _needToResume = true;
if (isPrepared) { if (isPrepared) {
_vodPlayerController?.resume(); _vodPlayerController?.resume();
} }
} else { } else {
// todo implements live player // todo implements live player
...@@ -413,13 +420,14 @@ class SuperPlayerController { ...@@ -413,13 +420,14 @@ class SuperPlayerController {
void resetPlayer() async { void resetPlayer() async {
isPrepared = false; isPrepared = false;
_needToResume = false; _needToResume = false;
_needToPause = false;
currentDuration = 0; currentDuration = 0;
videoDuration = 0; videoDuration = 0;
currentQuality = null; currentQuality = null;
currentQualiyList?.clear(); currentQualiyList?.clear();
_currentProtocol = null; _currentProtocol = null;
await _vodPlayerController?.stop(isNeedClear: false); await _vodPlayerController?.stop(isNeedClear: true);
_updatePlayerState(SuperPlayerState.INIT); _updatePlayerState(SuperPlayerState.INIT);
} }
...@@ -435,7 +443,7 @@ class SuperPlayerController { ...@@ -435,7 +443,7 @@ class SuperPlayerController {
/// return true : 执行了退出全屏等操作,消耗了返回事件 false:未消耗事件 /// return true : 执行了退出全屏等操作,消耗了返回事件 false:未消耗事件
bool onBackPress() { bool onBackPress() {
if(null != _vodPlayerController && _isFullScreen) { if (null != _vodPlayerController && _isFullScreen) {
_observer?.onSysBackPress(); _observer?.onSysBackPress();
return true; return true;
} }
...@@ -454,7 +462,7 @@ class SuperPlayerController { ...@@ -454,7 +462,7 @@ class SuperPlayerController {
if (videoQuality.url.isNotEmpty) { if (videoQuality.url.isNotEmpty) {
// url stream need manual seek // url stream need manual seek
double currentTime = await _vodPlayerController!.getCurrentPlaybackTime(); double currentTime = await _vodPlayerController!.getCurrentPlaybackTime();
await _vodPlayerController?.stop(isNeedClear: true); await _vodPlayerController?.stop(isNeedClear: false);
LogUtils.d(TAG, "onQualitySelect quality.url:${videoQuality.url}"); LogUtils.d(TAG, "onQualitySelect quality.url:${videoQuality.url}");
await _vodPlayerController?.setStartTime(currentTime); await _vodPlayerController?.setStartTime(currentTime);
await _vodPlayerController?.startPlay(videoQuality.url); await _vodPlayerController?.startPlay(videoQuality.url);
...@@ -476,7 +484,7 @@ class SuperPlayerController { ...@@ -476,7 +484,7 @@ class SuperPlayerController {
bool? isPlaying = await _vodPlayerController?.isPlaying(); bool? isPlaying = await _vodPlayerController?.isPlaying();
// resume when not playing.if isPlaying is null,not resume // resume when not playing.if isPlaying is null,not resume
if (!(isPlaying ?? true)) { if (!(isPlaying ?? true)) {
_vodPlayerController?.resume(); resume();
} }
} else { } else {
// todo implements live player // todo implements live player
...@@ -491,6 +499,7 @@ class SuperPlayerController { ...@@ -491,6 +499,7 @@ class SuperPlayerController {
/// 开关硬解编码播放 /// 开关硬解编码播放
Future<void> enableHardwareDecode(bool enable) async { Future<void> enableHardwareDecode(bool enable) async {
_isOpenHWAcceleration = enable;
if (playerType == SuperPlayerType.VOD) { if (playerType == SuperPlayerType.VOD) {
if (null != _vodPlayerController) { if (null != _vodPlayerController) {
await _vodPlayerController?.enableHardwareDecode(enable); await _vodPlayerController?.enableHardwareDecode(enable);
...@@ -512,6 +521,11 @@ class SuperPlayerController { ...@@ -512,6 +521,11 @@ class SuperPlayerController {
} }
} }
Future<void> setPlayRate(double rate) async {
currentPlayRate = rate;
_vodPlayerController?.setRate(rate);
}
/// 获得当前播放器状态 /// 获得当前播放器状态
SuperPlayerState getPlayerState() { SuperPlayerState getPlayerState() {
return playerState; return playerState;
......
// Copyright (c) 2022 Tencent. All rights reserved.
part of demo_super_player_lib; part of demo_super_player_lib;
/// superplayer's bridge between widget and controller /// superplayer's bridge between widget and controller
......
// Copyright (c) 2022 Tencent. All rights reserved.
part of demo_super_player_lib; part of demo_super_player_lib;
/// video quality utils /// video quality utils
......
// Copyright (c) 2022 Tencent. All rights reserved.
part of demo_super_player_lib; part of demo_super_player_lib;
/// slider /// slider
...@@ -123,16 +124,7 @@ class _VideoBottomViewState extends State<VideoBottomView> { ...@@ -123,16 +124,7 @@ class _VideoBottomViewState extends State<VideoBottomView> {
Widget _getSlider() { Widget _getSlider() {
return Expanded( return Expanded(
child: Theme( child: Theme(
data: ThemeData( data: ThemeResource.getCommonSliderTheme(),
sliderTheme: SliderThemeData(
trackHeight: 2,
thumbColor: Color(ColorResource.COLOR_MAIN_THEME),
thumbShape: RoundSliderThumbShape(enabledThumbRadius: 4),
overlayColor: Colors.white,
overlayShape: RoundSliderOverlayShape(overlayRadius: 10),
activeTrackColor: Color(ColorResource.COLOR_MAIN_THEME),
inactiveTrackColor: Color(ColorResource.COLOR_GRAY),
)),
child: Slider( child: Slider(
min: 0, min: 0,
max: 1, max: 1,
......
// Copyright (c) 2022 Tencent. All rights reserved.
part of demo_super_player_lib;
class SuperPlayerCoverView extends StatefulWidget {
final _CoverViewController _controller;
SuperPlayerModel? videoModel;
SuperPlayerCoverView(this._controller, GlobalKey<_SuperPlayerCoverViewState> key, this.videoModel) : super(key: key);
@override
State<StatefulWidget> createState() => _SuperPlayerCoverViewState();
}
class _SuperPlayerCoverViewState extends State<SuperPlayerCoverView> {
bool _isShowCover = true;
SuperPlayerModel? _videoModel;
@override
void initState() {
super.initState();
if (widget.videoModel != null) {
_isShowCover = true;
_videoModel = widget.videoModel;
} else {
_isShowCover = false;
}
}
@override
Widget build(BuildContext context) {
bool hasCover = false;
String coverUrl = "";
if (null != _videoModel) {
SuperPlayerModel model = _videoModel!;
// custom cover is preferred
if (model.customeCoverUrl.isNotEmpty) {
coverUrl = model.customeCoverUrl;
hasCover = true;
} else if (model.coverUrl.isNotEmpty) {
coverUrl = model.coverUrl;
hasCover = true;
}
}
return Visibility(
visible: _isShowCover,
child: Positioned.fill(
top: topBottomOffset,
bottom: topBottomOffset,
left: 0,
right: 0,
child: InkWell(
onDoubleTap: _onDoubleTapVideo,
onTap: _onSingleTapVideo,
child: Container(
child: hasCover ? Image.network(coverUrl,fit: BoxFit.cover,) : Container(),
)
)),
);
}
void _onDoubleTapVideo() {
widget._controller.onDoubleTapVideo();
}
void _onSingleTapVideo() {
widget._controller.onSingleTapVideo();
}
void showCover(SuperPlayerModel model) {
setState(() {
_videoModel = model;
_isShowCover = true;
});
}
void hideCover() {
setState(() {
_isShowCover = false;
});
}
}
class _CoverViewController {
Function onDoubleTapVideo;
Function onSingleTapVideo;
_CoverViewController(this.onDoubleTapVideo, this.onSingleTapVideo);
}
// Copyright (c) 2022 Tencent. All rights reserved.
part of demo_super_player_lib;
typedef BoolFunction = bool Function();
typedef DoubleFunction = double Function();
/// 超级播放器更多菜单
class SuperPlayerMoreView extends StatefulWidget {
_MoreViewController controller;
SuperPlayerMoreView(this.controller, {Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _SuperPlayerMoreViewState();
}
class _SuperPlayerMoreViewState extends State<SuperPlayerMoreView> {
double _currentBrightness = 0.01;
double _currentVolumn = 0;
bool _isShowMoreView = false;
bool _isOpenAccelerate = true;
String _currentRate = "";
Map<String, double> playRateStr = {"1.0x": 1.0, "1.25x": 1.25, "1.5x": 1.5, "2.0x": 2.0};
@override
void initState() {
super.initState();
double playerPlayRate = widget.controller.getPlayRate();
for(String rateStr in playRateStr.keys) {
if(playerPlayRate == playRateStr[rateStr]) {
_currentRate = rateStr;
break;
}
}
// if not found in playRateStr,set 1.0
if(_currentRate.isEmpty) {
_currentRate = playRateStr.keys.first;
}
_isOpenAccelerate = widget.controller.getAccelerateIsOpen();
// regist system volume changed event
SuperPlayerPlugin.instance.onEventBroadcast.listen((event) {
int code = event["event"];
if (code == TXVodPlayEvent.EVENT_VOLUME_CHANGED) {
refreshVolume();
}
});
_initData();
}
void refreshVolume() async {
_currentVolumn = await SuperPlayerPlugin.getSystemVolume();
setState(() {});
}
void _initData() async {
double tempBrightness = await SuperPlayerPlugin.getBrightness();
if (tempBrightness == -1) {
_onChangeBrightness(1);
} else {
_currentBrightness = tempBrightness;
}
_currentVolumn = await SuperPlayerPlugin.getSystemVolume();
setState(() {});
}
@override
Widget build(BuildContext context) {
return Visibility(
visible: _isShowMoreView,
child: Positioned(
right: 0,
bottom: 0,
top: 0,
child: Container(
height: double.infinity,
width: 320,
padding: EdgeInsets.only(left: 15, right: 20, top: 15, bottom: 15),
decoration: BoxDecoration(color: Color(ColorResource.COLOR_TRANS_BLACK)),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_getVolumeWidget(),
_getBrightnessWidget(),
_getPlayRateWidget(),
_getSwitchHardwareWidget(),
],
),
)),
));
}
Widget _getSwitchHardwareWidget() {
return Container(
margin: EdgeInsets.only(top: 10, bottom: 10),
child: Row(
children: [
Text(
StringResource.HARDWARE_ACCE_LABEL,
textAlign: TextAlign.center,
style: ThemeResource.getCommonLabelTextStyle(),
),
Switch(
activeColor: Color(ColorResource.COLOR_MAIN_THEME),
value: _isOpenAccelerate,
onChanged: _onChangeAccelerate)
],
),
);
}
Widget _getPlayRateWidget() {
List<Widget> playRateChild = [
Text(
StringResource.MULITIPE_SPEED_PLAY_LABEL,
textAlign: TextAlign.center,
style: ThemeResource.getCommonLabelTextStyle(),
)
];
for (String rateStr in playRateStr.keys) {
playRateChild.add(Container(
padding: EdgeInsets.only(left: 5, right: 5),
child: InkWell(
onTap: () => _onChangePlayRate(rateStr),
child: Text(
rateStr,
textAlign: TextAlign.center,
style: rateStr == _currentRate ? ThemeResource.getCheckedLabelTextStyle() : ThemeResource.getCommonLabelTextStyle(),
),
),
));
}
return Container(
margin: EdgeInsets.only(top: 10, bottom: 10),
child: Row(
children: playRateChild,
),
);
}
Widget _getBrightnessWidget() {
return Container(
margin: EdgeInsets.only(top: 10, bottom: 10),
child: Row(children: [
Text(
StringResource.BRIGHTNESS_LABEL,
textAlign: TextAlign.center,
style: ThemeResource.getCommonLabelTextStyle(),
),
Image(width: 30, height: 30, image: AssetImage("images/superplayer_ic_light_min.png")),
Expanded(
child: Theme(
data: ThemeResource.getCommonSliderTheme(),
child: Slider(
min: 0,
max: 1,
value: _currentBrightness,
onChanged: _onChangeBrightness,
)),
),
Image(width: 30, height: 30, image: AssetImage("images/superplayer_ic_light_max.png")),
]),
);
}
Widget _getVolumeWidget() {
return Container(
margin: EdgeInsets.only(top: 10, bottom: 10),
child: Row(
children: [
Text(
StringResource.VOICE_LABEL,
textAlign: TextAlign.center,
style: ThemeResource.getCommonLabelTextStyle(),
),
Image(width: 30, height: 30, image: AssetImage("images/superplayer_ic_volume_min.png")),
Expanded(
child: Theme(
data: ThemeResource.getCommonSliderTheme(),
child: Slider(
min: 0,
max: 1,
value: _currentVolumn,
onChanged: _onChangeVolume,
)),
),
Image(width: 30, height: 30, image: AssetImage("images/superplayer_ic_volume_max.png")),
],
),
);
}
void _onChangePlayRate(String rateKey) {
if (_currentRate != rateKey) {
setState(() {
_currentRate = rateKey;
});
double rate = playRateStr[_currentRate]!;
widget.controller.onChangedPlayRate(rate);
}
}
void _onChangeBrightness(double value) {
if (_currentBrightness != value) {
setState(() {
_currentBrightness = value;
});
SuperPlayerPlugin.setBrightness(value);
}
}
void _onChangeVolume(double value) {
if (_currentVolumn != value) {
setState(() {
_currentVolumn = value;
});
SuperPlayerPlugin.setSystemVolume(value);
}
}
void _onChangeAccelerate(bool value) {
if (value != _isOpenAccelerate) {
setState(() {
_isOpenAccelerate = value;
});
widget.controller.siwtchAccelerate(value);
}
}
void toggleShowMoreView() {
setState(() {
_isShowMoreView = !_isShowMoreView;
});
}
void hideShowMoreView() {
if (_isShowMoreView) {
setState(() {
_isShowMoreView = false;
});
}
}
}
class _MoreViewController {
BoolFunction getAccelerateIsOpen;
DoubleFunction getPlayRate;
Function(bool value) siwtchAccelerate;
Function(double playRate) onChangedPlayRate;
_MoreViewController(this.getAccelerateIsOpen, this.getPlayRate, this.siwtchAccelerate, this.onChangedPlayRate);
}
// Copyright (c) 2022 Tencent. All rights reserved.
part of demo_super_player_lib; part of demo_super_player_lib;
class QualityListView extends StatefulWidget { class QualityListView extends StatefulWidget {
...@@ -48,8 +49,8 @@ class _QualityListViewState extends State<QualityListView> { ...@@ -48,8 +49,8 @@ class _QualityListViewState extends State<QualityListView> {
_qualityList![index].title, _qualityList![index].title,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: _currentQuality == _qualityList![index] style: _currentQuality == _qualityList![index]
? TextStyle(fontSize: 12, color: Color(ColorResource.COLOR_MAIN_THEME)) ? ThemeResource.getCheckedTextStyle()
: TextStyle(fontSize: 12, color: Colors.white), : ThemeResource.getCommonTextStyle(),
), ),
), ),
); );
......
// Copyright (c) 2022 Tencent. All rights reserved.
part of demo_super_player_lib; part of demo_super_player_lib;
class _VideoTitleView extends StatefulWidget { class _VideoTitleView extends StatefulWidget {
final String _title; final String _title;
final _VideoTitleController _controller; final _VideoTitleController _controller;
final bool initIsFullScreen;
_VideoTitleView(this._controller ,this._title, GlobalKey<_VideoTitleViewState> key):super(key: key); _VideoTitleView(this._controller, this.initIsFullScreen, this._title, GlobalKey<_VideoTitleViewState> key)
: super(key: key);
@override @override
State<StatefulWidget> createState() => _VideoTitleViewState(); State<StatefulWidget> createState() => _VideoTitleViewState();
} }
class _VideoTitleViewState extends State<_VideoTitleView> { class _VideoTitleViewState extends State<_VideoTitleView> {
String _title = ""; String _title = "";
bool _isFullScreen = false;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_title = widget._title; _title = widget._title;
_isFullScreen = widget.initIsFullScreen;
} }
@override @override
...@@ -39,26 +43,49 @@ class _VideoTitleViewState extends State<_VideoTitleView> { ...@@ -39,26 +43,49 @@ class _VideoTitleViewState extends State<_VideoTitleView> {
Text( Text(
_title, _title,
style: TextStyle(fontSize: 11, color: Colors.white), style: TextStyle(fontSize: 11, color: Colors.white),
) ),
Expanded(child: SizedBox()),
Visibility(
visible: _isFullScreen,
child: InkWell(
onTap: _onTapMore,
child: Image(
width: 30,
height: 30,
image: AssetImage("images/superplayer_ic_vod_more_normal.png"),
),
))
], ],
), ),
); );
} }
void _onTapMore() {
widget._controller._onTapMore();
}
void _onTapBackBtn() { void _onTapBackBtn() {
widget._controller._onTapBack(); widget._controller._onTapBack();
} }
void updateTitle(String name) { void updateTitle(String name) {
if(mounted) { if (mounted) {
setState(() { setState(() {
_title = name; _title = name;
}); });
} }
} }
void updateFullScreen(bool showFullScreen) {
setState(() {
_isFullScreen = showFullScreen;
});
}
} }
class _VideoTitleController { class _VideoTitleController {
Function _onTapBack; Function _onTapBack;
_VideoTitleController(this._onTapBack); Function _onTapMore;
}
\ No newline at end of file _VideoTitleController(this._onTapBack, this._onTapMore);
}
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论