提交 cacc3d68 authored 作者: jiangjun's avatar jiangjun

实现android点播播放器截图

上级 6c5fa77a
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -7,6 +7,7 @@ import android.os.Bundle; ...@@ -7,6 +7,7 @@ import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
...@@ -15,6 +16,7 @@ import com.tencent.rtmp.ITXVodPlayListener; ...@@ -15,6 +16,7 @@ import com.tencent.rtmp.ITXVodPlayListener;
import com.tencent.rtmp.TXBitrateItem; import com.tencent.rtmp.TXBitrateItem;
import com.tencent.rtmp.TXImageSprite; import com.tencent.rtmp.TXImageSprite;
import com.tencent.rtmp.TXLiveConstants; import com.tencent.rtmp.TXLiveConstants;
import com.tencent.rtmp.TXLivePlayer;
import com.tencent.rtmp.TXPlayInfoParams; import com.tencent.rtmp.TXPlayInfoParams;
import com.tencent.rtmp.TXPlayerDrmBuilder; import com.tencent.rtmp.TXPlayerDrmBuilder;
import com.tencent.rtmp.TXTrackInfo; import com.tencent.rtmp.TXTrackInfo;
...@@ -23,6 +25,7 @@ import com.tencent.rtmp.TXVodDef; ...@@ -23,6 +25,7 @@ import com.tencent.rtmp.TXVodDef;
import com.tencent.rtmp.TXVodPlayConfig; import com.tencent.rtmp.TXVodPlayConfig;
import com.tencent.rtmp.TXVodPlayer; import com.tencent.rtmp.TXVodPlayer;
import com.tencent.rtmp.ui.TXCloudVideoView; import com.tencent.rtmp.ui.TXCloudVideoView;
import com.tencent.ugc.TXRecordCommon;
import com.tencent.vod.flutter.FTXEvent; import com.tencent.vod.flutter.FTXEvent;
import com.tencent.vod.flutter.FTXPIPManager; import com.tencent.vod.flutter.FTXPIPManager;
import com.tencent.vod.flutter.FTXTransformation; import com.tencent.vod.flutter.FTXTransformation;
...@@ -52,6 +55,9 @@ import com.tencent.vod.flutter.ui.render.FTXRenderView; ...@@ -52,6 +55,9 @@ import com.tencent.vod.flutter.ui.render.FTXRenderView;
import com.tencent.vod.flutter.ui.render.FTXRenderViewFactory; import com.tencent.vod.flutter.ui.render.FTXRenderViewFactory;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
...@@ -74,6 +80,7 @@ public class FTXVodPlayer extends FTXVodPlayerRenderHost implements ITXVodPlayLi ...@@ -74,6 +80,7 @@ public class FTXVodPlayer extends FTXVodPlayerRenderHost implements ITXVodPlayLi
private TXVodPlayer mVodPlayer; private TXVodPlayer mVodPlayer;
private TXImageSprite mTxImageSprite; private TXImageSprite mTxImageSprite;
private FTXRenderView mRenderView;
private static final int Uninitialized = -101; private static final int Uninitialized = -101;
private boolean mEnableHardwareDecode = true; private boolean mEnableHardwareDecode = true;
...@@ -272,6 +279,56 @@ public class FTXVodPlayer extends FTXVodPlayerRenderHost implements ITXVodPlayLi ...@@ -272,6 +279,56 @@ public class FTXVodPlayer extends FTXVodPlayerRenderHost implements ITXVodPlayLi
} }
} }
@NonNull
@Override
public FtxMessages.SnapshotRespMsg snapshot(@NonNull FtxMessages.SnapshotReqMsg playerMsg) {
// mVodPlayer.snapshot(bitmap -> {
//
// });
if (mVodPlayer != null && mRenderView != null) {
final FtxMessages.SnapshotRespMsg.Builder respBuilder = new FtxMessages.SnapshotRespMsg.Builder();
final Bitmap bitmap = mRenderView.captureBitmap();
if (bitmap != null && playerMsg.getFilePath() != null) {
// 确定图片格式
Bitmap.CompressFormat format = (playerMsg.getFormat() != null && playerMsg.getFormat() == 1)
? Bitmap.CompressFormat.JPEG
: Bitmap.CompressFormat.PNG;
// 确定图片质量
int quality = 100;
if (playerMsg.getQuality() != null) {
quality = Math.max(0, Math.min(100, (int) (playerMsg.getQuality() * 100)));
}
// 保存图片
try {
File file = new File(playerMsg.getFilePath());
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(format, quality, out);
out.flush();
out.close();
respBuilder.setSuccess(true);
respBuilder.setReason("");
} catch (IOException e) {
Log.e(TAG, "save bitmap failed", e);
respBuilder.setSuccess(false);
respBuilder.setReason(e.getMessage());
}
} else {
respBuilder.setSuccess(false);
respBuilder.setReason("bitmap is null or file path is null");
}
return respBuilder.build();
}
// 如果播放器为空,返回失败结果
return new FtxMessages.SnapshotRespMsg.Builder()
.setSuccess(false)
.setReason("player is null or renderView is null")
.build();
}
protected long init(boolean onlyAudio) { protected long init(boolean onlyAudio) {
if (mVodPlayer == null) { if (mVodPlayer == null) {
mVodPlayer = new TXVodPlayer(mFlutterPluginBinding.getApplicationContext()); mVodPlayer = new TXVodPlayer(mFlutterPluginBinding.getApplicationContext());
...@@ -887,6 +944,7 @@ public class FTXVodPlayer extends FTXVodPlayerRenderHost implements ITXVodPlayLi ...@@ -887,6 +944,7 @@ public class FTXVodPlayer extends FTXVodPlayerRenderHost implements ITXVodPlayLi
public void setPlayerView(@NonNull Long renderViewId) { public void setPlayerView(@NonNull Long renderViewId) {
int viewId = renderViewId.intValue(); int viewId = renderViewId.intValue();
FTXRenderView renderView = mRenderViewFactory.findViewById(viewId); FTXRenderView renderView = mRenderViewFactory.findViewById(viewId);
mRenderView = renderView;
if (null == renderView) { if (null == renderView) {
LiteavLog.e(TAG, "setPlayerView can not find renderView by id:" LiteavLog.e(TAG, "setPlayerView can not find renderView by id:"
+ viewId + ", release player's renderView"); + viewId + ", release player's renderView");
......
package com.tencent.vod.flutter.player.render.gl; package com.tencent.vod.flutter.player.render.gl;
import android.graphics.Bitmap;
import android.opengl.GLES20;
import java.nio.IntBuffer;
import android.graphics.SurfaceTexture; import android.graphics.SurfaceTexture;
import android.opengl.EGL14; import android.opengl.EGL14;
...@@ -498,4 +501,76 @@ public class FTXEGLRender implements SurfaceTexture.OnFrameAvailableListener { ...@@ -498,4 +501,76 @@ public class FTXEGLRender implements SurfaceTexture.OnFrameAvailableListener {
} }
} }
/**
* 捕获当前渲染帧的图像
* @return Bitmap 截图结果,如果失败则返回null
*/
public Bitmap captureFrame() {
if (mEGLDisplay == EGL14.EGL_NO_DISPLAY || mEGLSurfaceEncoder == EGL14.EGL_NO_SURFACE) {
LiteavLog.e(TAG, "Cannot capture frame, EGL not initialized");
return null;
}
try {
// 保存当前EGL环境
saveCurrentEglEnvironment();
// 设置当前EGL上下文
if (!makeCurrent(1)) {
LiteavLog.e(TAG, "Failed to make current context");
restoreEglEnvironment();
return null;
}
// 读取像素数据
int width = mViewWidth > 0 ? mViewWidth : mWidth;
int height = mViewHeight > 0 ? mViewHeight : mHeight;
if (width <= 0 || height <= 0) {
LiteavLog.e(TAG, "Invalid dimensions for capture: " + width + "x" + height);
restoreEglEnvironment();
return null;
}
// 创建缓冲区存储像素数据
int[] pixels = new int[width * height];
IntBuffer pixelBuffer = IntBuffer.wrap(pixels);
// 从OpenGL ES读取像素
GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, pixelBuffer);
// 检查是否有OpenGL错误
int error = GLES20.glGetError();
if (error != GLES20.GL_NO_ERROR) {
LiteavLog.e(TAG, "OpenGL error during glReadPixels: " + error);
restoreEglEnvironment();
return null;
}
// 恢复之前的EGL环境
restoreEglEnvironment();
// 创建Bitmap并转换像素格式(OpenGL坐标系与Bitmap坐标系不同,需要垂直翻转)
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
IntBuffer flippedBuffer = IntBuffer.allocate(width * height);
// 垂直翻转图像数据
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int srcIndex = (height - 1 - y) * width + x;
flippedBuffer.put(pixels[srcIndex]);
}
}
flippedBuffer.rewind();
bitmap.copyPixelsFromBuffer(flippedBuffer);
return bitmap;
} catch (Exception e) {
LiteavLog.e(TAG, "Error capturing frame", e);
restoreEglEnvironment();
return null;
}
}
} }
package com.tencent.vod.flutter.ui.render; package com.tencent.vod.flutter.ui.render;
import android.graphics.Bitmap;
import com.tencent.vod.flutter.player.render.FTXPlayerRenderSurfaceHost; import com.tencent.vod.flutter.player.render.FTXPlayerRenderSurfaceHost;
public interface FTXRenderCarrier { public interface FTXRenderCarrier {
...@@ -27,4 +29,6 @@ public interface FTXRenderCarrier { ...@@ -27,4 +29,6 @@ public interface FTXRenderCarrier {
void removeSurfaceTextureListener(FTXCarrierSurfaceListener listener); void removeSurfaceTextureListener(FTXCarrierSurfaceListener listener);
void removeAllSurfaceListener(); void removeAllSurfaceListener();
Bitmap captureBitmap();
} }
package com.tencent.vod.flutter.ui.render; package com.tencent.vod.flutter.ui.render;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
...@@ -103,4 +104,16 @@ public class FTXRenderView implements PlatformView { ...@@ -103,4 +104,16 @@ public class FTXRenderView implements PlatformView {
mContainer.setCarrier(null); mContainer.setCarrier(null);
LiteavLog.i(TAG, "render view is dispose, id:" + mViewId + ", view:" + hashCode()); LiteavLog.i(TAG, "render view is dispose, id:" + mViewId + ", view:" + hashCode());
} }
/**
* 截取当前纹理视图的图像
* @return Bitmap 截图结果,如果失败则返回null
*/
public Bitmap captureBitmap() {
if (mTextureView != null) {
return mTextureView.captureBitmap();
}
return null;
}
} }
package com.tencent.vod.flutter.ui.render; package com.tencent.vod.flutter.ui.render;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap;
import android.view.Surface; import android.view.Surface;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
import android.view.SurfaceView; import android.view.SurfaceView;
...@@ -227,6 +228,14 @@ public class FTXSurfaceView extends SurfaceView implements FTXRenderCarrier { ...@@ -227,6 +228,14 @@ public class FTXSurfaceView extends SurfaceView implements FTXRenderCarrier {
mSurfaceListenerDelegate.mExternalSurfaceListeners.clear(); mSurfaceListenerDelegate.mExternalSurfaceListeners.clear();
} }
@Override
public Bitmap captureBitmap() {
if (mRender != null) {
return mRender.captureFrame();
}
return null;
}
private static class SurfaceViewInnerListener implements SurfaceHolder.Callback { private static class SurfaceViewInnerListener implements SurfaceHolder.Callback {
private final List<FTXCarrierSurfaceListener> mExternalSurfaceListeners = new CopyOnWriteArrayList<>(); private final List<FTXCarrierSurfaceListener> mExternalSurfaceListeners = new CopyOnWriteArrayList<>();
......
package com.tencent.vod.flutter.ui.render; package com.tencent.vod.flutter.ui.render;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.SurfaceTexture; import android.graphics.SurfaceTexture;
import android.view.Surface; import android.view.Surface;
import android.view.TextureView; import android.view.TextureView;
...@@ -284,4 +285,13 @@ public class FTXTextureView extends TextureView implements FTXRenderCarrier { ...@@ -284,4 +285,13 @@ public class FTXTextureView extends TextureView implements FTXRenderCarrier {
} }
} }
@Override
public Bitmap captureBitmap() {
if (mRender != null) {
return mRender.captureFrame();
}
return null;
}
} }
...@@ -27,7 +27,7 @@ android { ...@@ -27,7 +27,7 @@ android {
namespace="com.example.flutter.player" namespace="com.example.flutter.player"
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.tencent.liteav.demo" applicationId "com.hiteacher.industrylearner2"
minSdkVersion flutter.minSdkVersion minSdkVersion flutter.minSdkVersion
targetSdk 34 targetSdk 34
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
......
...@@ -4,8 +4,8 @@ ...@@ -4,8 +4,8 @@
import 'dart:async'; import 'dart:async';
// The obtained license URL // The obtained license URL
const LICENSE_URL = ""; const LICENSE_URL = "https://1390221090.trtcube-license.cn/license/v2/1390221090_1/v_cube.license";
// The obtained license key // The obtained license key
const LICENSE_KEY = ""; const LICENSE_KEY = "ac0e94a28975a987b86c29429275ecf5";
Completer<bool> isLicenseSuc = Completer(); Completer<bool> isLicenseSuc = Completer();
\ No newline at end of file
...@@ -320,6 +320,8 @@ class _DemoSuperPlayerState extends State<DemoSuperPlayer> with TXPipPlayerResto ...@@ -320,6 +320,8 @@ class _DemoSuperPlayerState extends State<DemoSuperPlayer> with TXPipPlayerResto
SuperPlayerModel model = SuperPlayerModel(); SuperPlayerModel model = SuperPlayerModel();
model.title = AppLocals.current.playerTestVideo; model.title = AppLocals.current.playerTestVideo;
model.videoURL = "http://liteavapp.qcloud.com/live/liteavdemoplayerstreamid_demo1080p.flv"; model.videoURL = "http://liteavapp.qcloud.com/live/liteavdemoplayerstreamid_demo1080p.flv";
// model.videoURL = 'https://cdn.pixabay.com/video/2025/10/22/311442_large.mp4';
// model.videoURL = 'https://1257307760.vod2.myqcloud.com/ce465e88vodcq1257307760/df8e0dfa1253642701442822691/Km2GPDojwSEA.mp4';
model.coverUrl = model.coverUrl =
"http://1500005830.vod2.myqcloud.com/6c9a5118vodcq1500005830/66bc542f387702300661648850/0RyP1rZfkdQA.png"; "http://1500005830.vod2.myqcloud.com/6c9a5118vodcq1500005830/66bc542f387702300661648850/0RyP1rZfkdQA.png";
model.playAction = playAction; model.playAction = playAction;
......
// Copyright (c) 2022 Tencent. All rights reserved. // Copyright (c) 2022 Tencent. All rights reserved.
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
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:path_provider/path_provider.dart';
import 'package:super_player/super_player.dart'; import 'package:super_player/super_player.dart';
import 'package:super_player_example/res/app_localizations.dart'; import 'package:super_player_example/res/app_localizations.dart';
import 'package:superplayer_widget/demo_superplayer_lib.dart'; import 'package:superplayer_widget/demo_superplayer_lib.dart';
...@@ -19,14 +21,19 @@ class DemoTXVodPlayer extends StatefulWidget { ...@@ -19,14 +21,19 @@ class DemoTXVodPlayer extends StatefulWidget {
_DemoTXVodPlayerState createState() => _DemoTXVodPlayerState(); _DemoTXVodPlayerState createState() => _DemoTXVodPlayerState();
} }
class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingObserver { class _DemoTXVodPlayerState extends State<DemoTXVodPlayer>
with WidgetsBindingObserver {
late TXVodPlayerController _controller; late TXVodPlayerController _controller;
double _currentProgress = 0.0; double _currentProgress = 0.0;
bool _isMute = false; bool _isMute = false;
int _volume = 100; int _volume = 100;
List _supportedBitrates = []; List _supportedBitrates = [];
int _curBitrateIndex = 0; int _curBitrateIndex = 0;
String _url = "https://1500005830.vod2.myqcloud.com/43843ec0vodtranscq1500005830/48d0f1f9387702299774251236/adp.10.m3u8";
// String _url = "http://1500005830.vod2.myqcloud.com/43843ec0vodtranscq1500005830/48d0f1f9387702299774251236/adp.10.m3u8";
String _url = 'https://cdn.pixabay.com/video/2025/10/22/311442_large.mp4';
// String _url = 'https://1257307760.vod2.myqcloud.com/ce465e88vodcq1257307760/df8e0dfa1253642701442822691/Km2GPDojwSEA.mp4';
TXPlayInfoParams? _videoParams; TXPlayInfoParams? _videoParams;
int _appId = 0; int _appId = 0;
String _fileId = ""; String _fileId = "";
...@@ -37,10 +44,12 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb ...@@ -37,10 +44,12 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb
StreamSubscription? playEventSubscription; StreamSubscription? playEventSubscription;
StreamSubscription? playNetEventSubscription; StreamSubscription? playNetEventSubscription;
FTXAndroidRenderViewType _renderType = FTXAndroidRenderViewType.SURFACE_VIEW; FTXAndroidRenderViewType _renderType = FTXAndroidRenderViewType.SURFACE_VIEW;
FTXPlayerRenderMode _renderMode = FTXPlayerRenderMode.ADJUST_RESOLUTION; FTXPlayerRenderMode _renderMode = FTXPlayerRenderMode.FULL_FILL_CONTAINER;
GlobalKey<VideoSliderViewState> progressSliderKey = GlobalKey(); GlobalKey<VideoSliderViewState> progressSliderKey = GlobalKey();
String? _snapshotPath;
Future<void> init() async { Future<void> init() async {
if (!mounted) return; if (!mounted) return;
await SuperPlayerPlugin.setConsoleEnabled(true); await SuperPlayerPlugin.setConsoleEnabled(true);
...@@ -48,25 +57,28 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb ...@@ -48,25 +57,28 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb
debugPrint("Playback status ${val?.name}"); debugPrint("Playback status ${val?.name}");
}); });
LogUtils.logOpen = true; LogUtils.logOpen = true;
playEventSubscription =
playEventSubscription = _controller.onPlayerEventBroadcast.listen((event) async { _controller.onPlayerEventBroadcast.listen((event) async {
// Subscribe to event distribution // Subscribe to event distribution
final int code = event["event"]; final int code = event["event"];
if (code == TXVodPlayEvent.PLAY_EVT_RCV_FIRST_I_FRAME) { if (code == TXVodPlayEvent.PLAY_EVT_RCV_FIRST_I_FRAME) {
EasyLoading.dismiss(); EasyLoading.dismiss();
_supportedBitrates = (await _controller.getSupportedBitrates())!; _supportedBitrates = (await _controller.getSupportedBitrates())!;
} else if (code== TXVodPlayEvent.PLAY_EVT_PLAY_PROGRESS) { } else if (code == TXVodPlayEvent.PLAY_EVT_PLAY_PROGRESS) {
_isPlaying = true; _isPlaying = true;
_currentProgress = event[TXVodPlayEvent.EVT_PLAY_PROGRESS].toDouble(); _currentProgress = event[TXVodPlayEvent.EVT_PLAY_PROGRESS].toDouble();
double videoDuration = event[TXVodPlayEvent.EVT_PLAY_DURATION].toDouble(); // Total playback time, converted unit in seconds double videoDuration = event[TXVodPlayEvent.EVT_PLAY_DURATION]
.toDouble(); // Total playback time, converted unit in seconds
if (videoDuration == 0.0) { if (videoDuration == 0.0) {
progressSliderKey.currentState?.updateProgress(0.0, 0.0); progressSliderKey.currentState?.updateProgress(0.0, 0.0);
} else { } else {
progressSliderKey.currentState?.updateProgress(_currentProgress / videoDuration, videoDuration); progressSliderKey.currentState
?.updateProgress(_currentProgress / videoDuration, videoDuration);
} }
} else if (code == TXVodPlayEvent.PLAY_EVT_PLAY_LOADING) { } else if (code == TXVodPlayEvent.PLAY_EVT_PLAY_LOADING) {
EasyLoading.show(status: "loading"); EasyLoading.show(status: "loading");
} else if (code == TXVodPlayEvent.PLAY_EVT_VOD_LOADING_END || code == TXVodPlayEvent.PLAY_EVT_PLAY_BEGIN) { } else if (code == TXVodPlayEvent.PLAY_EVT_VOD_LOADING_END ||
code == TXVodPlayEvent.PLAY_EVT_PLAY_BEGIN) {
EasyLoading.dismiss(); EasyLoading.dismiss();
} else if (code != -100 && code < 0) { } else if (code != -100 && code < 0) {
EasyLoading.showToast("playError:$event"); EasyLoading.showToast("playError:$event");
...@@ -130,7 +142,7 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb ...@@ -130,7 +142,7 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb
height: 230, height: 230,
color: Colors.black, color: Colors.black,
child: Center( child: Center(
child:Container( child: Container(
width: double.infinity, width: double.infinity,
height: double.infinity, height: double.infinity,
child: TXPlayerVideo( child: TXPlayerVideo(
...@@ -147,8 +159,7 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb ...@@ -147,8 +159,7 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb
_controller.setPlayerView(viewId); _controller.setPlayerView(viewId);
}, },
), ),
) )),
),
), ),
VideoSliderView(_controller, progressSliderKey), VideoSliderView(_controller, progressSliderKey),
Expanded( Expanded(
...@@ -167,10 +178,18 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb ...@@ -167,10 +178,18 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb
children: [ children: [
Container( Container(
height: 100, height: 100,
child: IconButton(icon: Image.asset('images/addp.png'), onPressed: () => {onPressed()}), child: IconButton(
icon: Image.asset('images/addp.png'),
onPressed: () => {onPressed()}),
) )
], ],
)), )),
Builder(builder: (context) {
if (_snapshotPath != null) {
return Image.file(File(_snapshotPath!));
}
return const SizedBox();
})
], ],
), ),
)), )),
...@@ -185,14 +204,21 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb ...@@ -185,14 +204,21 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb
_isPlaying = false; _isPlaying = false;
_controller.pause(); _controller.pause();
}), }),
_createItem(AppLocals.current.playerVariableSpeedPlay, () {onClickSetRate();}), _createItem(AppLocals.current.playerVariableSpeedPlay, () {
_createItem(_isMute ? AppLocals.current.playerCancelMute : AppLocals.current.playerSetMute, () { onClickSetRate();
}),
_createItem(
_isMute
? AppLocals.current.playerCancelMute
: AppLocals.current.playerSetMute, () {
setState(() { setState(() {
_isMute = !_isMute; _isMute = !_isMute;
_controller.setMute(_isMute); _controller.setMute(_isMute);
}); });
}), }),
_createItem(AppLocals.current.playerAdjustVolume, () {onClickVolume();}), _createItem(AppLocals.current.playerAdjustVolume, () {
onClickVolume();
}),
_createItem(AppLocals.current.playerSwitchBitrate, () { _createItem(AppLocals.current.playerSwitchBitrate, () {
if (_supportedBitrates.length > 1) { if (_supportedBitrates.length > 1) {
onClickBitrate(); onClickBitrate();
...@@ -202,7 +228,8 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb ...@@ -202,7 +228,8 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb
}), }),
_createItem(AppLocals.current.playerPlaybackDuration, () async { _createItem(AppLocals.current.playerPlaybackDuration, () async {
double time = await _controller.getCurrentPlaybackTime(); double time = await _controller.getCurrentPlaybackTime();
EasyLoading.showToast('${time.toStringAsFixed(2)}${AppLocals.current.playerSecond}'); EasyLoading.showToast(
'${time.toStringAsFixed(2)}${AppLocals.current.playerSecond}');
}), }),
_createItem(AppLocals.current.playerVideoSize, () async { _createItem(AppLocals.current.playerVideoSize, () async {
int width = await _controller.getWidth(); int width = await _controller.getWidth();
...@@ -213,11 +240,15 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb ...@@ -213,11 +240,15 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb
bool isLoop = await _controller.isLoop(); bool isLoop = await _controller.isLoop();
EasyLoading.showToast('isLoop:$isLoop'); EasyLoading.showToast('isLoop:$isLoop');
}), }),
_createItem(enableHardware ? AppLocals.current.playerSwitchSoft : AppLocals.current.playerSwitchHard, () async { _createItem(
enableHardware
? AppLocals.current.playerSwitchSoft
: AppLocals.current.playerSwitchHard, () async {
TXPlayerState? state = _controller.playState; TXPlayerState? state = _controller.playState;
if (state != TXPlayerState.disposed && state != TXPlayerState.stopped) { if (state != TXPlayerState.disposed && state != TXPlayerState.stopped) {
enableHardware = !enableHardware; enableHardware = !enableHardware;
bool enableSuccess = await _controller.enableHardwareDecode(enableHardware); bool enableSuccess =
await _controller.enableHardwareDecode(enableHardware);
double startTime = await _controller.getCurrentPlaybackTime(); double startTime = await _controller.getCurrentPlaybackTime();
await _controller.setStartTime(startTime); await _controller.setStartTime(startTime);
if (_url.isNotEmpty) { if (_url.isNotEmpty) {
...@@ -228,11 +259,15 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb ...@@ -228,11 +259,15 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb
EasyLoading.showError("video source is not exists"); EasyLoading.showError("video source is not exists");
} }
setState(() {}); setState(() {});
String wareMode = enableHardware ? AppLocals.current.playerHardEncode : AppLocals.current.playerSoftEncode; String wareMode = enableHardware
? AppLocals.current.playerHardEncode
: AppLocals.current.playerSoftEncode;
if (enableSuccess) { if (enableSuccess) {
EasyLoading.showToast(AppLocals.current.playerSwitchSucTo.txFormat([wareMode])); EasyLoading.showToast(
AppLocals.current.playerSwitchSucTo.txFormat([wareMode]));
} else { } else {
EasyLoading.showToast(AppLocals.current.playerSwitchFailedTo.txFormat([wareMode])); EasyLoading.showToast(
AppLocals.current.playerSwitchFailedTo.txFormat([wareMode]));
} }
} else { } else {
EasyLoading.showToast(AppLocals.current.playerPlayEnd); EasyLoading.showToast(AppLocals.current.playerPlayEnd);
...@@ -240,9 +275,11 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb ...@@ -240,9 +275,11 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb
}), }),
_createItem(AppLocals.current.playerPlayableTime, () async { _createItem(AppLocals.current.playerPlayableTime, () async {
double time = await _controller.getPlayableDuration(); double time = await _controller.getPlayableDuration();
EasyLoading.showToast(AppLocals.current.playerPlayableDurationTo.txFormat([time.toString()])); EasyLoading.showToast(AppLocals.current.playerPlayableDurationTo
.txFormat([time.toString()]));
}), }),
_createItem(_renderMode == FTXPlayerRenderMode.ADJUST_RESOLUTION _createItem(
_renderMode == FTXPlayerRenderMode.ADJUST_RESOLUTION
? AppLocals.current.playerRenderModeAdjust ? AppLocals.current.playerRenderModeAdjust
: AppLocals.current.playerRenderModeFill, () async { : AppLocals.current.playerRenderModeFill, () async {
if (_renderMode == FTXPlayerRenderMode.ADJUST_RESOLUTION) { if (_renderMode == FTXPlayerRenderMode.ADJUST_RESOLUTION) {
...@@ -253,13 +290,22 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb ...@@ -253,13 +290,22 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb
_controller.setRenderMode(_renderMode); _controller.setRenderMode(_renderMode);
setState(() {}); setState(() {});
}), }),
_createItem('截图', () async {
String savePath =
await getTemporaryDirectory().then((value) => value.path);
_snapshotPath = await _controller.snapshot(saveDirPath: savePath);
if (mounted) {
setState(() {});
}
}),
]; ];
/// iOS does not have this capability. /// iOS does not have this capability.
if (defaultTargetPlatform != TargetPlatform.iOS) { if (defaultTargetPlatform != TargetPlatform.iOS) {
children.add(_createItem(AppLocals.current.playerCacheTime, () async { children.add(_createItem(AppLocals.current.playerCacheTime, () async {
double time = await _controller.getBufferDuration(); double time = await _controller.getBufferDuration();
EasyLoading.showToast('${time.toStringAsFixed(2)}${AppLocals.current.playerSecond}'); EasyLoading.showToast(
'${time.toStringAsFixed(2)}${AppLocals.current.playerSecond}');
})); }));
} }
return children; return children;
...@@ -292,7 +338,12 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb ...@@ -292,7 +338,12 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb
showDialog( showDialog(
context: context, context: context,
builder: (context) { builder: (context) {
return DemoInputDialog("", 0, "", (String url, int appId, String fileId, String pSign, bool enableDownload, bool isDrm) { return DemoInputDialog(
"",
0,
"",
(String url, int appId, String fileId, String pSign,
bool enableDownload, bool isDrm) {
_url = url; _url = url;
_appId = appId; _appId = appId;
_fileId = fileId; _fileId = fileId;
...@@ -313,11 +364,17 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb ...@@ -313,11 +364,17 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb
_controller.startVodPlay(url); _controller.startVodPlay(url);
} else if (appId != 0 && fileId.isNotEmpty) { } else if (appId != 0 && fileId.isNotEmpty) {
_controller.stop(isNeedClear: true); _controller.stop(isNeedClear: true);
TXPlayInfoParams params = TXPlayInfoParams(appId: _appId, fileId: _fileId, psign: pSign != null ? pSign : ""); TXPlayInfoParams params = TXPlayInfoParams(
appId: _appId,
fileId: _fileId,
psign: pSign != null ? pSign : "");
_videoParams = params; _videoParams = params;
_controller.startVodPlayWithParams(params); _controller.startVodPlayWithParams(params);
} }
}, needPisgn: true, needDrm: true,); },
needPisgn: true,
needDrm: true,
);
}); });
} }
...@@ -347,7 +404,8 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb ...@@ -347,7 +404,8 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb
showDialog( showDialog(
context: context, context: context,
builder: (context) { builder: (context) {
return DemoBitrateCheckbox(_supportedBitrates, _curBitrateIndex, (int result) { return DemoBitrateCheckbox(_supportedBitrates, _curBitrateIndex,
(int result) {
_curBitrateIndex = result; _curBitrateIndex = result;
_controller.setBitrateIndex(_curBitrateIndex); _controller.setBitrateIndex(_curBitrateIndex);
EasyLoading.showSuccess(AppLocals.current.playerSwitchSuc); EasyLoading.showSuccess(AppLocals.current.playerSwitchSuc);
......
...@@ -37,7 +37,8 @@ class _MyAppState extends State<MyApp> { ...@@ -37,7 +37,8 @@ class _MyAppState extends State<MyApp> {
initPlayerLicense(); initPlayerLicense();
initPlatformState(); initPlatformState();
_getFlutterSdkVersion(); _getFlutterSdkVersion();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); // SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
SystemChrome.setPreferredOrientations([]);
LogUtils.logOpen = true; LogUtils.logOpen = true;
} }
......
...@@ -33,6 +33,8 @@ dependencies: ...@@ -33,6 +33,8 @@ dependencies:
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2 cupertino_icons: ^1.0.2
path_provider: 2.1.5
dependency_overrides: dependency_overrides:
# force override flutter_easyloading dep # force override flutter_easyloading dep
flutter_spinkit: 5.1.0 flutter_spinkit: 5.1.0
......
This source diff could not be displayed because it is too large. You can view the blob instead.
// Copyright (c) 2022 Tencent. All rights reserved. // Copyright (c) 2022 Tencent. All rights reserved.
part of SuperPlayer; part of SuperPlayer;
class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TXPlayerValue?>, class TXVodPlayerController extends ChangeNotifier
TXPlayerController, TXVodPlayerFlutterAPI { implements
ValueListenable<TXPlayerValue?>,
TXPlayerController,
TXVodPlayerFlutterAPI {
int? _playerId = -1; int? _playerId = -1;
static String kTag = "TXVodPlayerController"; static String kTag = "TXVodPlayerController";
...@@ -12,6 +15,7 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -12,6 +15,7 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
bool _isNeedDisposed = false; bool _isNeedDisposed = false;
TXPlayerValue? _value; TXPlayerValue? _value;
TXPlayerState? _state; TXPlayerState? _state;
TXPlayerState? get playState => _state; TXPlayerState? get playState => _state;
@override @override
...@@ -30,9 +34,12 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -30,9 +34,12 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
double? videoRight = 0; double? videoRight = 0;
double? videoBottom = 0; double? videoBottom = 0;
final StreamController<TXPlayerState?> _stateStreamController = StreamController.broadcast(); final StreamController<TXPlayerState?> _stateStreamController =
final StreamController<Map<dynamic, dynamic>> _eventStreamController = StreamController.broadcast(); StreamController.broadcast();
final StreamController<Map<dynamic, dynamic>> _netStatusStreamController = StreamController.broadcast(); final StreamController<Map<dynamic, dynamic>> _eventStreamController =
StreamController.broadcast();
final StreamController<Map<dynamic, dynamic>> _netStatusStreamController =
StreamController.broadcast();
/// Playback State Listener /// Playback State Listener
/// ///
...@@ -44,16 +51,17 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -44,16 +51,17 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
/// ///
/// 播放事件监听 /// 播放事件监听
/// @see:https://cloud.tencent.com/document/product/454/7886#.E6.92.AD.E6.94.BE.E4.BA.8B.E4.BB.B6 /// @see:https://cloud.tencent.com/document/product/454/7886#.E6.92.AD.E6.94.BE.E4.BA.8B.E4.BB.B6
Stream<Map<dynamic, dynamic>> get onPlayerEventBroadcast => _eventStreamController.stream; Stream<Map<dynamic, dynamic>> get onPlayerEventBroadcast =>
_eventStreamController.stream;
/// VOD player network status callback /// VOD player network status callback
/// ///
/// 点播播放器网络状态回调 /// 点播播放器网络状态回调
/// see:https://cloud.tencent.com/document/product/454/7886#.E6.92.AD.E6.94.BE.E4.BA.8B.E4.BB.B6 /// see:https://cloud.tencent.com/document/product/454/7886#.E6.92.AD.E6.94.BE.E4.BA.8B.E4.BB.B6
Stream<Map<dynamic, dynamic>> get onPlayerNetStatusBroadcast => _netStatusStreamController.stream; Stream<Map<dynamic, dynamic>> get onPlayerNetStatusBroadcast =>
_netStatusStreamController.stream;
TXVodPlayerController({bool? onlyAudio}) TXVodPlayerController({bool? onlyAudio}) : _initPlayer = Completer() {
: _initPlayer = Completer() {
_value = TXPlayerValue.uninitialized(); _value = TXPlayerValue.uninitialized();
_state = _value!.state; _state = _value!.state;
_create(onlyAudio: onlyAudio); _create(onlyAudio: onlyAudio);
...@@ -61,8 +69,10 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -61,8 +69,10 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
Future<void> _create({bool? onlyAudio}) async { Future<void> _create({bool? onlyAudio}) async {
_playerId = await SuperPlayerPlugin.createVodPlayer(onlyAudio: onlyAudio); _playerId = await SuperPlayerPlugin.createVodPlayer(onlyAudio: onlyAudio);
_vodPlayerApi = TXFlutterVodPlayerApi(messageChannelSuffix: _playerId.toString()); _vodPlayerApi =
TXVodPlayerFlutterAPI.setUp(this, messageChannelSuffix: _playerId.toString()); TXFlutterVodPlayerApi(messageChannelSuffix: _playerId.toString());
TXVodPlayerFlutterAPI.setUp(this,
messageChannelSuffix: _playerId.toString());
_initPlayer.complete(_playerId); _initPlayer.complete(_playerId);
} }
...@@ -74,8 +84,10 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -74,8 +84,10 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
void printVersionInfo() async { void printVersionInfo() async {
LogUtils.d(kTag, "dart SDK version:${Platform.version}"); LogUtils.d(kTag, "dart SDK version:${Platform.version}");
LogUtils.d(kTag, "liteAV SDK version:${await SuperPlayerPlugin.platformVersion}"); LogUtils.d(
LogUtils.d(kTag, "superPlayer SDK version:${FPlayerPckInfo.PLAYER_VERSION}"); kTag, "liteAV SDK version:${await SuperPlayerPlugin.platformVersion}");
LogUtils.d(
kTag, "superPlayer SDK version:${FPlayerPckInfo.PLAYER_VERSION}");
} }
/// Starting from version 10.7, the method `startPlay` has been changed to `startVodPlay` for playing videos via a URL. /// Starting from version 10.7, the method `startPlay` has been changed to `startVodPlay` for playing videos via a URL.
...@@ -188,7 +200,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -188,7 +200,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
Future<bool> isPlaying() async { Future<bool> isPlaying() async {
if (_isNeedDisposed) return false; if (_isNeedDisposed) return false;
await _initPlayer.future; await _initPlayer.future;
BoolMsg boolMsg = await _vodPlayerApi.isPlaying(PlayerMsg()..playerId = _playerId); BoolMsg boolMsg =
await _vodPlayerApi.isPlaying(PlayerMsg()..playerId = _playerId);
return boolMsg.value ?? false; return boolMsg.value ?? false;
} }
...@@ -292,7 +305,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -292,7 +305,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
Future<List?> getSupportedBitrates() async { Future<List?> getSupportedBitrates() async {
if (_isNeedDisposed) return []; if (_isNeedDisposed) return [];
await _initPlayer.future; await _initPlayer.future;
ListMsg listMsg = await _vodPlayerApi.getSupportedBitrate(PlayerMsg()..playerId = _playerId); ListMsg listMsg = await _vodPlayerApi
.getSupportedBitrate(PlayerMsg()..playerId = _playerId);
return listMsg.value; return listMsg.value;
} }
...@@ -302,7 +316,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -302,7 +316,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
Future<int> getBitrateIndex() async { Future<int> getBitrateIndex() async {
if (_isNeedDisposed) return -1; if (_isNeedDisposed) return -1;
await _initPlayer.future; await _initPlayer.future;
IntMsg intMsg = await _vodPlayerApi.getBitrateIndex(PlayerMsg()..playerId = _playerId); IntMsg intMsg =
await _vodPlayerApi.getBitrateIndex(PlayerMsg()..playerId = _playerId);
return intMsg.value ?? -1; return intMsg.value ?? -1;
} }
...@@ -375,7 +390,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -375,7 +390,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
Future<double> getCurrentPlaybackTime() async { Future<double> getCurrentPlaybackTime() async {
if (_isNeedDisposed) return 0; if (_isNeedDisposed) return 0;
await _initPlayer.future; await _initPlayer.future;
DoubleMsg doubleMsg = await _vodPlayerApi.getCurrentPlaybackTime(PlayerMsg()..playerId = _playerId); DoubleMsg doubleMsg = await _vodPlayerApi
.getCurrentPlaybackTime(PlayerMsg()..playerId = _playerId);
return doubleMsg.value ?? 0; return doubleMsg.value ?? 0;
} }
...@@ -385,7 +401,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -385,7 +401,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
Future<double> getBufferDuration() async { Future<double> getBufferDuration() async {
if (_isNeedDisposed) return 0; if (_isNeedDisposed) return 0;
await _initPlayer.future; await _initPlayer.future;
DoubleMsg doubleMsg = await _vodPlayerApi.getBufferDuration(PlayerMsg()..playerId = _playerId); DoubleMsg doubleMsg = await _vodPlayerApi
.getBufferDuration(PlayerMsg()..playerId = _playerId);
return doubleMsg.value ?? 0; return doubleMsg.value ?? 0;
} }
...@@ -395,7 +412,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -395,7 +412,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
Future<double> getPlayableDuration() async { Future<double> getPlayableDuration() async {
if (_isNeedDisposed) return 0; if (_isNeedDisposed) return 0;
await _initPlayer.future; await _initPlayer.future;
DoubleMsg doubleMsg = await _vodPlayerApi.getPlayableDuration(PlayerMsg()..playerId = _playerId); DoubleMsg doubleMsg = await _vodPlayerApi
.getPlayableDuration(PlayerMsg()..playerId = _playerId);
return doubleMsg.value ?? 0; return doubleMsg.value ?? 0;
} }
...@@ -405,7 +423,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -405,7 +423,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
Future<int> getWidth() async { Future<int> getWidth() async {
if (_isNeedDisposed) return 0; if (_isNeedDisposed) return 0;
await _initPlayer.future; await _initPlayer.future;
IntMsg intMsg = await _vodPlayerApi.getWidth(PlayerMsg()..playerId = _playerId); IntMsg intMsg =
await _vodPlayerApi.getWidth(PlayerMsg()..playerId = _playerId);
return intMsg.value ?? 0; return intMsg.value ?? 0;
} }
...@@ -415,7 +434,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -415,7 +434,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
Future<int> getHeight() async { Future<int> getHeight() async {
if (_isNeedDisposed) return 0; if (_isNeedDisposed) return 0;
await _initPlayer.future; await _initPlayer.future;
IntMsg intMsg = await _vodPlayerApi.getHeight(PlayerMsg()..playerId = _playerId); IntMsg intMsg =
await _vodPlayerApi.getHeight(PlayerMsg()..playerId = _playerId);
return intMsg.value ?? 0; return intMsg.value ?? 0;
} }
...@@ -436,7 +456,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -436,7 +456,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
Future<bool> isLoop() async { Future<bool> isLoop() async {
if (_isNeedDisposed) return false; if (_isNeedDisposed) return false;
await _initPlayer.future; await _initPlayer.future;
BoolMsg boolMsg = await _vodPlayerApi.isLoop(PlayerMsg()..playerId = _playerId); BoolMsg boolMsg =
await _vodPlayerApi.isLoop(PlayerMsg()..playerId = _playerId);
return boolMsg.value ?? false; return boolMsg.value ?? false;
} }
...@@ -470,10 +491,14 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -470,10 +491,14 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
/// 使用系统默认图标,只支持flutter本地资源图片,传递的时候,与flutter使用图片资源一致,例如: images/back_icon.png /// 使用系统默认图标,只支持flutter本地资源图片,传递的时候,与flutter使用图片资源一致,例如: images/back_icon.png
@override @override
Future<int> enterPictureInPictureMode( Future<int> enterPictureInPictureMode(
{String? backIconForAndroid, String? playIconForAndroid, String? pauseIconForAndroid, String? forwardIconForAndroid}) async { {String? backIconForAndroid,
String? playIconForAndroid,
String? pauseIconForAndroid,
String? forwardIconForAndroid}) async {
if (_isNeedDisposed) return -1; if (_isNeedDisposed) return -1;
await _initPlayer.future; await _initPlayer.future;
IntMsg intMsg = await _vodPlayerApi.enterPictureInPictureMode(PipParamsPlayerMsg() IntMsg intMsg =
await _vodPlayerApi.enterPictureInPictureMode(PipParamsPlayerMsg()
..backIconForAndroid = backIconForAndroid ..backIconForAndroid = backIconForAndroid
..playIconForAndroid = playIconForAndroid ..playIconForAndroid = playIconForAndroid
..pauseIconForAndroid = pauseIconForAndroid ..pauseIconForAndroid = pauseIconForAndroid
...@@ -493,7 +518,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -493,7 +518,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
Future<Uint8List?> getImageSprite(double time) async { Future<Uint8List?> getImageSprite(double time) async {
await _initPlayer.future; await _initPlayer.future;
UInt8ListMsg int8listMsg = await _vodPlayerApi.getImageSprite(DoublePlayerMsg() UInt8ListMsg int8listMsg =
await _vodPlayerApi.getImageSprite(DoublePlayerMsg()
..value = time ..value = time
..playerId = _playerId); ..playerId = _playerId);
return int8listMsg.value; return int8listMsg.value;
...@@ -505,7 +531,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -505,7 +531,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
Future<double> getDuration() async { Future<double> getDuration() async {
if (_isNeedDisposed) return 0; if (_isNeedDisposed) return 0;
await _initPlayer.future; await _initPlayer.future;
DoubleMsg doubleMsg = await _vodPlayerApi.getDuration(PlayerMsg()..playerId = _playerId); DoubleMsg doubleMsg =
await _vodPlayerApi.getDuration(PlayerMsg()..playerId = _playerId);
return doubleMsg.value ?? 0; return doubleMsg.value ?? 0;
} }
...@@ -516,7 +543,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -516,7 +543,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
Future<void> exitPictureInPictureMode() async { Future<void> exitPictureInPictureMode() async {
if (_isNeedDisposed) return; if (_isNeedDisposed) return;
await _initPlayer.future; await _initPlayer.future;
await _vodPlayerApi.exitPictureInPictureMode(PlayerMsg()..playerId = _playerId); await _vodPlayerApi
.exitPictureInPictureMode(PlayerMsg()..playerId = _playerId);
} }
/// This interface is only supported by the premium version of the player (Player_Premium), /// This interface is only supported by the premium version of the player (Player_Premium),
...@@ -533,10 +561,13 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -533,10 +561,13 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
/// @param name 字幕的名字。如果添加多个字幕,字幕名称请设置为不同的名字,用于区分与其他添加的字幕,否则可能会导致字幕选择错误。 /// @param name 字幕的名字。如果添加多个字幕,字幕名称请设置为不同的名字,用于区分与其他添加的字幕,否则可能会导致字幕选择错误。
/// @param mimeType 字幕类型,仅支持VVT和SRT格式 [VOD_PLAY_MIMETYPE_TEXT_SRT] [VOD_PLAY_MIMETYPE_TEXT_VTT] /// @param mimeType 字幕类型,仅支持VVT和SRT格式 [VOD_PLAY_MIMETYPE_TEXT_SRT] [VOD_PLAY_MIMETYPE_TEXT_VTT]
/// 后面可以通过[getSubtitleTrackInfo]返回结果中的 name 获取对应的名字 /// 后面可以通过[getSubtitleTrackInfo]返回结果中的 name 获取对应的名字
Future<void> addSubtitleSource(String url, String name, {String? mimeType}) async { Future<void> addSubtitleSource(String url, String name,
{String? mimeType}) async {
if (_isNeedDisposed) return; if (_isNeedDisposed) return;
await _initPlayer.future; await _initPlayer.future;
await _vodPlayerApi.addSubtitleSource(SubTitlePlayerMsg(url: url, name: name, mimeType: mimeType)..playerId = _playerId); await _vodPlayerApi.addSubtitleSource(
SubTitlePlayerMsg(url: url, name: name, mimeType: mimeType)
..playerId = _playerId);
} }
/// This interface is only supported by the premium version of the player (Player_Premium), /// This interface is only supported by the premium version of the player (Player_Premium),
...@@ -548,12 +579,14 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -548,12 +579,14 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
Future<List<TXTrackInfo>> getSubtitleTrackInfo() async { Future<List<TXTrackInfo>> getSubtitleTrackInfo() async {
if (_isNeedDisposed) return []; if (_isNeedDisposed) return [];
await _initPlayer.future; await _initPlayer.future;
ListMsg listMsg = await _vodPlayerApi.getSubtitleTrackInfo(PlayerMsg(playerId: _playerId)); ListMsg listMsg = await _vodPlayerApi
.getSubtitleTrackInfo(PlayerMsg(playerId: _playerId));
if (null != listMsg.value) { if (null != listMsg.value) {
List<dynamic>? transInfoData = listMsg.value!; List<dynamic>? transInfoData = listMsg.value!;
List<TXTrackInfo> trackInfoList = []; List<TXTrackInfo> trackInfoList = [];
for (Map<dynamic, dynamic> map in transInfoData) { for (Map<dynamic, dynamic> map in transInfoData) {
TXTrackInfo trackInfo = TXTrackInfo(map["name"], map["trackIndex"], map["trackType"]); TXTrackInfo trackInfo =
TXTrackInfo(map["name"], map["trackIndex"], map["trackType"]);
trackInfo.isSelected = map["isSelected"] ?? false; trackInfo.isSelected = map["isSelected"] ?? false;
trackInfo.isExclusive = map["isExclusive"] ?? true; trackInfo.isExclusive = map["isExclusive"] ?? true;
trackInfo.isInternal = map["isInternal"] ?? true; trackInfo.isInternal = map["isInternal"] ?? true;
...@@ -573,12 +606,14 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -573,12 +606,14 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
Future<List<TXTrackInfo>> getAudioTrackInfo() async { Future<List<TXTrackInfo>> getAudioTrackInfo() async {
if (_isNeedDisposed) return []; if (_isNeedDisposed) return [];
await _initPlayer.future; await _initPlayer.future;
ListMsg listMsg = await _vodPlayerApi.getAudioTrackInfo(PlayerMsg(playerId: _playerId)); ListMsg listMsg =
await _vodPlayerApi.getAudioTrackInfo(PlayerMsg(playerId: _playerId));
if (null != listMsg.value) { if (null != listMsg.value) {
List<dynamic>? transInfoData = listMsg.value!; List<dynamic>? transInfoData = listMsg.value!;
List<TXTrackInfo> trackInfoList = []; List<TXTrackInfo> trackInfoList = [];
for (Map<dynamic, dynamic> map in transInfoData) { for (Map<dynamic, dynamic> map in transInfoData) {
TXTrackInfo trackInfo = TXTrackInfo(map["name"], map["trackIndex"], map["trackType"]); TXTrackInfo trackInfo =
TXTrackInfo(map["name"], map["trackIndex"], map["trackType"]);
trackInfo.isSelected = map["isSelected"] ?? false; trackInfo.isSelected = map["isSelected"] ?? false;
trackInfo.isExclusive = map["isExclusive"] ?? true; trackInfo.isExclusive = map["isExclusive"] ?? true;
trackInfo.isInternal = map["isInternal"] ?? true; trackInfo.isInternal = map["isInternal"] ?? true;
...@@ -630,7 +665,7 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -630,7 +665,7 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
..value = [value]); ..value = [value]);
} }
Future<void>setPlayerView(int renderViewId) async{ Future<void> setPlayerView(int renderViewId) async {
if (_isNeedDisposed) return; if (_isNeedDisposed) return;
await _initPlayer.future; await _initPlayer.future;
await _vodPlayerApi.setPlayerView(renderViewId); await _vodPlayerApi.setPlayerView(renderViewId);
...@@ -652,6 +687,30 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -652,6 +687,30 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
await _vodPlayerApi.reDraw(); await _vodPlayerApi.reDraw();
} }
///
/// only valid on Android
///
Future<String?> snapshot({
required String saveDirPath,
// 1: jpg other: png
int format = 1,
double quality = 1.0,
}) async {
final path =
'$saveDirPath/${DateTime.now().millisecondsSinceEpoch.toString()}';
final res = await _vodPlayerApi.snapshot(
snapshotSavePath: path,
format: 1,
quality: quality,
);
if (res.success != null && res.success == true) {
return path;
} else {
debugPrint('------> ${res.reason ?? '截图是吧'}');
return null;
}
}
/// release controller /// release controller
/// ///
/// 释放controller /// 释放controller
...@@ -707,13 +766,15 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -707,13 +766,15 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
case TXVodPlayEvent.PLAY_EVT_PLAY_LOADING: case TXVodPlayEvent.PLAY_EVT_PLAY_LOADING:
_changeState(TXPlayerState.buffering); _changeState(TXPlayerState.buffering);
break; break;
case TXVodPlayEvent.PLAY_EVT_CHANGE_RESOLUTION: // Downstream video resolution change. case TXVodPlayEvent
.PLAY_EVT_CHANGE_RESOLUTION: // Downstream video resolution change.
if (defaultTargetPlatform == TargetPlatform.android) { if (defaultTargetPlatform == TargetPlatform.android) {
int? videoWidth = event[TXVodPlayEvent.EVT_VIDEO_WIDTH]; int? videoWidth = event[TXVodPlayEvent.EVT_VIDEO_WIDTH];
int? videoHeight = event[TXVodPlayEvent.EVT_VIDEO_HEIGHT]; int? videoHeight = event[TXVodPlayEvent.EVT_VIDEO_HEIGHT];
videoWidth ??= event[TXVodPlayEvent.EVT_PARAM1]; videoWidth ??= event[TXVodPlayEvent.EVT_PARAM1];
videoHeight ??= event[TXVodPlayEvent.EVT_PARAM2]; videoHeight ??= event[TXVodPlayEvent.EVT_PARAM2];
if ((videoWidth != null && videoWidth > 0) && (videoHeight != null && videoHeight > 0)) { if ((videoWidth != null && videoWidth > 0) &&
(videoHeight != null && videoHeight > 0)) {
resizeVideoWidth = videoWidth.toDouble(); resizeVideoWidth = videoWidth.toDouble();
resizeVideoHeight = videoHeight.toDouble(); resizeVideoHeight = videoHeight.toDouble();
videoLeft = event["videoLeft"] ?? 0; videoLeft = event["videoLeft"] ?? 0;
...@@ -752,7 +813,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX ...@@ -752,7 +813,8 @@ class TXVodPlayerController extends ChangeNotifier implements ValueListenable<TX
case TXVodPlayEvent.EVENT_SUBTITLE_DATA: case TXVodPlayEvent.EVENT_SUBTITLE_DATA:
String subtitleDataStr = map[TXVodPlayEvent.EXTRA_SUBTITLE_DATA] ?? ""; String subtitleDataStr = map[TXVodPlayEvent.EXTRA_SUBTITLE_DATA] ?? "";
if (subtitleDataStr != "") { if (subtitleDataStr != "") {
map[TXVodPlayEvent.EXTRA_SUBTITLE_DATA] = subtitleDataStr.trim().replaceAll('\\N', '\n'); map[TXVodPlayEvent.EXTRA_SUBTITLE_DATA] =
subtitleDataStr.trim().replaceAll('\\N', '\n');
} }
break; break;
default: default:
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论