赞
踩
Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。 Flutter可以与现有的代码一起工作。在全世界,Flutter正在被越来越多的开发者和组织使用,并且Flutter是完全免费、开源的。
1. Beautiful - Flutter 允许你控制屏幕上的每一寸像素,这让「设计」不用再对「实现」妥协;
2. Fast - 一个应用不卡顿的标准是什么,你可能会说 16ms 抑或是 60fps,这对桌面端应用或者移动端应用来说已足够,但当面对广阔的 AR/VR 领域,60fps 仍然会成为使人脑产生眩晕的瓶颈,而 Flutter 的目标远不止 60fps;借助 Dart 支持的 AOT 编译以及 Skia 的绘制,Flutter 可以运行的很快;
3. Productive - 前端开发可能已经习惯的开发中 hot reload 模式,但这一特性在移动开发中还算是个新鲜事。Flutter 提供有状态的 hot reload 开发模式,并允许一套 codebase 运行于多端;其他的,再比如开发采用 JIT 编译与发布的 AOT 编译,都使得开发者在开发应用时可以更加高效;
4. Open - Dart / Skia / Flutter (Framework),这些都是开源的,Flutter 与 Dart 团队也对包括 Web 在内的多种技术持开放态度,只要是优秀的他们都愿意借鉴吸收。而在生态建设上,Flutter 回应 GitHub Issue 的速度更是让人惊叹,因为是真的快(closed 状态的 issue 平均解决时间为 0.29天);
首先,Flutter则是依靠Flutter Engine虚拟机在iOS和Android上运行,开发人员可以通过Flutter框架和API在内部进行交互。Flutter Engine使用C/C++编写,具有低延迟输入和高帧速率的特点,不像Unity3d一样,我们是回调YUV/RGB数据,在Unity3d里面绘制,Flutter直接调用native SDK,效率更高。
其次,客户和开发者驱动,Flutter发展至今,目前还没有个像样的RTSP或RTMP播放器,一个播放器,不是说,有个界面,有个开始、停止按钮就可以了,一个好用的直播播放器,对功能和性能属性要求很高,特别是稳定性和低延迟这块,不谦虚的说,可能是首款功能强大、真正好用的Flutter RTSP/RTMP直播播放SDK。
Android和iOS手机上RTSP/RTMP播放效果:
1. 视频播放效果:
http://www.iqiyi.com/w_19s8dv6yht.html
2. 界面截图:
- //
- // smartplayer.dart
- // smartplayer
- //
- // GitHub: https://github.com/daniulive/SmarterStreaming
- // website: https://www.daniulive.com
- //
- // Created by daniulive on 2019/02/25.
- // Copyright © 2014~2019 daniulive. All rights reserved.
- //
-
- import 'dart:async';
- import 'dart:convert';
-
- import 'package:flutter/services.dart';
-
- class EVENTID {
- static const EVENT_DANIULIVE_COMMON_SDK = 0x00000000;
- static const EVENT_DANIULIVE_PLAYER_SDK = 0x01000000;
- static const EVENT_DANIULIVE_PUBLISHER_SDK = 0x02000000;
-
- static const EVENT_DANIULIVE_ERC_PLAYER_STARTED =
- EVENT_DANIULIVE_PLAYER_SDK | 0x1;
- static const EVENT_DANIULIVE_ERC_PLAYER_CONNECTING =
- EVENT_DANIULIVE_PLAYER_SDK | 0x2;
- static const EVENT_DANIULIVE_ERC_PLAYER_CONNECTION_FAILED =
- EVENT_DANIULIVE_PLAYER_SDK | 0x3;
- static const EVENT_DANIULIVE_ERC_PLAYER_CONNECTED =
- EVENT_DANIULIVE_PLAYER_SDK | 0x4;
- static const EVENT_DANIULIVE_ERC_PLAYER_DISCONNECTED =
- EVENT_DANIULIVE_PLAYER_SDK | 0x5;
- static const EVENT_DANIULIVE_ERC_PLAYER_STOP =
- EVENT_DANIULIVE_PLAYER_SDK | 0x6;
- static const EVENT_DANIULIVE_ERC_PLAYER_RESOLUTION_INFO =
- EVENT_DANIULIVE_PLAYER_SDK | 0x7;
- static const EVENT_DANIULIVE_ERC_PLAYER_NO_MEDIADATA_RECEIVED =
- EVENT_DANIULIVE_PLAYER_SDK | 0x8;
- static const EVENT_DANIULIVE_ERC_PLAYER_SWITCH_URL =
- EVENT_DANIULIVE_PLAYER_SDK | 0x9;
- static const EVENT_DANIULIVE_ERC_PLAYER_CAPTURE_IMAGE =
- EVENT_DANIULIVE_PLAYER_SDK | 0xA;
-
- static const EVENT_DANIULIVE_ERC_PLAYER_RECORDER_START_NEW_FILE =
- EVENT_DANIULIVE_PLAYER_SDK | 0x21; /*录像写入新文件*/
- static const EVENT_DANIULIVE_ERC_PLAYER_ONE_RECORDER_FILE_FINISHED =
- EVENT_DANIULIVE_PLAYER_SDK | 0x22; /*一个录像文件完成*/
-
- static const EVENT_DANIULIVE_ERC_PLAYER_START_BUFFERING =
- EVENT_DANIULIVE_PLAYER_SDK | 0x81;
- static const EVENT_DANIULIVE_ERC_PLAYER_BUFFERING =
- EVENT_DANIULIVE_PLAYER_SDK | 0x82;
- static const EVENT_DANIULIVE_ERC_PLAYER_STOP_BUFFERING =
- EVENT_DANIULIVE_PLAYER_SDK | 0x83;
-
- static const EVENT_DANIULIVE_ERC_PLAYER_DOWNLOAD_SPEED =
- EVENT_DANIULIVE_PLAYER_SDK | 0x91;
- }
-
- typedef SmartEventCallback = void Function(int, String, String, String);
-
- class SmartPlayerController {
- MethodChannel _channel;
- EventChannel _eventChannel;
- SmartEventCallback _eventCallback;
-
- void init(int id) {
- _channel = MethodChannel('smartplayer_plugin_$id');
- _eventChannel = EventChannel('smartplayer_event_$id');
- _eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);
- }
-
- void setEventCallback(SmartEventCallback callback) {
- _eventCallback = callback;
- }
-
- void _onEvent(Object event) {
- if (event != null) {
- Map valueMap = json.decode(event);
- String param = valueMap['param'];
- onSmartEvent(param);
- }
- }
-
- void _onError(Object error) {
- // print('error:'+ error);
- }
-
- Future<dynamic> _smartPlayerCall(String funcName) async {
- var ret = await _channel.invokeMethod(funcName);
- return ret;
- }
-
- Future<dynamic> _smartPlayerCallInt(String funcName, int param) async {
- var ret = await _channel.invokeMethod(funcName, {
- 'intParam': param,
- });
- return ret;
- }
-
- Future<dynamic> _smartPlayerCallIntInt(
- String funcName, int param1, int param2) async {
- var ret = await _channel.invokeMethod(funcName, {
- 'intParam': param1,
- 'intParam2': param2,
- });
- return ret;
- }
-
- Future<dynamic> _smartPlayerCallString(String funcName, String param) async {
- var ret = await _channel.invokeMethod(funcName, {
- 'strParam': param,
- });
- return ret;
- }
-
- /// 设置解码方式 false 软解码 true 硬解码 默认为false
- /// </summary>
- /// <param name="isHwDecoder"></param>
- Future<dynamic> setVideoDecoderMode(int isHwDecoder) async {
- return _smartPlayerCallInt('setVideoDecoderMode', isHwDecoder);
- }
-
- /// <summary>
- /// 设置音频输出模式: if 0: 自动选择; if with 1: audiotrack模式, 此接口仅限于Android平台使用
- /// </summary>
- /// <param name="use_audiotrack"></param>
- Future<dynamic> setAudioOutputType(int useAudiotrack) async {
- return _smartPlayerCallInt('setAudioOutputType', useAudiotrack);
- }
-
- /// <summary>
- /// 设置播放端缓存大小, 默认200毫秒
- /// </summary>
- /// <param name="buffer"></param>
- Future<dynamic> setBuffer(int buffer) async {
- return _smartPlayerCallInt('setBuffer', buffer);
- }
-
- /// <summary>
- /// 接口可实时调用:设置是否实时静音,1:静音; 0: 取消静音
- /// </summary>
- /// <param name="is_mute"></param>
- Future<dynamic> setMute(int isMute) async {
- return _smartPlayerCallInt('setMute', isMute);
- }
-
- /// <summary>
- /// 设置RTSP TCP模式, 1: TCP; 0: UDP
- /// </summary>
- /// <param name="is_using_tcp"></param>
- Future<dynamic> setRTSPTcpMode(int isUsingTcp) async {
- return _smartPlayerCallInt('setRTSPTcpMode', isUsingTcp);
- }
-
- /// <summary>
- /// 设置RTSP超时时间, timeout单位为秒,必须大于0
- /// </summary>
- /// <param name="timeout"></param>
- Future<dynamic> setRTSPTimeout(int timeout) async {
- return _smartPlayerCallInt('setRTSPTimeout', timeout);
- }
-
- /// <summary>
- /// 设置RTSP TCP/UDP自动切换
- /// 对于RTSP来说,有些可能支持rtp over udp方式,有些可能支持使用rtp over tcp方式.
- /// 为了方便使用,有些场景下可以开启自动尝试切换开关, 打开后如果udp无法播放,sdk会自动尝试tcp, 如果tcp方式播放不了,sdk会自动尝试udp.
- /// </summary>
- /// <param name="is_auto_switch_tcp_udp"></param>
- Future<dynamic> setRTSPAutoSwitchTcpUdp(int is_auto_switch_tcp_udp) async {
- return _smartPlayerCallInt('setRTSPAutoSwitchTcpUdp', is_auto_switch_tcp_udp);
- }
-
- /// <summary>
- /// 设置快速启动该模式,
- /// </summary>
- /// <param name="is_fast_startup"></param>
- Future<dynamic> setFastStartup(int isFastStartup) async {
- return _smartPlayerCallInt('setFastStartup', isFastStartup);
- }
-
- /// <summary>
- /// 设置超低延迟模式 false不开启 true开启 默认false
- /// </summary>
- /// <param name="mode"></param>
- Future<dynamic> setPlayerLowLatencyMode(int mode) async {
- return _smartPlayerCallInt('setPlayerLowLatencyMode', mode);
- }
-
- /// <summary>
- /// 设置视频垂直反转
- /// </summary>
- /// <param name="is_flip"></param>
- Future<dynamic> setFlipVertical(int is_flip) async {
- return _smartPlayerCallInt('setFlipVertical', is_flip);
- }
-
- /// <summary>
- /// 设置视频水平反转
- /// </summary>
- /// <param name="is_flip"></param>
- Future<dynamic> setFlipHorizontal(int is_flip) async {
- return _smartPlayerCallInt('setFlipHorizontal', is_flip);
- }
-
- /// <summary>
- /// 设置顺时针旋转, 注意除了0度之外, 其他角度都会额外消耗性能
- /// degress: 当前支持 0度,90度, 180度, 270度 旋转
- /// </summary>
- /// <param name="degress"></param>
- Future<dynamic> setRotation(int degress) async {
- return _smartPlayerCallInt('setRotation', degress);
- }
-
- /// <summary>
- /// 设置是否回调下载速度
- /// is_report: if 1: 上报下载速度, 0: 不上报.
- /// report_interval: 上报间隔,以秒为单位,>0.
- /// </summary>
- /// <param name="is_report"></param>
- /// <param name="report_interval"></param>
- Future<dynamic> setReportDownloadSpeed(
- int isReport, int reportInterval) async {
- return _smartPlayerCallIntInt(
- 'setReportDownloadSpeed', isReport, reportInterval);
- }
-
- /// <summary>
- /// Set playback orientation(设置播放方向),此接口仅适用于Android平台
- /// </summary>
- /// <param name="surOrg"></param>
- /// surOrg: current orientation, PORTRAIT 1, LANDSCAPE with 2
- Future<dynamic> setOrientation(int surOrg) async {
- return _smartPlayerCallInt('setOrientation', surOrg);
- }
-
- /// <summary>
- /// 设置是否需要在播放或录像过程中快照
- /// </summary>
- /// <param name="is_save_image"></param>
- Future<dynamic> setSaveImageFlag(int isSaveImage) async {
- return _smartPlayerCallInt('setSaveImageFlag', isSaveImage);
- }
-
- /// <summary>
- /// 播放或录像过程中快照
- /// </summary>
- /// <param name="imageName"></param>
- Future<dynamic> saveCurImage(String imageName) async {
- return _smartPlayerCallString('saveCurImage', imageName);
- }
-
- /// <summary>
- /// 播放或录像过程中,快速切换url
- /// </summary>
- /// <param name="uri"></param>
- Future<dynamic> switchPlaybackUrl(String uri) async {
- return _smartPlayerCallString('switchPlaybackUrl', uri);
- }
-
- /// <summary>
- /// 创建录像存储路径
- /// </summary>
- /// <param name="path"></param>
- Future<dynamic> createFileDirectory(String path) async {
- return _smartPlayerCallString('createFileDirectory', path);
- }
-
- /// <summary>
- /// 设置录像存储路径
- /// </summary>
- /// <param name="path"></param>
- Future<dynamic> setRecorderDirectory(String path) async {
- return _smartPlayerCallString('setRecorderDirectory', path);
- }
-
- /// <summary>
- /// 设置单个录像文件大小
- /// </summary>
- /// <param name="size"></param>
- Future<dynamic> setRecorderFileMaxSize(int size) async {
- return _smartPlayerCallInt('setRecorderFileMaxSize', size);
- }
-
- /// <summary>
- /// 设置录像时音频转AAC编码的开关
- /// aac比较通用,sdk增加其他音频编码(比如speex, pcmu, pcma等)转aac的功能.
- /// </summary>
- /// <param name="is_transcode"></param>
- /// is_transcode: 设置为1的话,如果音频编码不是aac,则转成aac,如果是aac,则不做转换. 设置为0的话,则不做任何转换. 默认是0.
- Future<dynamic> setRecorderAudioTranscodeAAC(int is_transcode) async {
- return _smartPlayerCallInt('setRecorderAudioTranscodeAAC', is_transcode);
- }
-
- /// <summary>
- /// 设置播放路径
- /// </summary>
- Future<dynamic> setUrl(String url) async {
- return _smartPlayerCallString('setUrl', url);
- }
-
- /// <summary>
- /// 开始播放
- /// </summary>
- Future<dynamic> startPlay() async {
- return _smartPlayerCall('startPlay');
- }
-
- /// <summary>
- /// 停止播放
- /// </summary>
- Future<dynamic> stopPlay() async {
- return _smartPlayerCall('stopPlay');
- }
-
- /// <summary>
- /// 开始录像
- /// </summary>
- Future<dynamic> startRecorder() async {
- return _smartPlayerCall('startRecorder');
- }
-
- /// <summary>
- /// 停止录像
- /// </summary>
- Future<dynamic> stopRecorder() async {
- return _smartPlayerCall('stopRecorder');
- }
-
- /// <summary>
- /// 关闭播放
- /// </summary>
- Future<dynamic> dispose() async {
- return await _channel.invokeMethod('dispose');
- }
-
- void onSmartEvent(String param) {
- if (!param.contains(",")) {
- print("[onNTSmartEvent] android传递参数错误");
- return;
- }
-
- List<String> strs = param.split(',');
-
- String code = strs[1];
- String param1 = strs[2];
- String param2 = strs[3];
- String param3 = strs[4];
- String param4 = strs[5];
-
- int evCode = int.parse(code);
-
- var p1, p2, p3;
- switch (evCode) {
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_STARTED:
- print("开始。。");
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTING:
- print("连接中。。");
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTION_FAILED:
- print("连接失败。。");
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTED:
- print("连接成功。。");
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_DISCONNECTED:
- print("连接断开。。");
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_STOP:
- print("停止播放。。");
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_RESOLUTION_INFO:
- print("分辨率信息: width: " + param1 + ", height: " + param2);
- p1 = param1;
- p2 = param2;
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_NO_MEDIADATA_RECEIVED:
- print("收不到媒体数据,可能是url错误。。");
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_SWITCH_URL:
- print("切换播放URL。。");
- break;
-
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CAPTURE_IMAGE:
- print("快照: " + param1 + " 路径:" + param3);
-
- if (int.parse(param1) == 0) {
- print("截取快照成功。.");
- } else {
- print("截取快照失败。.");
- }
- p1 = param1;
- p2 = param3;
- break;
-
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_RECORDER_START_NEW_FILE:
- print("[record]开始一个新的录像文件 : " + param3);
- p3 = param3;
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_ONE_RECORDER_FILE_FINISHED:
- print("[record]已生成一个录像文件 : " + param3);
- p3 = param3;
- break;
-
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_START_BUFFERING:
- print("Start_Buffering");
- break;
-
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_BUFFERING:
- print("Buffering: " + param1 + "%");
- p1 = param1;
- break;
-
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_STOP_BUFFERING:
- print("Stop_Buffering");
- break;
-
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_DOWNLOAD_SPEED:
- print("download_speed:" + (double.parse(param1) * 8 / 1000).toStringAsFixed(0) + "kbps" + ", " + (double.parse(param1) / 1024).toStringAsFixed(0) + "KB/s");
- p1 = param1;
- break;
- }
- if (_eventCallback != null) {
- _eventCallback(evCode, p1, p2, p3);
- }
- }
- }
- //
- // main.dart
- // main
- //
- // GitHub: https://github.com/daniulive/SmarterStreaming
- // website: https://www.daniulive.com
- //
- // Created by daniulive on 2019/02/25.
- // Copyright © 2014~2019 daniulive. All rights reserved.
- //
-
- import 'dart:io';
- import 'package:flutter/services.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter/cupertino.dart';
- import 'package:flutter/foundation.dart';
- import 'package:smartplayer_native_view/smartplayer.dart';
- import 'package:smartplayer_native_view/smartplayer_plugin.dart';
-
- void main() {
- ///
- /// 强制竖屏
- ///
- SystemChrome.setPreferredOrientations(
- [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
-
- runApp(new MyApp());
- }
-
- class MyApp extends StatefulWidget {
- @override
- _MyAppState createState() => new _MyAppState();
- }
-
- class _MyAppState extends State<MyApp> {
- SmartPlayerController player;
- double aspectRatio = 4.0 / 3.0;
-
- //输入需要播放的RTMP/RTSP url
- TextEditingController playback_url_controller_ = TextEditingController();
-
- //Event事件回调显示
- TextEditingController event_controller_ = TextEditingController();
-
- bool is_playing_ = false;
- bool is_mute_ = false;
-
- var rotate_degrees_ = 0;
-
- Widget smartPlayerView() {
- return SmartPlayerWidget(
- onSmartPlayerCreated: onSmartPlayerCreated,
- );
- }
-
- @override
- void initState() {
- print("initState called..");
- super.initState();
- }
-
- @override
- void didChangeDependencies() {
- print('didChangeDependencies called..');
- super.didChangeDependencies();
- }
-
- @override
- void deactivate() {
- print('deactivate called..');
- super.deactivate();
- }
-
- @override
- void dispose() {
- print("dispose called..");
- player.dispose();
- super.dispose();
- }
-
- @override
- Widget build(BuildContext context) {
- return MaterialApp(
- home: Scaffold(
- appBar: AppBar(
- title: const Text('Flutter SmartPlayer Demo'),
- ),
- body: new SingleChildScrollView(
- child: new Column(
- children: <Widget>[
- new Container(
- color: Colors.black,
- child: AspectRatio(
- child: smartPlayerView(),
- aspectRatio: aspectRatio,
- ),
- ),
- new TextField(
- controller: playback_url_controller_,
- keyboardType: TextInputType.text,
- decoration: InputDecoration(
- contentPadding: EdgeInsets.all(10.0),
- icon: Icon(Icons.link),
- labelText: '请输入RTSP/RTMP url',
- ),
- autofocus: false,
- ),
- new Row(
- children: [
- new RaisedButton(
- onPressed: this.onSmartPlayerStartPlay,
- child: new Text("开始播放")),
- new Container(width: 20),
- new RaisedButton(
- onPressed: this.onSmartPlayerStopPlay,
- child: new Text("停止播放")),
- new Container(width: 20),
- new RaisedButton(
- onPressed: this.onSmartPlayerMute,
- child: new Text("实时静音")),
- ],
- ),
- new Row(
- children: [
- new RaisedButton(
- onPressed: this.onSmartPlayerSwitchUrl,
- child: new Text("实时切换URL")),
- new Container(width: 20),
- new RaisedButton(
- onPressed: this.onSmartPlayerSetRotation,
- child: new Text("实时旋转View")),
- ],
- ),
- new TextField(
- controller: event_controller_,
- keyboardType: TextInputType.text,
- decoration: InputDecoration(
- contentPadding: EdgeInsets.all(10.0),
- icon: Icon(Icons.event_note),
- labelText: 'Event状态回调',
- ),
- autofocus: false,
- ),
- ],
- ),
- )),
- );
- }
-
- void _eventCallback(int code, String param1, String param2, String param3) {
- String event_str;
-
- switch (code) {
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_STARTED:
- event_str = "开始..";
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTING:
- event_str = "连接中..";
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTION_FAILED:
- event_str = "连接失败..";
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTED:
- event_str = "连接成功..";
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_DISCONNECTED:
- event_str = "连接断开..";
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_STOP:
- event_str = "停止播放..";
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_RESOLUTION_INFO:
- event_str = "分辨率信息: width: " + param1 + ", height: " + param2;
- setState(() {
- aspectRatio = double.parse(param1) / double.parse(param2);
- print('change aspectRatio:$aspectRatio');
- });
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_NO_MEDIADATA_RECEIVED:
- event_str = "收不到媒体数据,可能是url错误..";
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_SWITCH_URL:
- event_str = "切换播放URL..";
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CAPTURE_IMAGE:
- event_str = "快照: " + param1 + " 路径: " + param3;
-
- if (int.parse(param1) == 0) {
- print("截取快照成功。.");
- } else {
- print("截取快照失败。.");
- }
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_RECORDER_START_NEW_FILE:
- event_str = "[record] new file: " + param3;
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_ONE_RECORDER_FILE_FINISHED:
- event_str = "[record] record finished: " + param3;
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_START_BUFFERING:
- //event_str = "Start Buffering";
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_BUFFERING:
- event_str = "Buffering: " + param1 + "%";
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_STOP_BUFFERING:
- //event_str = "Stop Buffering";
- break;
- case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_DOWNLOAD_SPEED:
- event_str = "download_speed:" +
- (double.parse(param1) * 8 / 1000).toStringAsFixed(0) +
- "kbps" +
- ", " +
- (double.parse(param1) / 1024).toStringAsFixed(0) +
- "KB/s";
- break;
- }
-
- event_controller_.text = event_str;
- }
-
- void onSmartPlayerCreated(SmartPlayerController controller) async {
- player = controller;
- player.setEventCallback(_eventCallback);
-
- var ret = -1;
-
- //设置video decoder模式
- var is_video_hw_decoder = 0;
- if (defaultTargetPlatform == TargetPlatform.android)
- {
- ret = await player.setVideoDecoderMode(is_video_hw_decoder);
- }
- else if(defaultTargetPlatform == TargetPlatform.iOS)
- {
- is_video_hw_decoder = 1;
- ret = await player.setVideoDecoderMode(is_video_hw_decoder);
- }
-
- //设置缓冲时间
- var play_buffer = 100;
- ret = await player.setBuffer(play_buffer);
-
- //设置快速启动
- var is_fast_startup = 1;
- ret = await player.setFastStartup(is_fast_startup);
-
- //是否开启低延迟模式
- var is_low_latency_mode = 0;
- ret = await player.setPlayerLowLatencyMode(is_low_latency_mode);
-
- //set report download speed(默认5秒一次回调 用户可自行调整report间隔)
- ret = await player.setReportDownloadSpeed(1, 2);
-
- //设置RTSP超时时间
- var rtsp_timeout = 10;
- ret = await player.setRTSPTimeout(rtsp_timeout);
-
- var is_auto_switch_tcp_udp = 1;
- ret = await player.setRTSPAutoSwitchTcpUdp(is_auto_switch_tcp_udp);
-
- // 设置RTSP TCP模式
- //ret = await player.setRTSPTcpMode(1);
-
- //第一次启动 为方便测试 设置个初始url
- playback_url_controller_.text = "rtmp://live.hkstv.hk.lxdns.com/live/hks2";
- }
-
- Future<void> onSmartPlayerStartPlay() async {
- var ret = -1;
-
- if (playback_url_controller_.text.length < 8) {
- playback_url_controller_.text =
- "rtmp://live.hkstv.hk.lxdns.com/live/hks1"; //给个初始url
- }
-
- //实时静音设置
- ret = await player.setMute(is_mute_ ? 1 : 0);
-
- if (!is_playing_) {
- ret = await player.setUrl(playback_url_controller_.text);
- ret = await player.startPlay();
-
- if (ret == 0) {
- is_playing_ = true;
- }
- }
- }
-
- Future<void> onSmartPlayerStopPlay() async {
- if (is_playing_) {
- await player.stopPlay();
- playback_url_controller_.clear();
- is_playing_ = false;
- is_mute_ = false;
- }
- }
-
- Future<void> onSmartPlayerMute() async {
- if (is_playing_) {
- is_mute_ = !is_mute_;
- await player.setMute(is_mute_ ? 1 : 0);
- }
- }
-
- Future<void> onSmartPlayerSwitchUrl() async {
- if (is_playing_) {
- if (playback_url_controller_.text.length < 8) {
- playback_url_controller_.text =
- "rtmp://live.hkstv.hk.lxdns.com/live/hks1";
- }
-
- await player.switchPlaybackUrl(playback_url_controller_.text);
- }
- }
-
- Future<void> onSmartPlayerSetRotation() async {
- if (is_playing_) {
- rotate_degrees_ += 90;
- rotate_degrees_ = rotate_degrees_ % 360;
-
- if (0 == rotate_degrees_) {
- print("旋转90度");
- } else if (90 == rotate_degrees_) {
- print("旋转180度");
- } else if (180 == rotate_degrees_) {
- print("旋转270度");
- } else if (270 == rotate_degrees_) {
- print("不旋转");
- }
-
- await player.setRotation(rotate_degrees_);
- }
- }
- }
经测试,Flutter环境下,RTMP和RTSP播放,拥有Native SDK一样优异的播放体验。
相关资料:Github: https://github.com/daniulive/SmarterStreaming
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。