Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
T
tx_player_fork
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蒋俊
tx_player_fork
Commits
efb9316d
提交
efb9316d
authored
9月 02, 2022
作者:
kongdywang
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
SuperPlayer support live for Android&IOS platform
上级
2a99865e
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
36 个修改的文件
包含
599 行增加
和
226 行删除
+599
-226
README.md
Flutter/README.md
+2
-0
FTXLivePlayer.java
.../src/main/java/com/tencent/vod/flutter/FTXLivePlayer.java
+0
-0
FTXPIPManager.java
.../src/main/java/com/tencent/vod/flutter/FTXPIPManager.java
+47
-29
FTXTransformation.java
.../main/java/com/tencent/vod/flutter/FTXTransformation.java
+54
-20
FTXVodPlayer.java
...d/src/main/java/com/tencent/vod/flutter/FTXVodPlayer.java
+1
-2
SuperPlayerPlugin.java
.../main/java/com/tencent/vod/flutter/SuperPlayerPlugin.java
+5
-1
AndroidManifest.xml
Flutter/example/android/app/src/debug/AndroidManifest.xml
+0
-14
demo_superplayer.dart
Flutter/example/lib/demo_superplayer.dart
+102
-27
demo_txLiveplayer.dart
Flutter/example/lib/demo_txLiveplayer.dart
+6
-5
demo_txvodplayer.dart
Flutter/example/lib/demo_txvodplayer.dart
+3
-3
color_resource.dart
Flutter/example/lib/superplayer/common/color_resource.dart
+2
-0
superplayer_define.dart
...ter/example/lib/superplayer/model/superplayer_define.dart
+8
-1
superplayer_controller.dart
Flutter/example/lib/superplayer/superplayer_controller.dart
+0
-0
superplayer_observer.dart
Flutter/example/lib/superplayer/superplayer_observer.dart
+3
-3
superplayer_bottom_view.dart
...r/example/lib/superplayer/ui/superplayer_bottom_view.dart
+30
-30
superplayer_cover_view.dart
...er/example/lib/superplayer/ui/superplayer_cover_view.dart
+6
-2
superplayer_more_view.dart
...ter/example/lib/superplayer/ui/superplayer_more_view.dart
+20
-5
superplayer_title_view.dart
...er/example/lib/superplayer/ui/superplayer_title_view.dart
+2
-2
superplayer_video_slider.dart
.../example/lib/superplayer/ui/superplayer_video_slider.dart
+27
-15
superplayer_widget.dart
Flutter/example/lib/superplayer/ui/superplayer_widget.dart
+0
-0
pubspec.yaml
Flutter/example/pubspec.yaml
+1
-1
FTXLivePlayer.m
Flutter/ios/Classes/FTXLivePlayer.m
+41
-15
FTXTransformation.h
Flutter/ios/Classes/FTXTransformation.h
+3
-1
FTXTransformation.m
Flutter/ios/Classes/FTXTransformation.m
+20
-1
FTXVodPlayer.m
Flutter/ios/Classes/FTXVodPlayer.m
+1
-1
SuperPlayerPlugin.m
Flutter/ios/Classes/SuperPlayerPlugin.m
+4
-0
txplayer_holder.dart
Flutter/lib/Core/provider/txplayer_holder.dart
+15
-0
superplayer_plugin.dart
Flutter/lib/Core/superplayer_plugin.dart
+13
-0
txliveplayer_config.dart
Flutter/lib/Core/txliveplayer_config.dart
+65
-0
txliveplayer_controller.dart
Flutter/lib/Core/txliveplayer_controller.dart
+0
-0
txplayer_controller.dart
Flutter/lib/Core/txplayer_controller.dart
+15
-0
txplayer_define.dart
Flutter/lib/Core/txplayer_define.dart
+1
-1
txplayer_widget.dart
Flutter/lib/Core/txplayer_widget.dart
+61
-32
txvodplayer_controller.dart
Flutter/lib/Core/txvodplayer_controller.dart
+34
-11
super_player.dart
Flutter/lib/super_player.dart
+5
-2
pubspec.yaml
Flutter/pubspec.yaml
+2
-2
没有找到文件。
Flutter/README.md
浏览文件 @
efb9316d
...
...
@@ -47,6 +47,8 @@
### `pubspec.yaml`配置
**推荐flutter sdk 版本 3.0.0 及以上**
集成LiteAVSDK_Player版本,默认情况下也是集成此版本。在
`pubspec.yaml`
中增加配置
```
yaml
...
...
Flutter/android/src/main/java/com/tencent/vod/flutter/FTXLivePlayer.java
浏览文件 @
efb9316d
差异被折叠。
点击展开。
Flutter/android/src/main/java/com/tencent/vod/flutter/FTXPIPManager.java
浏览文件 @
efb9316d
...
...
@@ -205,40 +205,45 @@ public class FTXPIPManager {
return
;
}
if
(
android
.
os
.
Build
.
VERSION
.
SDK_INT
>=
android
.
os
.
Build
.
VERSION_CODES
.
O
)
{
List
<
RemoteAction
>
actions
=
new
ArrayList
<>();
// play back
Bundle
backData
=
new
Bundle
();
backData
.
putInt
(
FTXEvent
.
EXTRA_NAME_PLAY_OP
,
FTXEvent
.
EXTRA_PIP_PLAY_BACK
);
backData
.
putInt
(
FTXEvent
.
EXTRA_NAME_PLAYER_ID
,
params
.
mCurrentPlayerId
);
Intent
backIntent
=
new
Intent
(
FTXEvent
.
ACTION_PIP_PLAY_CONTROL
).
putExtras
(
backData
);
PendingIntent
preIntent
=
PendingIntent
.
getBroadcast
(
mActivity
,
FTXEvent
.
EXTRA_PIP_PLAY_BACK
,
backIntent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
|
PendingIntent
.
FLAG_IMMUTABLE
);
RemoteAction
preAction
=
new
RemoteAction
(
getBackIcon
(
params
),
"skipPre"
,
"skip pre"
,
preIntent
);
if
(
params
.
mIsNeedPlayBack
)
{
Bundle
backData
=
new
Bundle
();
backData
.
putInt
(
FTXEvent
.
EXTRA_NAME_PLAY_OP
,
FTXEvent
.
EXTRA_PIP_PLAY_BACK
);
backData
.
putInt
(
FTXEvent
.
EXTRA_NAME_PLAYER_ID
,
params
.
mCurrentPlayerId
);
Intent
backIntent
=
new
Intent
(
FTXEvent
.
ACTION_PIP_PLAY_CONTROL
).
putExtras
(
backData
);
PendingIntent
preIntent
=
PendingIntent
.
getBroadcast
(
mActivity
,
FTXEvent
.
EXTRA_PIP_PLAY_BACK
,
backIntent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
|
PendingIntent
.
FLAG_IMMUTABLE
);
RemoteAction
preAction
=
new
RemoteAction
(
getBackIcon
(
params
),
"skipPre"
,
"skip pre"
,
preIntent
);
actions
.
add
(
preAction
);
}
// resume or pause
Bundle
playOrPauseData
=
new
Bundle
();
playOrPauseData
.
putInt
(
FTXEvent
.
EXTRA_NAME_PLAYER_ID
,
params
.
mCurrentPlayerId
);
playOrPauseData
.
putInt
(
FTXEvent
.
EXTRA_NAME_PLAY_OP
,
FTXEvent
.
EXTRA_PIP_PLAY_RESUME_OR_PAUSE
);
Intent
playOrPauseIntent
=
new
Intent
(
FTXEvent
.
ACTION_PIP_PLAY_CONTROL
).
putExtras
(
playOrPauseData
);
Icon
playIcon
=
isPlaying
?
getPauseIcon
(
params
)
:
getPlayIcon
(
params
);
PendingIntent
playIntent
=
PendingIntent
.
getBroadcast
(
mActivity
,
FTXEvent
.
EXTRA_PIP_PLAY_RESUME_OR_PAUSE
,
playOrPauseIntent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
|
PendingIntent
.
FLAG_IMMUTABLE
);
RemoteAction
playOrPauseAction
=
new
RemoteAction
(
playIcon
,
"playOrPause"
,
"play Or Pause"
,
playIntent
);
if
(
params
.
mIsNeedPlayControl
)
{
Bundle
playOrPauseData
=
new
Bundle
();
playOrPauseData
.
putInt
(
FTXEvent
.
EXTRA_NAME_PLAYER_ID
,
params
.
mCurrentPlayerId
);
playOrPauseData
.
putInt
(
FTXEvent
.
EXTRA_NAME_PLAY_OP
,
FTXEvent
.
EXTRA_PIP_PLAY_RESUME_OR_PAUSE
);
Intent
playOrPauseIntent
=
new
Intent
(
FTXEvent
.
ACTION_PIP_PLAY_CONTROL
).
putExtras
(
playOrPauseData
);
Icon
playIcon
=
isPlaying
?
getPauseIcon
(
params
)
:
getPlayIcon
(
params
);
PendingIntent
playIntent
=
PendingIntent
.
getBroadcast
(
mActivity
,
FTXEvent
.
EXTRA_PIP_PLAY_RESUME_OR_PAUSE
,
playOrPauseIntent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
|
PendingIntent
.
FLAG_IMMUTABLE
);
RemoteAction
playOrPauseAction
=
new
RemoteAction
(
playIcon
,
"playOrPause"
,
"play Or Pause"
,
playIntent
);
actions
.
add
(
playOrPauseAction
);
}
// forward
Bundle
forwardData
=
new
Bundle
();
forwardData
.
putInt
(
FTXEvent
.
EXTRA_NAME_PLAY_OP
,
FTXEvent
.
EXTRA_PIP_PLAY_FORWARD
);
forwardData
.
putInt
(
FTXEvent
.
EXTRA_NAME_PLAYER_ID
,
params
.
mCurrentPlayerId
);
Intent
forwardIntent
=
new
Intent
(
FTXEvent
.
ACTION_PIP_PLAY_CONTROL
).
putExtras
(
forwardData
);
PendingIntent
nextIntent
=
PendingIntent
.
getBroadcast
(
mActivity
,
FTXEvent
.
EXTRA_PIP_PLAY_FORWARD
,
forwardIntent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
|
PendingIntent
.
FLAG_IMMUTABLE
);
RemoteAction
nextAction
=
new
RemoteAction
(
getForwardIcon
(
params
),
"skipNext"
,
"skip next"
,
nextIntent
);
List
<
RemoteAction
>
actions
=
new
ArrayList
<>();
actions
.
add
(
preAction
);
actions
.
add
(
playOrPauseAction
);
actions
.
add
(
nextAction
);
if
(
params
.
mIsNeedPlayForward
)
{
Bundle
forwardData
=
new
Bundle
();
forwardData
.
putInt
(
FTXEvent
.
EXTRA_NAME_PLAY_OP
,
FTXEvent
.
EXTRA_PIP_PLAY_FORWARD
);
forwardData
.
putInt
(
FTXEvent
.
EXTRA_NAME_PLAYER_ID
,
params
.
mCurrentPlayerId
);
Intent
forwardIntent
=
new
Intent
(
FTXEvent
.
ACTION_PIP_PLAY_CONTROL
).
putExtras
(
forwardData
);
PendingIntent
nextIntent
=
PendingIntent
.
getBroadcast
(
mActivity
,
FTXEvent
.
EXTRA_PIP_PLAY_FORWARD
,
forwardIntent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
|
PendingIntent
.
FLAG_IMMUTABLE
);
RemoteAction
nextAction
=
new
RemoteAction
(
getForwardIcon
(
params
),
"skipNext"
,
"skip next"
,
nextIntent
);
actions
.
add
(
nextAction
);
}
params
.
mPipParams
.
setActions
(
actions
);
mActivity
.
setPictureInPictureParams
(
params
.
mPipParams
.
build
());
...
...
@@ -285,6 +290,9 @@ public class FTXPIPManager {
String
mPlayForwardAssetPath
;
int
mCurrentPlayerId
;
protected
PictureInPictureParams
.
Builder
mPipParams
;
private
boolean
mIsNeedPlayBack
=
true
;
private
boolean
mIsNeedPlayForward
=
true
;
private
boolean
mIsNeedPlayControl
=
true
;
/**
* @param mPlayBackAssetPath 回退按钮图片资源路径,传空则使用系统默认图标
...
...
@@ -295,11 +303,21 @@ public class FTXPIPManager {
*/
public
PipParams
(
String
mPlayBackAssetPath
,
String
mPlayResumeAssetPath
,
String
mPlayPauseAssetPath
,
String
mPlayForwardAssetPath
,
int
mCurrentPlayerId
)
{
this
(
mPlayBackAssetPath
,
mPlayResumeAssetPath
,
mPlayPauseAssetPath
,
mPlayForwardAssetPath
,
mCurrentPlayerId
,
true
,
true
,
true
);
}
public
PipParams
(
String
mPlayBackAssetPath
,
String
mPlayResumeAssetPath
,
String
mPlayPauseAssetPath
,
String
mPlayForwardAssetPath
,
int
mCurrentPlayerId
,
boolean
isNeedPlayBack
,
boolean
isNeedPlayForward
,
boolean
isNeedPlayControl
)
{
this
.
mPlayBackAssetPath
=
mPlayBackAssetPath
;
this
.
mPlayResumeAssetPath
=
mPlayResumeAssetPath
;
this
.
mPlayPauseAssetPath
=
mPlayPauseAssetPath
;
this
.
mPlayForwardAssetPath
=
mPlayForwardAssetPath
;
this
.
mCurrentPlayerId
=
mCurrentPlayerId
;
this
.
mIsNeedPlayBack
=
isNeedPlayBack
;
this
.
mIsNeedPlayForward
=
isNeedPlayForward
;
this
.
mIsNeedPlayControl
=
isNeedPlayControl
;
}
}
...
...
Flutter/android/src/main/java/com/tencent/vod/flutter/FTXTransformation.java
浏览文件 @
efb9316d
...
...
@@ -3,7 +3,7 @@ package com.tencent.vod.flutter;
import
android.text.TextUtils
;
import
com.tencent.rtmp.TX
PlayerGlobalSettin
g
;
import
com.tencent.rtmp.TX
LivePlayConfi
g
;
import
com.tencent.rtmp.TXVodPlayConfig
;
import
java.util.HashMap
;
...
...
@@ -15,75 +15,61 @@ import java.util.Map;
public
class
FTXTransformation
{
@SuppressWarnings
(
"unchecked"
)
public
static
TXVodPlayConfig
transformToConfig
(
Map
<
Object
,
Object
>
config
)
{
public
static
TXVodPlayConfig
transformTo
Vod
Config
(
Map
<
Object
,
Object
>
config
)
{
TXVodPlayConfig
playConfig
=
new
TXVodPlayConfig
();
Integer
connectRetryCount
=
(
Integer
)
config
.
get
(
"connectRetryCount"
);
if
(
intIsNotEmpty
(
connectRetryCount
))
{
playConfig
.
setConnectRetryCount
(
connectRetryCount
);
}
Integer
connectRetryInterval
=
(
Integer
)
config
.
get
(
"connectRetryInterval"
);
if
(
intIsNotEmpty
(
connectRetryInterval
))
{
playConfig
.
setConnectRetryInterval
(
connectRetryInterval
);
}
Integer
timeout
=
(
Integer
)
config
.
get
(
"timeout"
);
if
(
intIsNotEmpty
(
timeout
))
{
playConfig
.
setTimeout
(
timeout
);
}
Integer
playerType
=
(
Integer
)
config
.
get
(
"playerType"
);
if
(
null
!=
playerType
)
{
playConfig
.
setPlayerType
(
playerType
);
}
Map
<
String
,
String
>
headers
=
(
Map
<
String
,
String
>)
config
.
get
(
"headers"
);
if
(
null
==
headers
)
{
headers
=
new
HashMap
<>();
}
playConfig
.
setHeaders
(
headers
);
Boolean
enableAccurateSeek
=
(
Boolean
)
config
.
get
(
"enableAccurateSeek"
);
if
(
null
!=
enableAccurateSeek
)
{
playConfig
.
setEnableAccurateSeek
(
enableAccurateSeek
);
}
Boolean
autoRotate
=
(
Boolean
)
config
.
get
(
"autoRotate"
);
if
(
null
!=
autoRotate
)
{
playConfig
.
setAutoRotate
(
autoRotate
);
}
Boolean
smoothSwitchBitrate
=
(
Boolean
)
config
.
get
(
"smoothSwitchBitrate"
);
if
(
null
!=
smoothSwitchBitrate
)
{
playConfig
.
setSmoothSwitchBitrate
(
smoothSwitchBitrate
);
}
String
cacheMp4ExtName
=
(
String
)
config
.
get
(
"cacheMp4ExtName"
);
if
(!
TextUtils
.
isEmpty
(
cacheMp4ExtName
))
{
playConfig
.
setCacheMp4ExtName
(
cacheMp4ExtName
);
}
Integer
progressInterval
=
(
Integer
)
config
.
get
(
"progressInterval"
);
if
(
intIsNotEmpty
(
progressInterval
))
{
playConfig
.
setProgressInterval
(
progressInterval
);
}
Integer
maxBufferSize
=
(
Integer
)
config
.
get
(
"maxBufferSize"
);
if
(
intIsNotEmpty
(
maxBufferSize
))
{
playConfig
.
setMaxBufferSize
(
maxBufferSize
);
}
Integer
maxPreloadSize
=
(
Integer
)
config
.
get
(
"maxPreloadSize"
);
if
(
intIsNotEmpty
(
maxPreloadSize
))
{
playConfig
.
setMaxPreloadSize
(
maxPreloadSize
);
}
Integer
firstStartPlayBufferTime
=
(
Integer
)
config
.
get
(
"firstStartPlayBufferTime"
);
if
(
null
!=
firstStartPlayBufferTime
)
{
playConfig
.
setFirstStartPlayBufferTime
(
firstStartPlayBufferTime
);
}
Integer
nextStartPlayBufferTime
=
(
Integer
)
config
.
get
(
"nextStartPlayBufferTime"
);
if
(
null
!=
nextStartPlayBufferTime
)
{
playConfig
.
setNextStartPlayBufferTime
(
nextStartPlayBufferTime
);
...
...
@@ -93,23 +79,19 @@ public class FTXTransformation {
if
(!
TextUtils
.
isEmpty
(
overlayKey
))
{
playConfig
.
setOverlayKey
(
overlayKey
);
}
String
overlayIv
=
(
String
)
config
.
get
(
"overlayIv"
);
if
(!
TextUtils
.
isEmpty
(
overlayIv
))
{
playConfig
.
setOverlayIv
(
overlayIv
);
}
Map
<
String
,
Object
>
extInfoMap
=
(
Map
<
String
,
Object
>)
config
.
get
(
"extInfoMap"
);
if
(
null
==
extInfoMap
)
{
extInfoMap
=
new
HashMap
<>();
}
playConfig
.
setExtInfo
(
extInfoMap
);
Boolean
enableRenderProcess
=
(
Boolean
)
config
.
get
(
"enableRenderProcess"
);
if
(
null
!=
enableRenderProcess
)
{
playConfig
.
setEnableRenderProcess
(
enableRenderProcess
);
}
String
preferredResolutionStr
=
(
String
)
config
.
get
(
"preferredResolution"
);
if
(
null
!=
preferredResolutionStr
)
{
long
preferredResolution
=
Long
.
parseLong
(
preferredResolutionStr
);
...
...
@@ -119,8 +101,60 @@ public class FTXTransformation {
return
playConfig
;
}
public
static
TXLivePlayConfig
transformToLiveConfig
(
Map
<
Object
,
Object
>
config
)
{
TXLivePlayConfig
livePlayConfig
=
new
TXLivePlayConfig
();
Double
cacheTime
=
(
Double
)
config
.
get
(
"cacheTime"
);
if
(
doubleIsNotEmpty
(
cacheTime
))
{
livePlayConfig
.
setCacheTime
(
cacheTime
.
floatValue
());
}
Double
maxAutoAdjustCacheTime
=
(
Double
)
config
.
get
(
"maxAutoAdjustCacheTime"
);
if
(
doubleIsNotEmpty
(
maxAutoAdjustCacheTime
))
{
livePlayConfig
.
setMaxAutoAdjustCacheTime
(
maxAutoAdjustCacheTime
.
floatValue
());
}
Double
minAutoAdjustCacheTime
=
(
Double
)
config
.
get
(
"minAutoAdjustCacheTime"
);
if
(
doubleIsNotEmpty
(
minAutoAdjustCacheTime
))
{
livePlayConfig
.
setMinAutoAdjustCacheTime
(
minAutoAdjustCacheTime
.
floatValue
());
}
Integer
videoBlockThreshold
=
(
Integer
)
config
.
get
(
"videoBlockThreshold"
);
if
(
intIsNotEmpty
(
videoBlockThreshold
))
{
livePlayConfig
.
setVideoBlockThreshold
(
videoBlockThreshold
);
}
Integer
connectRetryCount
=
(
Integer
)
config
.
get
(
"connectRetryCount"
);
if
(
intIsNotEmpty
(
connectRetryCount
))
{
livePlayConfig
.
setConnectRetryCount
(
connectRetryCount
);
}
Integer
connectRetryInterval
=
(
Integer
)
config
.
get
(
"connectRetryInterval"
);
if
(
intIsNotEmpty
(
connectRetryInterval
))
{
livePlayConfig
.
setConnectRetryInterval
(
connectRetryInterval
);
}
Boolean
autoAdjustCacheTime
=
(
Boolean
)
config
.
get
(
"autoAdjustCacheTime"
);
if
(
null
!=
autoAdjustCacheTime
)
{
livePlayConfig
.
setAutoAdjustCacheTime
(
autoAdjustCacheTime
);
}
Boolean
enableAec
=
(
Boolean
)
config
.
get
(
"enableAec"
);
if
(
null
!=
enableAec
)
{
livePlayConfig
.
setEnableAEC
(
enableAec
);
}
Boolean
enableMessage
=
(
Boolean
)
config
.
get
(
"enableMessage"
);
if
(
null
!=
enableMessage
)
{
livePlayConfig
.
setEnableMessage
(
enableMessage
);
}
Boolean
enableMetaData
=
(
Boolean
)
config
.
get
(
"enableMetaData"
);
if
(
null
!=
enableMetaData
)
{
livePlayConfig
.
setEnableMetaData
(
enableMetaData
);
}
String
flvSessionKey
=
(
String
)
config
.
get
(
"flvSessionKey"
);
if
(!
TextUtils
.
isEmpty
(
flvSessionKey
))
{
livePlayConfig
.
setFlvSessionKey
(
flvSessionKey
);
}
return
livePlayConfig
;
}
private
static
boolean
intIsNotEmpty
(
Integer
value
)
{
return
null
!=
value
&&
value
>
0
;
}
private
static
boolean
doubleIsNotEmpty
(
Double
value
)
{
return
null
!=
value
&&
value
>
0
;
}
}
Flutter/android/src/main/java/com/tencent/vod/flutter/FTXVodPlayer.java
浏览文件 @
efb9316d
...
...
@@ -22,7 +22,6 @@ import java.util.ArrayList;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
io.flutter.embedding.engine.plugins.FlutterPlugin
;
import
io.flutter.plugin.common.EventChannel
;
...
...
@@ -510,7 +509,7 @@ public class FTXVodPlayer extends FTXBasePlayer implements MethodChannel.MethodC
void
setPlayConfig
(
Map
<
Object
,
Object
>
config
)
{
if
(
mVodPlayer
!=
null
)
{
TXVodPlayConfig
playConfig
=
FTXTransformation
.
transformToConfig
(
config
);
TXVodPlayConfig
playConfig
=
FTXTransformation
.
transformTo
Vod
Config
(
config
);
mVodPlayer
.
setConfig
(
playConfig
);
}
}
...
...
Flutter/android/src/main/java/com/tencent/vod/flutter/SuperPlayerPlugin.java
浏览文件 @
efb9316d
...
...
@@ -133,7 +133,7 @@ public class SuperPlayerPlugin implements FlutterPlugin, MethodCallHandler, Acti
mPlayers
.
append
(
playerId
,
player
);
result
.
success
(
playerId
);
}
else
if
(
call
.
method
.
equals
(
"createLivePlayer"
))
{
FTXLivePlayer
player
=
new
FTXLivePlayer
(
mFlutterPluginBinding
,
mActivityPluginBinding
.
getActivity
());
FTXLivePlayer
player
=
new
FTXLivePlayer
(
mFlutterPluginBinding
,
mActivityPluginBinding
.
getActivity
()
,
mTxPipManager
);
int
playerId
=
player
.
getPlayerId
();
mPlayers
.
append
(
playerId
,
player
);
result
.
success
(
playerId
);
...
...
@@ -210,6 +210,10 @@ public class SuperPlayerPlugin implements FlutterPlugin, MethodCallHandler, Acti
result
.
success
(
mTxPipManager
.
isSupportDevice
());
}
else
if
(
call
.
method
.
equals
(
"getLiteAVSDKVersion"
))
{
result
.
success
(
TXLiveBase
.
getSDKVersionStr
());
}
else
if
(
call
.
method
.
equals
(
"setGlobalEnv"
))
{
String
envConfig
=
call
.
argument
(
"envConfig"
);
int
setResult
=
TXLiveBase
.
setGlobalEnv
(
envConfig
);
result
.
success
(
setResult
);
}
else
{
result
.
notImplemented
();
}
...
...
Flutter/example/android/app/src/debug/AndroidManifest.xml
浏览文件 @
efb9316d
...
...
@@ -13,26 +13,12 @@
<uses-permission
android:name=
"android.permission.READ_EXTERNAL_STORAGE"
/>
<uses-feature
android:name=
"android.hardware.camera"
/>
<uses-feature
android:name=
"android.hardware.camera.autofocus"
/>
<uses-permission
android:name=
"android.permission.INTERNET"
/>
<uses-permission
android:name=
"android.permission.ACCESS_NETWORK_STATE"
/>
<uses-permission
android:name=
"android.permission.ACCESS_WIFI_STATE"
/>
<uses-permission
android:name=
"android.permission.READ_PHONE_STATE"
/>
<uses-permission
android:name=
"android.permission.CALL_PHONE"
/>
<uses-permission
android:name=
"android.permission.WRITE_EXTERNAL_STORAGE"
/>
<uses-permission
android:name=
"android.permission.READ_EXTERNAL_STORAGE"
/>
<uses-permission
android:name=
"android.permission.READ_LOGS"
/>
<uses-permission
android:name=
"android.permission.RECORD_AUDIO"
/>
<uses-permission
android:name=
"android.permission.CAMERA"
/>
<uses-permission
android:name=
"android.permission.CAPTURE_AUDIO_OUTPUT"
/>
<uses-permission
android:name=
"android.permission.CAPTURE_VIDEO_OUTPUT"
/>
<uses-permission
android:name=
"android.permission.MODIFY_AUDIO_SETTINGS"
/>
<uses-permission
android:name=
"android.permission.BLUETOOTH"
/>
<uses-permission
android:name=
"android.permission.SYSTEM_ALERT_WINDOW"
/>
<uses-permission
android:name=
"android.permission.CHANGE_CONFIGURATION"
/>
<uses-permission
android:name=
"android.permission.WRITE_SETTINGS"
/>
<!-- <android:uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> -->
<uses-permission
android:name=
"android.permission.RECEIVE_BOOT_COMPLETED"
/>
</manifest>
Flutter/example/lib/demo_superplayer.dart
浏览文件 @
efb9316d
...
...
@@ -14,10 +14,20 @@ class DemoSuperplayer extends StatefulWidget {
}
class
_DemoSuperplayerState
extends
State
<
DemoSuperplayer
>
{
static
const
DEFAULT_PLACE_HOLDER
=
"http://xiaozhibo-10055601.file.myqcloud.com/coverImg.jpg"
;
List
<
SuperPlayerModel
>
videoModels
=
[];
bool
_isFullScreen
=
false
;
late
SuperPlayerController
_controller
;
StreamSubscription
?
simpleEventSubscription
;
int
tabSelectPos
=
0
;
TextStyle
_textStyleSelected
=
new
TextStyle
(
fontSize:
16
,
color:
Colors
.
white
);
TextStyle
_textStyleUnSelected
=
new
TextStyle
(
fontSize:
16
,
color:
Colors
.
grey
);
@override
void
initState
()
{
...
...
@@ -30,12 +40,14 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
simpleEventSubscription
=
_controller
.
onSimplePlayerEventBroadcast
.
listen
((
event
)
{
String
evtName
=
event
[
"event"
];
if
(
evtName
==
SuperPlayerViewEvent
.
onStartFullScreenPlay
)
{
// enter fullscreen
}
else
if
(
evtName
==
SuperPlayerViewEvent
.
onStopFullScreenPlay
)
{
// exit fullscreen
}
else
{
print
(
evtName
);
}
});
ini
tData
();
_getLiveLis
tData
();
}
@override
...
...
@@ -69,6 +81,34 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
return
!
_controller
.
onBackPress
();
}
Widget
getTabRow
()
{
return
new
Container
(
height:
40
,
child:
new
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceEvenly
,
children:
[
new
GestureDetector
(
child:
new
Container
(
child:
Text
(
"直播"
,
style:
tabSelectPos
==
0
?
_textStyleSelected
:
_textStyleUnSelected
,
),
),
onTap:
_getLiveListData
,
),
new
GestureDetector
(
onTap:
_getVodListData
,
child:
new
Container
(
child:
Text
(
"点播"
,
style:
tabSelectPos
==
1
?
_textStyleSelected
:
_textStyleUnSelected
,
),
)),
],
),
);
}
Widget
getBody
()
{
return
Column
(
children:
[
_getPlayArea
(),
Expanded
(
flex:
1
,
child:
_getListArea
()),
_getAddArea
()],
...
...
@@ -85,32 +125,39 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
Widget
_getListArea
()
{
return
Container
(
margin:
EdgeInsets
.
only
(
top:
10
),
child:
ListView
.
builder
(
shrinkWrap:
true
,
itemCount:
videoModels
.
length
,
itemBuilder:
(
context
,
i
)
=>
_buildVideoItem
(
videoModels
[
i
]),
),
);
margin:
EdgeInsets
.
only
(
top:
10
),
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
start
,
children:
[
getTabRow
(),
Expanded
(
child:
ListView
.
builder
(
shrinkWrap:
true
,
itemCount:
videoModels
.
length
,
itemBuilder:
(
context
,
i
)
=>
_buildVideoItem
(
videoModels
[
i
]),
))
],
));
}
Widget
_buildVideoItem
(
SuperPlayerModel
playModel
)
{
return
Column
(
children:
[
ListTile
(
leading:
Image
.
network
(
playModel
.
coverUrl
,
width:
100
,
height:
60
,
fit:
BoxFit
.
cover
,
alignment:
Alignment
.
center
,
),
title:
new
Text
(
playModel
.
title
,
style:
TextStyle
(
color:
Colors
.
white
),
),
onTap:
()
=>
playCurrentModel
(
playModel
),
horizontalTitleGap:
10
,),
leading:
Image
.
network
(
playModel
.
coverUrl
.
isEmpty
?
DEFAULT_PLACE_HOLDER
:
playModel
.
coverUrl
,
width:
100
,
height:
60
,
fit:
BoxFit
.
cover
,
alignment:
Alignment
.
center
,
),
title:
new
Text
(
playModel
.
title
,
style:
TextStyle
(
color:
Colors
.
white
),
),
onTap:
()
=>
playCurrentModel
(
playModel
),
horizontalTitleGap:
10
,
),
Divider
()
],
);
...
...
@@ -124,6 +171,7 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
}
void
onAddVideoTap
(
BuildContext
context
)
{
bool
isLive
=
tabSelectPos
==
0
;
showDialog
(
context:
context
,
builder:
(
context
)
{
...
...
@@ -144,7 +192,7 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
}
playCurrentModel
(
model
);
},
needPisgn:
true
);
},
needPisgn:
!
isLive
,
showFileEdited:
!
isLive
,
);
});
}
...
...
@@ -152,7 +200,35 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
_controller
.
playWithModel
(
model
);
}
void
initData
()
async
{
void
_getLiveListData
()
async
{
setState
(()
{
tabSelectPos
=
0
;
});
List
<
SuperPlayerModel
>
models
=
[];
int
playAction
=
SuperPlayerModel
.
PLAY_ACTION_AUTO_PLAY
;
SuperPlayerModel
model
=
SuperPlayerModel
();
model
.
title
=
"测试视频"
;
model
.
videoURL
=
"http://liteavapp.qcloud.com/live/liteavdemoplayerstreamid_demo1080p.flv"
;
model
.
coverUrl
=
"http://1500005830.vod2.myqcloud.com/6c9a5118vodcq1500005830/66bc542f387702300661648850/0RyP1rZfkdQA.png"
;
model
.
playAction
=
playAction
;
models
.
add
(
model
);
videoModels
.
clear
();
videoModels
.
addAll
(
models
);
setState
(()
{
if
(
videoModels
.
isNotEmpty
)
{
playCurrentModel
(
videoModels
[
0
]);
}
else
{
EasyLoading
.
showError
(
"video list request error"
);
}
});
}
void
_getVodListData
()
async
{
setState
(()
{
tabSelectPos
=
1
;
});
List
<
SuperPlayerModel
>
models
=
[];
int
playAction
=
SuperPlayerModel
.
PLAY_ACTION_AUTO_PLAY
;
...
...
@@ -196,13 +272,12 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
List
<
Future
<
void
>>
requestList
=
[];
SuperVodDataLoader
loader
=
SuperVodDataLoader
();
for
(
SuperPlayerModel
tempModel
in
models
)
{
requestList
.
add
(
loader
.
getVideoData
(
tempModel
,
(
resultModel
)
{
videoModels
.
add
(
resultModel
);
}));
requestList
.
add
(
loader
.
getVideoData
(
tempModel
,
(
_
)
{}));
}
await
Future
.
wait
(
requestList
);
videoModels
.
clear
();
videoModels
.
addAll
(
models
);
setState
(()
{
if
(
videoModels
.
isNotEmpty
)
{
playCurrentModel
(
videoModels
[
0
]);
...
...
Flutter/example/lib/demo_txLiveplayer.dart
浏览文件 @
efb9316d
...
...
@@ -81,15 +81,16 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
await
SuperPlayerPlugin
.
setConsoleEnabled
(
true
);
await
_controller
.
initialize
();
await
_controller
.
setConfig
(
FTXLivePlayConfig
());
// 安卓需要设置hls格式才可正常播放
await
_controller
.
p
lay
(
_url
,
playType:
TXPlayType
.
LIVE_FLV
);
await
_controller
.
startP
lay
(
_url
,
playType:
TXPlayType
.
LIVE_FLV
);
}
@override
void
initState
()
{
super
.
initState
();
init
();
WidgetsBinding
.
instance
?
.
addObserver
(
this
);
WidgetsBinding
.
instance
.
addObserver
(
this
);
EasyLoading
.
show
(
status:
'loading...'
);
}
...
...
@@ -207,7 +208,7 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
),
new
GestureDetector
(
onTap:
()
async
{
_controller
.
p
lay
(
_url
,
playType:
TXPlayType
.
LIVE_FLV
);
_controller
.
startP
lay
(
_url
,
playType:
TXPlayType
.
LIVE_FLV
);
},
child:
Container
(
color:
Colors
.
transparent
,
...
...
@@ -290,7 +291,7 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
playNetEventSubscription
?.
cancel
();
_controller
.
dispose
();
super
.
dispose
();
WidgetsBinding
.
instance
?
.
removeObserver
(
this
);
WidgetsBinding
.
instance
.
removeObserver
(
this
);
EasyLoading
.
dismiss
();
}
...
...
@@ -302,7 +303,7 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
_url
=
url
;
_controller
.
stop
();
if
(
url
.
isNotEmpty
)
{
_controller
.
p
lay
(
url
);
_controller
.
startP
lay
(
url
);
}
},
showFileEdited:
false
);
});
...
...
Flutter/example/lib/demo_txvodplayer.dart
浏览文件 @
efb9316d
...
...
@@ -18,7 +18,7 @@ class DemoTXVodPlayer extends StatefulWidget {
class
_DemoTXVodlayerState
extends
State
<
DemoTXVodPlayer
>
with
WidgetsBindingObserver
{
late
TXVodPlayerController
_controller
;
double
_aspectRatio
=
0
;
double
_aspectRatio
=
16
/
9
;
double
_currentProgress
=
0.0
;
bool
_isMute
=
false
;
int
_volume
=
100
;
...
...
@@ -92,7 +92,7 @@ class _DemoTXVodlayerState extends State<DemoTXVodPlayer>
void
initState
()
{
super
.
initState
();
init
();
WidgetsBinding
.
instance
?
.
addObserver
(
this
);
WidgetsBinding
.
instance
.
addObserver
(
this
);
EasyLoading
.
show
(
status:
'loading...'
);
}
...
...
@@ -386,7 +386,7 @@ class _DemoTXVodlayerState extends State<DemoTXVodPlayer>
playEventSubscription
?.
cancel
();
_controller
.
dispose
();
super
.
dispose
();
WidgetsBinding
.
instance
?
.
removeObserver
(
this
);
WidgetsBinding
.
instance
.
removeObserver
(
this
);
EasyLoading
.
dismiss
();
}
...
...
Flutter/example/lib/superplayer/common/color_resource.dart
浏览文件 @
efb9316d
...
...
@@ -6,4 +6,5 @@ class ColorResource {
static
const
COLOR_GRAY
=
0xFFBBBBBB
;
static
const
COLOR_TRANS_BLACK
=
0xBB000000
;
static
const
COLOR_WHITE
=
0xFFFFFFFF
;
static
const
COLOR_TRANS_GRAY
=
0x11BBBBBB
;
}
\ No newline at end of file
Flutter/example/lib/superplayer/model/superplayer_define.dart
浏览文件 @
efb9316d
...
...
@@ -34,7 +34,7 @@ class SuperPlayerCode {
static
const
VOD_REQUEST_FILE_ID_FAIL
=
40002
;
}
abstract
class
SuperPlayerViewEvent
{
class
SuperPlayerViewEvent
{
static
const
onStartFullScreenPlay
=
"onStartFullScreenPlay"
;
//进入全屏播放
static
const
onStopFullScreenPlay
=
"onStopFullScreenPlay"
;
//退出全屏播放
static
const
onSuperPlayerDidStart
=
"onSuperPlayerDidStart"
;
//播放开始通知
...
...
@@ -43,4 +43,11 @@ abstract class SuperPlayerViewEvent {
static
const
onSuperPlayerBackAction
=
"onSuperPlayerBackAction"
;
//返回事件
}
/// 播放器插件当前所处的布局状态
class
SuperPlayerUIStatus
{
static
const
WINDOW_MODE
=
0
;
static
const
FULLSCREEN_MODE
=
1
;
static
const
PIP_MODE
=
2
;
}
Flutter/example/lib/superplayer/superplayer_controller.dart
浏览文件 @
efb9316d
差异被折叠。
点击展开。
Flutter/example/lib/superplayer/superplayer_observer.dart
浏览文件 @
efb9316d
...
...
@@ -8,10 +8,10 @@ class _SuperPlayerObserver {
Function
onPlayPause
;
Function
onPlayStop
;
Function
onPlayLoading
;
Function
(
int
current
,
int
duration
,
double
playableDuration
)
onPlayProgress
;
Function
(
double
current
,
double
duration
,
double
playableDuration
)
onPlayProgress
;
Function
(
double
position
)
onSeek
;
Function
(
bool
success
,
SuperPlayerType
playerType
,
VideoQuality
quality
)
onSwitchStreamStart
;
Function
(
bool
success
,
SuperPlayerType
playerType
,
VideoQuality
quality
)
onSwitchStreamEnd
;
Function
(
bool
success
,
SuperPlayerType
playerType
,
VideoQuality
?
quality
)
onSwitchStreamStart
;
Function
(
bool
success
,
SuperPlayerType
playerType
,
VideoQuality
?
quality
)
onSwitchStreamEnd
;
Function
(
int
code
,
String
msg
)
onError
;
Function
(
SuperPlayerType
playerType
)
onPlayerTypeChange
;
Function
(
TXLivePlayerController
controller
,
String
url
)
onPlayTimeShiftLive
;
...
...
Flutter/example/lib/superplayer/ui/superplayer_bottom_view.dart
浏览文件 @
efb9316d
...
...
@@ -17,15 +17,15 @@ class VideoBottomView extends StatefulWidget {
class
_VideoBottomViewState
extends
State
<
VideoBottomView
>
{
static
const
TAG
=
"VideoBottomView"
;
double
_currentProgress
=
0
;
double
_playableProgress
=
0
;
int
_currentDuration
=
0
;
int
_videoDuration
=
0
;
double
_currentDuration
=
0
;
double
_videoDuration
=
0
;
double
_bufferedDuration
=
0
;
bool
_showFullScreenBtn
=
true
;
bool
_isPlayMode
=
false
;
bool
_isShowQuality
=
false
;
// only showed on fullscreen mode
bool
_isOnDraging
=
false
;
SuperPlayerType
_playerType
=
SuperPlayerType
.
VOD
;
VideoQuality
?
_currentQuality
;
@override
...
...
@@ -34,13 +34,15 @@ class _VideoBottomViewState extends State<VideoBottomView> {
_videoDuration
=
widget
.
_playerController
.
videoDuration
;
_currentDuration
=
widget
.
_playerController
.
currentDuration
;
}
else
if
(
null
!=
widget
.
_playerController
.
videoModel
)
{
_videoDuration
=
widget
.
_playerController
.
videoModel
!.
duration
;
_videoDuration
=
widget
.
_playerController
.
videoModel
!.
duration
.
toDouble
()
;
}
_isPlayMode
=
(
widget
.
_playerController
.
playerState
==
SuperPlayerState
.
PLAYING
);
_showFullScreenBtn
=
!
widget
.
_playerController
.
_isFullScreen
;
_isShowQuality
=
widget
.
_playerController
.
_isFullScreen
;
bool
isFullScreen
=
widget
.
_playerController
.
_playerUIStatus
==
SuperPlayerUIStatus
.
FULLSCREEN_MODE
;
_showFullScreenBtn
=
!
isFullScreen
;
_isShowQuality
=
isFullScreen
;
_currentQuality
=
widget
.
_playerController
.
currentQuality
;
_playerType
=
widget
.
_playerController
.
playerType
;
_fixProgress
();
super
.
initState
();
...
...
@@ -128,8 +130,8 @@ class _VideoBottomViewState extends State<VideoBottomView> {
return
Expanded
(
child:
VideoSlider
(
min:
0
,
max:
1
,
value:
_current
Progress
,
max:
_videoDuration
,
value:
_current
Duration
,
bufferedValue:
_playableProgress
,
activeColor:
Color
(
ColorResource
.
COLOR_MAIN_THEME
),
inactiveColor:
Color
(
ColorResource
.
COLOR_GRAY
),
...
...
@@ -138,16 +140,18 @@ class _VideoBottomViewState extends State<VideoBottomView> {
progressHeight:
2
,
sliderRadius:
4
,
sliderOutterRadius:
10
,
// 直播禁止时移
canDrag:
_playerType
==
SuperPlayerType
.
VOD
,
onDragUpdate:
(
value
)
{
_isOnDraging
=
true
;
},
onDragEnd:
(
value
)
{
setState
(()
{
_isOnDraging
=
false
;
_current
Progress
=
value
;
widget
.
_playerController
.
seek
(
_current
Progress
*
_video
Duration
);
_current
Duration
=
value
*
_videoDuration
;
widget
.
_playerController
.
seek
(
_currentDuration
);
LogUtils
.
d
(
TAG
,
"_current
Progress:
$_currentProgress
,_videoDuration:
$_videoDuration
,currentDuration:
${_currentProgress * _videoDuration}
"
);
"_current
Duration:
$_currentDuration
,_videoDuration:
$_videoDuration
"
);
});
},
),
...
...
@@ -166,7 +170,7 @@ class _VideoBottomViewState extends State<VideoBottomView> {
widget
.
_controller
.
onTapQuality
();
}
void
updateDuration
(
int
duration
,
int
videoDuration
,
double
bufferedDration
)
{
void
updateDuration
(
double
duration
,
double
videoDuration
,
double
bufferedDration
)
{
if
(
_isOnDraging
)
{
return
;
}
...
...
@@ -183,19 +187,6 @@ class _VideoBottomViewState extends State<VideoBottomView> {
}
void
_fixProgress
()
{
// provent division zero problem
if
(
_videoDuration
==
0
)
{
_currentProgress
=
0
;
}
else
{
_currentProgress
=
_currentDuration
/
_videoDuration
;
}
if
(
_currentProgress
<
0
)
{
_currentProgress
=
0
;
}
if
(
_currentProgress
>
1
)
{
_currentProgress
=
1
;
}
if
(
_bufferedDuration
==
0
)
{
_playableProgress
=
0
;
}
else
{
...
...
@@ -218,15 +209,24 @@ class _VideoBottomViewState extends State<VideoBottomView> {
}
}
void
updateFullScreen
(
bool
showFullScreen
)
{
void
updatePlayerType
(
SuperPlayerType
type
)
{
if
(
_playerType
!=
type
)
{
setState
(()
{
_playerType
=
type
;
});
}
}
void
updateUIStatus
(
int
status
)
{
setState
(()
{
_showFullScreenBtn
=
!
showFullScreen
;
_isShowQuality
=
showFullScreen
;
bool
isFullScreen
=
widget
.
_playerController
.
_playerUIStatus
==
SuperPlayerUIStatus
.
FULLSCREEN_MODE
;
_showFullScreenBtn
=
!
isFullScreen
;
_isShowQuality
=
isFullScreen
;
});
}
String
_buildTextString
(
int
time
)
{
Duration
duration
=
Duration
(
seconds:
time
);
String
_buildTextString
(
double
time
)
{
Duration
duration
=
Duration
(
seconds:
time
.
toInt
()
);
// 返回此持续时间跨越的整秒数。
String
inSeconds
=
(
duration
.
inSeconds
%
60
).
toString
().
padLeft
(
2
,
"0"
);
// 返回此持续时间跨越的整分钟数。
...
...
Flutter/example/lib/superplayer/ui/superplayer_cover_view.dart
浏览文件 @
efb9316d
...
...
@@ -43,7 +43,7 @@ class _SuperPlayerCoverViewState extends State<SuperPlayerCoverView> {
}
return
Visibility
(
visible:
_isShowCover
,
visible:
_isShowCover
&&
hasCover
,
child:
Positioned
.
fill
(
top:
topBottomOffset
,
bottom:
topBottomOffset
,
...
...
@@ -53,7 +53,11 @@ class _SuperPlayerCoverViewState extends State<SuperPlayerCoverView> {
onDoubleTap:
_onDoubleTapVideo
,
onTap:
_onSingleTapVideo
,
child:
Container
(
child:
hasCover
?
Image
.
network
(
coverUrl
,
fit:
BoxFit
.
cover
,)
:
Container
(),
decoration:
BoxDecoration
(
// 增加一个半透明背景,防止透明封面图的出现
color:
Color
(
ColorResource
.
COLOR_TRANS_GRAY
)
),
child:
Image
.
network
(
coverUrl
,
fit:
BoxFit
.
cover
),
)
)),
);
...
...
Flutter/example/lib/superplayer/ui/superplayer_more_view.dart
浏览文件 @
efb9316d
...
...
@@ -18,6 +18,7 @@ class _SuperPlayerMoreViewState extends State<SuperPlayerMoreView> {
double
_currentVolumn
=
0
;
bool
_isShowMoreView
=
false
;
bool
_isOpenAccelerate
=
true
;
bool
_isVodPlay
=
false
;
String
_currentRate
=
""
;
Map
<
String
,
double
>
playRateStr
=
{
"1.0x"
:
1.0
,
"1.25x"
:
1.25
,
"1.5x"
:
1.5
,
"2.0x"
:
2.0
};
StreamSubscription
?
volumeSubscription
;
...
...
@@ -25,6 +26,7 @@ class _SuperPlayerMoreViewState extends State<SuperPlayerMoreView> {
@override
void
initState
()
{
super
.
initState
();
_isVodPlay
=
widget
.
controller
.
getIsVodPlay
();
double
playerPlayRate
=
widget
.
controller
.
getPlayRate
();
for
(
String
rateStr
in
playRateStr
.
keys
)
{
if
(
playerPlayRate
==
playRateStr
[
rateStr
])
{
...
...
@@ -132,10 +134,13 @@ class _SuperPlayerMoreViewState extends State<SuperPlayerMoreView> {
),
));
}
return
Container
(
margin:
EdgeInsets
.
only
(
top:
10
,
bottom:
10
),
child:
Row
(
children:
playRateChild
,
return
Visibility
(
visible:
_isVodPlay
,
child:
Container
(
margin:
EdgeInsets
.
only
(
top:
10
,
bottom:
10
),
child:
Row
(
children:
playRateChild
,
),
),
);
}
...
...
@@ -243,6 +248,15 @@ class _SuperPlayerMoreViewState extends State<SuperPlayerMoreView> {
}
}
void
updatePlayerType
(
SuperPlayerType
playerType
)
{
bool
isVodPlay
=
playerType
==
SuperPlayerType
.
VOD
;
if
(
isVodPlay
!=
_isVodPlay
)
{
setState
(()
{
_isVodPlay
=
isVodPlay
;
});
}
}
@override
void
dispose
()
{
super
.
dispose
();
...
...
@@ -255,6 +269,7 @@ class _MoreViewController {
DoubleFunction
getPlayRate
;
Function
(
bool
value
)
siwtchAccelerate
;
Function
(
double
playRate
)
onChangedPlayRate
;
BoolFunction
getIsVodPlay
;
_MoreViewController
(
this
.
getAccelerateIsOpen
,
this
.
getPlayRate
,
this
.
siwtchAccelerate
,
this
.
onChangedPlayRate
);
_MoreViewController
(
this
.
getAccelerateIsOpen
,
this
.
getPlayRate
,
this
.
siwtchAccelerate
,
this
.
onChangedPlayRate
,
this
.
getIsVodPlay
);
}
Flutter/example/lib/superplayer/ui/superplayer_title_view.dart
浏览文件 @
efb9316d
...
...
@@ -76,9 +76,9 @@ class _VideoTitleViewState extends State<_VideoTitleView> {
}
}
void
update
FullScreen
(
bool
showFullScreen
)
{
void
update
UIStatus
(
int
status
)
{
setState
(()
{
_isFullScreen
=
s
howFullScreen
;
_isFullScreen
=
s
tatus
==
SuperPlayerUIStatus
.
FULLSCREEN_MODE
;
});
}
}
...
...
Flutter/example/lib/superplayer/ui/superplayer_video_slider.dart
浏览文件 @
efb9316d
...
...
@@ -17,6 +17,7 @@ class VideoSlider extends StatefulWidget {
final
Color
?
bufferedColor
;
final
Color
?
sliderColor
;
final
Color
?
sliderOutterColor
;
bool
?
canDrag
=
true
;
// calback
final
Function
?
onDragStart
;
...
...
@@ -38,12 +39,16 @@ class VideoSlider extends StatefulWidget {
this
.
sliderOutterColor
,
this
.
onDragStart
,
this
.
onDragUpdate
,
this
.
onDragEnd
})
{
this
.
onDragEnd
,
this
.
canDrag
})
{
double
range
=
(
max
-
min
);
_checkRange
(
range
,
valueName:
"max - min"
);
double
currentProgress
=
value
/
range
;
double
?
bufferedProgress
=
bufferedValue
!=
null
?
bufferedValue
!
/
range
:
null
;
controller
=
_VideoSliderController
(
currentProgress
,
bufferedProgress:
bufferedProgress
);
if
(
range
<=
0
)
{
controller
=
_VideoSliderController
(
1
,
bufferedProgress:
1
);
}
else
{
double
currentProgress
=
value
/
range
;
double
?
bufferedProgress
=
bufferedValue
!=
null
?
bufferedValue
!
/
range
:
null
;
controller
=
_VideoSliderController
(
currentProgress
,
bufferedProgress:
bufferedProgress
);
}
}
@override
...
...
@@ -77,24 +82,31 @@ class VideoSliderState extends State<VideoSlider> {
double
rightPadding
=
overlayRadius
;
return
GestureDetector
(
onHorizontalDragStart:
(
DragStartDetails
details
)
{
isDraging
=
true
;
widget
.
onDragStart
?.
call
();
if
(
widget
.
canDrag
!)
{
isDraging
=
true
;
widget
.
onDragStart
?.
call
();
}
},
onHorizontalDragUpdate:
(
DragUpdateDetails
details
)
{
isDraging
=
true
;
_seekToPosition
(
details
.
globalPosition
);
widget
.
onDragUpdate
?.
call
(
widget
.
controller
.
progress
);
if
(
widget
.
canDrag
!)
{
isDraging
=
true
;
_seekToPosition
(
details
.
globalPosition
);
widget
.
onDragUpdate
?.
call
(
widget
.
controller
.
progress
);}
},
onHorizontalDragEnd:
(
DragEndDetails
details
)
{
isDraging
=
false
;
widget
.
onDragEnd
?.
call
(
widget
.
controller
.
progress
);
if
(
widget
.
canDrag
!)
{
isDraging
=
false
;
widget
.
onDragEnd
?.
call
(
widget
.
controller
.
progress
);}
},
onHorizontalDragCancel:
()
{
isDraging
=
false
;
widget
.
onDragEnd
?.
call
(
widget
.
controller
.
progress
);
if
(
widget
.
canDrag
!)
{
isDraging
=
false
;
widget
.
onDragEnd
?.
call
(
widget
.
controller
.
progress
);}
},
onTapDown:
(
TapDownDetails
details
)
{
_seekToPosition
(
details
.
globalPosition
);
if
(
widget
.
canDrag
!)
{
_seekToPosition
(
details
.
globalPosition
);
}
},
child:
Center
(
child:
Container
(
...
...
Flutter/example/lib/superplayer/ui/superplayer_widget.dart
浏览文件 @
efb9316d
差异被折叠。
点击展开。
Flutter/example/pubspec.yaml
浏览文件 @
efb9316d
...
...
@@ -7,7 +7,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
environment
:
sdk
:
'
>=2.12.0
<3.0.0'
flutter
:
"
>=
1.2
0.0"
flutter
:
"
>=
2.
0.0"
dependencies
:
flutter
:
...
...
Flutter/ios/Classes/FTXLivePlayer.m
浏览文件 @
efb9316d
...
...
@@ -2,6 +2,7 @@
#import "FTXLivePlayer.h"
#import "FTXPlayerEventSinkQueue.h"
#import "FTXTransformation.h"
#import <TXLiteAVSDK_Professional/TXLiteAVSDK.h>
#import <Flutter/Flutter.h>
#import <stdatomic.h>
...
...
@@ -25,7 +26,7 @@ static const int uninitialized = -1;
// 旧的一帧
CVPixelBufferRef
_lastBuffer
;
int64_t
_textureId
;
id
<
FlutterPluginRegistrar
>
_registrar
;
id
<
FlutterTextureRegistry
>
_textureRegistry
;
}
...
...
@@ -39,20 +40,20 @@ static const int uninitialized = -1;
_textureId
=
-
1
;
_eventSink
=
[
FTXPlayerEventSinkQueue
new
];
_netStatusSink
=
[
FTXPlayerEventSinkQueue
new
];
__weak
typeof
(
self
)
weakSelf
=
self
;
_methodChannel
=
[
FlutterMethodChannel
methodChannelWithName
:[
@"cloud.tencent.com/txliveplayer/"
stringByAppendingString
:[
self
.
playerId
stringValue
]]
binaryMessenger
:[
registrar
messenger
]];
[
_methodChannel
setMethodCallHandler
:
^
(
FlutterMethodCall
*
_Nonnull
call
,
FlutterResult
_Nonnull
result
)
{
[
weakSelf
handleMethodCall
:
call
result
:
result
];
}];
_eventChannel
=
[
FlutterEventChannel
eventChannelWithName
:[
@"cloud.tencent.com/txliveplayer/event/"
stringByAppendingString
:[
self
.
playerId
stringValue
]]
binaryMessenger
:[
registrar
messenger
]];
[
_eventChannel
setStreamHandler
:
self
];
_netStatusChannel
=
[
FlutterEventChannel
eventChannelWithName
:[
@"cloud.tencent.com/txliveplayer/net/"
stringByAppendingString
:[
self
.
playerId
stringValue
]]
binaryMessenger
:[
registrar
messenger
]];
[
_netStatusChannel
setStreamHandler
:
self
];
}
return
self
;
}
...
...
@@ -61,7 +62,7 @@ static const int uninitialized = -1;
[
self
stopPlay
];
[
_txLivePlayer
removeVideoWidget
];
_txLivePlayer
=
nil
;
if
(
_textureId
>=
0
)
{
[
_textureRegistry
unregisterTexture
:
_textureId
];
_textureId
=
-
1
;
...
...
@@ -81,7 +82,7 @@ static const int uninitialized = -1;
CVPixelBufferRelease
(
_lastBuffer
);
_lastBuffer
=
nil
;
}
[
_methodChannel
setMethodCallHandler
:
nil
];
_methodChannel
=
nil
;
...
...
@@ -101,7 +102,7 @@ static const int uninitialized = -1;
int64_t
tId
=
[
_textureRegistry
registerTexture
:
self
];
_textureId
=
tId
;
}
if
(
_txLivePlayer
!=
nil
)
{
TXLivePlayConfig
*
config
=
[
TXLivePlayConfig
new
];
[
config
setPlayerPixelFormatType
:
kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
];
...
...
@@ -137,11 +138,12 @@ static const int uninitialized = -1;
}
}
-
(
void
)
switchStream
:
(
NSString
*
)
url
-
(
int
)
switchStream
:
(
NSString
*
)
url
{
if
(
_txLivePlayer
!=
nil
)
{
[
_txLivePlayer
switchStream
:
url
];
return
[
_txLivePlayer
switchStream
:
url
];
}
return
-
1
;
}
-
(
int
)
seek
:
(
float
)
progress
...
...
@@ -207,7 +209,7 @@ static const int uninitialized = -1;
-
(
void
)
setLiveMode
:
(
int
)
type
{
TXLivePlayConfig
*
config
=
_txLivePlayer
.
config
;
if
(
type
==
0
)
{
//自动模式
config
.
bAutoAdjustCacheTime
=
YES
;
...
...
@@ -238,7 +240,7 @@ static const int uninitialized = -1;
if
(
_txLivePlayer
!=
nil
)
{
return
[
_txLivePlayer
prepareLiveSeek
:
domain
bizId
:
bizId
];
}
return
uninitialized
;
}
...
...
@@ -246,7 +248,7 @@ static const int uninitialized = -1;
if
(
_txLivePlayer
!=
nil
)
{
return
[
_txLivePlayer
resumeLive
];
}
return
uninitialized
;
}
...
...
@@ -262,12 +264,26 @@ static const int uninitialized = -1;
}
}
-
(
BOOL
)
enableHardwareDecode
:
(
BOOL
)
enable
{
if
(
_txLivePlayer
!=
nil
)
{
_txLivePlayer
.
enableHWAcceleration
=
enable
;
}
return
false
;
}
-
(
void
)
setPlayConfig
:
(
NSDictionary
*
)
args
{
if
(
_txLivePlayer
!=
nil
&&
[
args
[
@"config"
]
isKindOfClass
:[
NSDictionary
class
]])
{
_txLivePlayer
.
config
=
[
FTXTransformation
transformToLiveConfig
:
args
];
}
}
#pragma mark -
-
(
void
)
handleMethodCall
:
(
FlutterMethodCall
*
)
call
result
:
(
FlutterResult
)
result
{
NSDictionary
*
args
=
call
.
arguments
;
if
([
@"init"
isEqualToString
:
call
.
method
]){
BOOL
onlyAudio
=
[
args
[
@"onlyAudio"
]
boolValue
];
NSNumber
*
textureId
=
[
self
createPlayer
:
onlyAudio
];
...
...
@@ -309,12 +325,15 @@ static const int uninitialized = -1;
result
(
nil
);
}
else
if
([
@"destory"
isEqualToString
:
call
.
method
])
{
[
self
destory
];
result
(
nil
);
}
else
if
([
@"setRenderRotation"
isEqualToString
:
call
.
method
])
{
int
rotation
=
[
args
[
@"rotation"
]
intValue
];
[
self
setRenderRotation
:
rotation
];
result
(
nil
);
}
else
if
([
@"switchStream"
isEqualToString
:
call
.
method
])
{
NSString
*
url
=
args
[
@"url"
];
[
self
switchStream
:
url
];
int
switchResult
=
[
self
switchStream
:
url
];
result
(
@
(
switchResult
));
}
else
if
([
@"seek"
isEqualToString
:
call
.
method
])
{
result
(
FlutterMethodNotImplemented
);
}
else
if
([
@"setAppID"
isEqualToString
:
call
.
method
])
{
...
...
@@ -327,6 +346,13 @@ static const int uninitialized = -1;
}
else
if
([
@"resumeLive"
isEqualToString
:
call
.
method
])
{
int
r
=
[
self
resumeLive
];
result
(
@
(
r
));
}
else
if
([
@"enableHardwareDecode"
isEqualToString
:
call
.
method
])
{
BOOL
enable
=
[
args
[
@"enable"
]
boolValue
];
int
r
=
[
self
enableHardwareDecode
:
enable
];
result
(
@
(
r
));
}
else
if
([
@"setConfig"
isEqualToString
:
call
.
method
]){
[
self
setPlayConfig
:
args
];
result
(
nil
);
}
else
{
result
(
FlutterMethodNotImplemented
);
}
...
...
Flutter/ios/Classes/FTXTransformation.h
浏览文件 @
efb9316d
...
...
@@ -6,6 +6,8 @@ static NSString* cacheFolder = nil;
static
int
maxCacheItems
=
-
1
;
@interface
FTXTransformation
:
NSObject
+
(
TXVodPlayConfig
*
)
transformToConfig
:(
NSDictionary
*
)
map
;
+
(
TXVodPlayConfig
*
)
transformToVodConfig
:(
NSDictionary
*
)
map
;
+
(
TXLivePlayConfig
*
)
transformToLiveConfig
:(
NSDictionary
*
)
map
;
@end
Flutter/ios/Classes/FTXTransformation.m
浏览文件 @
efb9316d
...
...
@@ -4,7 +4,7 @@
@implementation
FTXTransformation
+
(
TXVodPlayConfig
*
)
transformToConfig
:(
NSDictionary
*
)
args
+
(
TXVodPlayConfig
*
)
transformTo
Vod
Config
:(
NSDictionary
*
)
args
{
TXVodPlayConfig
*
playConfig
=
[[
TXVodPlayConfig
alloc
]
init
];
playConfig
.
connectRetryCount
=
[
args
[
@"config"
][
@"connectRetryCount"
]
intValue
];
...
...
@@ -48,6 +48,25 @@
return
playConfig
;
}
+
(
TXLivePlayConfig
*
)
transformToLiveConfig
:(
NSDictionary
*
)
args
{
TXLivePlayConfig
*
playConfig
=
[[
TXLivePlayConfig
alloc
]
init
];
playConfig
.
cacheTime
=
[
args
[
@"config"
][
@"cacheTime"
]
floatValue
];
playConfig
.
maxAutoAdjustCacheTime
=
[
args
[
@"config"
][
@"maxAutoAdjustCacheTime"
]
floatValue
];
playConfig
.
minAutoAdjustCacheTime
=
[
args
[
@"config"
][
@"minAutoAdjustCacheTime"
]
floatValue
];
playConfig
.
videoBlockThreshold
=
[
args
[
@"config"
][
@"videoBlockThreshold"
]
intValue
];
playConfig
.
connectRetryCount
=
[
args
[
@"config"
][
@"connectRetryCount"
]
intValue
];
playConfig
.
connectRetryInterval
=
[
args
[
@"config"
][
@"connectRetryInterval"
]
intValue
];
playConfig
.
bAutoAdjustCacheTime
=
[
args
[
@"config"
][
@"autoAdjustCacheTime"
]
boolValue
];
playConfig
.
enableAEC
=
[
args
[
@"config"
][
@"enableAec"
]
boolValue
];
playConfig
.
enableMessage
=
[
args
[
@"config"
][
@"enableMessage"
]
intValue
];
playConfig
.
enableMetaData
=
[
args
[
@"config"
][
@"enableMetaData"
]
intValue
];
playConfig
.
flvSessionKey
=
[
args
[
@"config"
][
@"flvSessionKey"
]
stringValue
];
return
playConfig
;
}
@end
Flutter/ios/Classes/FTXVodPlayer.m
浏览文件 @
efb9316d
...
...
@@ -583,7 +583,7 @@ BOOL volatile isStop = false;
-
(
void
)
setPlayConfig
:
(
NSDictionary
*
)
args
{
if
(
_txVodPlayer
!=
nil
&&
[
args
[
@"config"
]
isKindOfClass
:[
NSDictionary
class
]])
{
_txVodPlayer
.
config
=
[
FTXTransformation
transformToConfig
:
args
];
_txVodPlayer
.
config
=
[
FTXTransformation
transformTo
Vod
Config
:
args
];
}
}
...
...
Flutter/ios/Classes/SuperPlayerPlugin.m
浏览文件 @
efb9316d
...
...
@@ -187,6 +187,10 @@ SuperPlayerPlugin* instance;
}
else
if
([
@"isDeviceSupportPip"
isEqualToString
:
call
.
method
])
{
BOOL
isSupport
=
[
TXVodPlayer
isSupportPictureInPicture
];
result
([
NSNumber
numberWithBool
:
isSupport
]);
}
else
if
([
@"setGlobalEnv"
isEqualToString
:
call
.
method
])
{
NSString
*
envConfig
=
call
.
arguments
[
@"envConfig"
];
int
setResult
=
[
TXLiveBase
setGlobalEnv
:[
envConfig
UTF8String
]];
result
(
@
(
setResult
));
}
else
{
result
(
FlutterMethodNotImplemented
);
}
...
...
Flutter/lib/Core/provider/txplayer_holder.dart
0 → 100644
浏览文件 @
efb9316d
// Copyright (c) 2022 Tencent. All rights reserved.
part of
SuperPlayer
;
abstract
class
TXModel
{
}
class
TXPlayerHolder
extends
TXModel
{
TXPlayerController
controller
;
TXPlayerHolder
(
this
.
controller
);
void
updateController
(
TXPlayerController
playerController
)
{
controller
=
playerController
;
}
}
Flutter/lib/Core/superplayer_plugin.dart
浏览文件 @
efb9316d
...
...
@@ -19,6 +19,7 @@ class SuperPlayerPlugin {
/// 原生交互,通用事件监听,来自插件的事件,例如 声音变化等事件
Stream
<
Map
<
dynamic
,
dynamic
>>
get
onEventBroadcast
=>
_eventStreamController
.
stream
;
/// 原生交互,通用事件监听,来自原生容器的事件,例如 PIP事件、activity/controller 生命周期变化
Stream
<
Map
<
dynamic
,
dynamic
>>
get
onExtraEventBroadcast
=>
_eventPipStreamController
.
stream
;
...
...
@@ -153,4 +154,16 @@ class SuperPlayerPlugin {
static
Future
<
String
?>
getLiteAVSDKVersion
()
async
{
return
await
_channel
.
invokeMethod
(
'getLiteAVSDKVersion'
);
}
///
/// 设置 liteav SDK 接入的环境。
/// 腾讯云在全球各地区部署的环境,按照各地区政策法规要求,需要接入不同地区接入点。
///
/// @param envConfig 需要接入的环境,SDK 默认接入的环境是:默认正式环境。
/// @return 0:成功;其他:错误
/// @note 目标市场为中国大陆的客户请不要调用此接口,如果目标市场为海外用户,请通过技术支持联系我们,了解 env_config 的配置方法,以确保 App 遵守 GDPR 标准。
///
static
Future
<
int
>
setGlobalEnv
(
String
envConfig
)
async
{
return
await
_channel
.
invokeMethod
(
"setGlobalEnv"
,
{
"envConfig"
:
envConfig
});
}
}
Flutter/lib/Core/txliveplayer_config.dart
0 → 100644
浏览文件 @
efb9316d
// Copyright (c) 2022 Tencent. All rights reserved.
part of
SuperPlayer
;
/// TXLivePlayer config
class
FTXLivePlayConfig
{
// 播放器缓存时间,单位秒,取值需要大于0,默认值:5
double
cacheTime
=
5.0
;
// 播放器缓存自动调整的最大时间,单位秒,取值需要大于0,默认值:5
double
maxAutoAdjustCacheTime
=
5.0
;
// 播放器缓存自动调整的最小时间,单位秒,取值需要大于0,默认值为1
double
minAutoAdjustCacheTime
=
1.0
;
// 播放器视频卡顿报警阈值,单位毫秒,只有渲染间隔超过这个阈值的卡顿才会有 PLAY_WARNING_VIDEO_PLAY_LAG 通知
int
videoBlockThreshold
=
800
;
// 播放器遭遇网络连接断开时 SDK 默认重试的次数,取值范围1 - 10,默认值:3。
int
connectRetryCount
=
3
;
// 网络重连的时间间隔,单位秒,取值范围3 - 30,默认值:3。
int
connectRetryInterval
=
3
;
// 是否自动调整播放器缓存时间,默认值:true
// true:启用自动调整,自动调整的最大值和最小值可以分别通过修改 maxCacheTime 和 minCacheTime 来设置
// false:关闭自动调整,采用默认的指定缓存时间(1s),可以通过修改 cacheTime 来调整缓存时间
bool
autoAdjustCacheTime
=
true
;
// 是否开启回声消除, 默认值为 false
bool
enableAec
=
false
;
// 是否开启消息通道, 默认值为 true
bool
enableMessage
=
true
;
// 是否开启 MetaData 数据回调,默认值为 NO。
// true:SDK 通过 EVT_PLAY_GET_METADATA 消息抛出视频流的 MetaData 数据;
// false:SDK 不抛出视频流的 MetaData 数据。
// 标准直播流都会在最开始的阶段有一个 MetaData 数据头,该数据头支持定制。
// 您可以通过 TXLivePushConfig 中的 metaData 属性设置一些自定义数据,再通过 TXLivePlayListener 中的
// onPlayEvent(EVT_PLAY_GET_METADATA) 消息接收到这些数据。
//【特别说明】每条音视频流中只能设置一个 MetaData 数据头,除非断网重连,否则 TXLivePlayer 的
// EVT_PLAY_GET_METADATA 消息也只会收到一次。
bool
enableMetaData
=
false
;
// 是否开启 HTTP 头信息回调,默认值为 “”
// HTTP
// 响应头中除了“content-length”、“content-type”等标准字段,不同云服务商还可能会添加一些非标准字段。
// 比如腾讯云会在直播 CDN 的 HTTP-FLV 格式的直播流中增加 “X-Tlive-SpanId”
// 响应头,并在其中设置一个随机字符串,用来唯一标识一次直播。
//
// 如果您在使用腾讯云的直播 CDN,可以设置 flvSessionKey 为 “X-Tlive-SpanId”,SDK 会在 HTTP
// 响应头里解析这个字段, 并通过 TXLivePlayListener 中的 onPlayEvent(EVT_PLAY_GET_FLVSESSIONKEY)
// 事件通知给您的 App。
//
//【特别说明】每条音视频流中只能解析一个 flvSessionKey,除非断网重连,否则
// EVT_PLAY_GET_FLVSESSIONKEY 只会抛送一次。
String
flvSessionKey
=
""
;
Map
<
String
,
dynamic
>
toJson
()
{
Map
<
String
,
dynamic
>
json
=
{};
json
[
"cacheTime"
]
=
cacheTime
;
json
[
"maxAutoAdjustCacheTime"
]
=
maxAutoAdjustCacheTime
;
json
[
"minAutoAdjustCacheTime"
]
=
minAutoAdjustCacheTime
;
json
[
"videoBlockThreshold"
]
=
videoBlockThreshold
;
json
[
"connectRetryCount"
]
=
connectRetryCount
;
json
[
"connectRetryInterval"
]
=
connectRetryInterval
;
json
[
"autoAdjustCacheTime"
]
=
autoAdjustCacheTime
;
json
[
"enableAec"
]
=
enableAec
;
json
[
"enableMessage"
]
=
enableMessage
;
json
[
"enableMetaData"
]
=
enableMetaData
;
json
[
"flvSessionKey"
]
=
flvSessionKey
;
return
json
;
}
}
\ No newline at end of file
Flutter/lib/Core/txliveplayer_controller.dart
浏览文件 @
efb9316d
差异被折叠。
点击展开。
Flutter/lib/Core/txplayer_controller.dart
浏览文件 @
efb9316d
...
...
@@ -9,4 +9,18 @@ abstract class TXPlayerController {
double
?
get
videoTop
;
double
?
get
videoRight
;
double
?
get
videoBottom
;
Future
<
bool
>
startPlay
(
String
url
);
Future
<
void
>
initialize
({
bool
?
onlyAudio
});
Future
<
void
>
setAutoPlay
({
bool
?
isAutoPlay
});
Future
<
bool
>
stop
({
bool
isNeedClear
=
false
});
Future
<
bool
>
isPlaying
();
Future
<
void
>
pause
();
Future
<
void
>
resume
();
Future
<
void
>
setMute
(
bool
mute
);
Future
<
void
>
seek
(
double
progress
);
Future
<
void
>
setRate
(
double
rate
);
Future
<
bool
>
enableHardwareDecode
(
bool
enable
);
Future
<
int
>
enterPictureInPictureMode
(
{
String
?
backIconForAndroid
,
String
?
playIconForAndroid
,
String
?
pauseIconForAndroid
,
String
?
forwardIconForAndroid
});
}
\ No newline at end of file
Flutter/lib/Core/txplayer_define.dart
浏览文件 @
efb9316d
...
...
@@ -116,7 +116,7 @@ abstract class TXVodPlayEvent {
static
const
ERROR_IOS_PIP_PLAYER_NOT_EXIST
=
-
109
;
// pip 错误,播放器对象不存在 only support iOS
static
const
ERROR_IOS_PIP_IS_RUNNING
=
-
110
;
// pip 错误,PIP功能已经运行 only support iOS
static
const
ERROR_IOS_PIP_NOT_RUNNING
=
-
111
;
// pip 错误,PIP功能没有启动 only support iOS
static
const
ERROR_PIP_CAN_NOT_ENTER
=
-
120
;
// pip 错误,当前不能进入pip模式,例如正处于全屏模式下
/// 视频下载相关事件
static
const
EVENT_PREDOWNLOAD_ON_COMPLETE
=
200
;
// 视频预下载完成
...
...
Flutter/lib/Core/txplayer_widget.dart
浏览文件 @
efb9316d
...
...
@@ -3,10 +3,9 @@ part of SuperPlayer;
class
TXPlayerVideo
extends
StatefulWidget
{
final
TXPlayerController
controller
;
final
Stream
<
TXPlayerHolder
>?
playerStream
;
TXPlayerVideo
({
required
this
.
controller
,
Key
?
key
})
:
super
(
key:
key
)
{
assert
(
controller
!=
null
);
}
TXPlayerVideo
({
required
this
.
controller
,
this
.
playerStream
});
@override
TXPlayerVideoState
createState
()
=>
TXPlayerVideoState
();
...
...
@@ -16,52 +15,82 @@ class TXPlayerVideoState extends State<TXPlayerVideo> {
static
const
TAG
=
"TXPlayerVideo"
;
int
_textureId
=
-
1
;
StreamSubscription
?
streamSubscription
;
late
TXPlayerController
controller
;
@override
void
initState
()
{
super
.
initState
();
controller
=
widget
.
controller
;
_checkStreamListen
();
_resetControllerLink
();
}
void
_checkStreamListen
()
{
if
(
null
!=
streamSubscription
)
{
streamSubscription
!.
cancel
();
}
streamSubscription
=
widget
.
playerStream
?.
listen
((
event
)
{
controller
=
event
.
controller
;
_resetControllerLink
();
});
}
widget
.
controller
.
textureId
.
then
((
newTextureId
)
{
if
(
_textureId
!=
newTextureId
)
{
void
_resetControllerLink
()
async
{
int
remainTextureId
=
await
controller
.
textureId
;
if
(
remainTextureId
>=
0
)
{
if
(
remainTextureId
!=
_textureId
)
{
setState
(()
{
LogUtils
.
d
(
TAG
,
"_textureId =
$
new
TextureId
"
);
_textureId
=
new
TextureId
;
LogUtils
.
d
(
TAG
,
"_textureId =
$
remain
TextureId
"
);
_textureId
=
remain
TextureId
;
});
}
});
}
else
{
setState
(()
{
_textureId
=
-
1
;
});
controller
.
textureId
.
then
((
newTextureId
)
{
if
(
_textureId
!=
newTextureId
)
{
setState
(()
{
LogUtils
.
d
(
TAG
,
"_textureId =
$newTextureId
"
);
_textureId
=
newTextureId
;
});
}
});
}
}
@override
Widget
build
(
BuildContext
context
)
{
if
((
defaultTargetPlatform
==
TargetPlatform
.
android
)
&&
(
widget
.
controller
.
resizeVideoHeight
!
>
0
&&
widget
.
controller
.
resizeVideoWidth
!
>
0
))
{
(
controller
.
resizeVideoHeight
!
>
0
&&
controller
.
resizeVideoWidth
!
>
0
))
{
return
_textureId
==
-
1
?
Container
()
:
LayoutBuilder
(
builder:
(
context
,
constrains
)
{
var
viewWidth
=
constrains
.
maxWidth
;
var
viewHeight
=
constrains
.
maxHeight
;
var
videoWidth
=
widget
.
controller
.
resizeVideoWidth
!;
var
videoHeight
=
widget
.
controller
.
resizeVideoHeight
!;
var
viewWidth
=
constrains
.
maxWidth
;
var
viewHeight
=
constrains
.
maxHeight
;
var
videoWidth
=
controller
.
resizeVideoWidth
!;
var
videoHeight
=
widget
.
controller
.
resizeVideoHeight
!;
double
left
=
widget
.
controller
.
videoLeft
!
*
viewWidth
/
videoWidth
;
double
top
=
widget
.
controller
.
videoTop
!
*
viewHeight
/
videoHeight
;
double
right
=
widget
.
controller
.
videoRight
!
*
viewWidth
/
videoWidth
;
double
bottom
=
widget
.
controller
.
videoBottom
!
*
viewHeight
/
videoHeight
;
return
Stack
(
children:
[
Positioned
(
top:
top
,
left:
left
,
right:
right
,
bottom:
bottom
,
child:
Texture
(
textureId:
_textureId
)
)
],
);
});
double
left
=
controller
.
videoLeft
!
*
viewWidth
/
videoWidth
;
double
top
=
controller
.
videoTop
!
*
viewHeight
/
videoHeight
;
double
right
=
controller
.
videoRight
!
*
viewWidth
/
videoWidth
;
double
bottom
=
controller
.
videoBottom
!
*
viewHeight
/
videoHeight
;
return
Stack
(
children:
[
Positioned
(
top:
top
,
left:
left
,
right:
right
,
bottom:
bottom
,
child:
Texture
(
textureId:
_textureId
))
],
);
});
}
else
{
return
_textureId
==
-
1
?
Container
()
:
Texture
(
textureId:
_textureId
);
return
_textureId
==
-
1
?
Container
()
:
Texture
(
textureId:
_textureId
);
}
}
@override
void
dispose
()
{
streamSubscription
?.
cancel
();
super
.
dispose
();
}
}
Flutter/lib/Core/txvodplayer_controller.dart
浏览文件 @
efb9316d
...
...
@@ -17,9 +17,7 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
StreamSubscription
?
_netSubscription
;
final
StreamController
<
TXPlayerState
?>
_stateStreamController
=
StreamController
.
broadcast
();
final
StreamController
<
Map
<
dynamic
,
dynamic
>>
_eventStreamController
=
StreamController
.
broadcast
();
final
StreamController
<
Map
<
dynamic
,
dynamic
>>
_netStatusStreamController
=
StreamController
.
broadcast
();
/// 播放状态监听,@see TXPlayerState
...
...
@@ -137,6 +135,7 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
/// 通过url开始播放视频
/// @param url : 视频播放地址
/// return 是否播放成功
@override
Future
<
bool
>
startPlay
(
String
url
)
async
{
await
_initPlayer
.
future
;
await
_createTexture
.
future
;
...
...
@@ -165,6 +164,7 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
/// 播放器初始化,创建共享纹理、初始化播放器
/// @param onlyAudio 是否是纯音频模式
@override
Future
<
void
>
initialize
({
bool
?
onlyAudio
})
async
{
if
(
_isNeedDisposed
)
return
;
await
_initPlayer
.
future
;
...
...
@@ -176,6 +176,7 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
}
/// 设置是否自动播放
@override
Future
<
void
>
setAutoPlay
({
bool
?
isAutoPlay
})
async
{
if
(
_isNeedDisposed
)
return
;
await
_initPlayer
.
future
;
...
...
@@ -184,7 +185,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
/// 停止播放
/// return 是否停止成功
Future
<
bool
>
stop
({
bool
isNeedClear
=
true
})
async
{
@override
Future
<
bool
>
stop
({
bool
isNeedClear
=
false
})
async
{
if
(
_isNeedDisposed
)
return
false
;
await
_initPlayer
.
future
;
final
result
=
await
_channel
.
invokeMethod
(
"stop"
,
{
"isNeedClear"
:
isNeedClear
});
...
...
@@ -193,12 +195,14 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
}
/// 视频是否处于正在播放中
Future
<
bool
?>
isPlaying
()
async
{
@override
Future
<
bool
>
isPlaying
()
async
{
await
_initPlayer
.
future
;
return
await
_channel
.
invokeMethod
(
"isPlaying"
);
}
/// 视频暂停,必须在播放器开始播放的时候调用
@override
Future
<
void
>
pause
()
async
{
if
(
_isNeedDisposed
)
return
;
await
_initPlayer
.
future
;
...
...
@@ -207,6 +211,7 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
}
/// 继续播放,在暂停的时候调用
@override
Future
<
void
>
resume
()
async
{
if
(
_isNeedDisposed
)
return
;
await
_initPlayer
.
future
;
...
...
@@ -214,6 +219,7 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
}
/// 设置是否静音
@override
Future
<
void
>
setMute
(
bool
mute
)
async
{
if
(
_isNeedDisposed
)
return
;
await
_initPlayer
.
future
;
...
...
@@ -229,6 +235,7 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
/// 将视频播放进度定位到指定的进度进行播放
/// progress 要定位的视频时间,单位 秒
@override
Future
<
void
>
seek
(
double
progress
)
async
{
if
(
_isNeedDisposed
)
return
;
await
_initPlayer
.
future
;
...
...
@@ -236,6 +243,7 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
}
/// 设置播放速率,默认速率 1
@override
Future
<
void
>
setRate
(
double
rate
)
async
{
if
(
_isNeedDisposed
)
return
;
await
_initPlayer
.
future
;
...
...
@@ -294,7 +302,7 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
}
/// 设置播放器配置
/// config @see
FTXVodPlayConfig
/// config @see
[FTXVodPlayConfig]
Future
<
void
>
setConfig
(
FTXVodPlayConfig
config
)
async
{
if
(
_isNeedDisposed
)
return
;
await
_initPlayer
.
future
;
...
...
@@ -351,6 +359,7 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
}
/// 开启/关闭硬件编码
@override
Future
<
bool
>
enableHardwareDecode
(
bool
enable
)
async
{
if
(
_isNeedDisposed
)
return
false
;
await
_initPlayer
.
future
;
...
...
@@ -363,12 +372,26 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
/// </h1>
/// @param backIcon playIcon pauseIcon forwardIcon 为播放后退、播放、暂停、前进的图标,如果赋值的话,将会使用传递的图标,否则
/// 使用系统默认图标,只支持flutter本地资源图片,传递的时候,与flutter使用图片资源一致,例如: images/back_icon.png
@override
Future
<
int
>
enterPictureInPictureMode
(
{
String
?
backIcon
,
String
?
playIcon
,
String
?
pauseIcon
,
String
?
forwardIcon
})
async
{
{
String
?
backIconForAndroid
,
String
?
playIconForAndroid
,
String
?
pauseIconForAndroid
,
String
?
forwardIconForAndroid
})
async
{
if
(
_isNeedDisposed
)
return
-
1
;
await
_initPlayer
.
future
;
return
await
_channel
.
invokeMethod
(
"enterPictureInPictureMode"
,
{
"backIcon"
:
backIcon
,
"playIcon"
:
playIcon
,
"pauseIcon"
:
pauseIcon
,
"forwardIcon"
:
forwardIcon
});
if
(
Platform
.
isAndroid
)
{
return
await
_channel
.
invokeMethod
(
"enterPictureInPictureMode"
,
{
"backIcon"
:
backIconForAndroid
,
"playIcon"
:
playIconForAndroid
,
"pauseIcon"
:
pauseIconForAndroid
,
"forwardIcon"
:
forwardIconForAndroid
});
}
else
if
(
Platform
.
isIOS
)
{
return
await
_channel
.
invokeMethod
(
"enterPictureInPictureMode"
);
}
else
{
return
-
1
;
}
}
/// 获取总时长
...
...
@@ -378,13 +401,15 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
return
await
_channel
.
invokeMethod
(
"getDuration"
);
}
///
废弃
controller
///
释放
controller
@override
void
dispose
()
async
{
_isNeedDisposed
=
true
;
if
(!
_isDisposed
)
{
await
_eventSubscription
!.
cancel
();
_eventSubscription
=
null
;
await
_netSubscription
!.
cancel
();
_netSubscription
=
null
;
await
_release
();
_changeState
(
TXPlayerState
.
disposed
);
...
...
@@ -398,8 +423,6 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
}
@override
// TODO: implement value
get
value
=>
_value
;
set
value
(
TXPlayerValue
?
val
)
{
...
...
Flutter/lib/super_player.dart
浏览文件 @
efb9316d
...
...
@@ -3,6 +3,7 @@ library SuperPlayer;
import
'dart:async'
;
import
'dart:core'
;
import
'dart:io'
;
import
'dart:math'
;
import
'package:flutter/cupertino.dart'
;
...
...
@@ -19,4 +20,6 @@ part 'Core/txplayer_widget.dart';
part
'Core/txvodplayer_config.dart'
;
part
'Core/txvodplayer_controller.dart'
;
part
'Core/txvoddownload_controller.dart'
;
part
'Core/tools/common_utils.dart'
;
\ No newline at end of file
part
'Core/txliveplayer_config.dart'
;
part
'Core/tools/common_utils.dart'
;
part
'Core/provider/txplayer_holder.dart'
;
\ No newline at end of file
Flutter/pubspec.yaml
浏览文件 @
efb9316d
name
:
super_player
description
:
player plugin.
version
:
1.0.
3
version
:
1.0.
5
author
:
homepage
:
environment
:
sdk
:
'
>=2.12.0
<3.0.0'
flutter
:
"
>=
1.2
0.0"
flutter
:
"
>=
2.
0.0"
dependencies
:
flutter
:
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论