为什么要用Flutter?
Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。 Flutter可以与现有的代码一起工作。在全世界,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天);
除了支持APICloud, Unity3d, React Native外,为什么要做Flutter下的RTSP/RTMP播放器
首先,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. 界面截图:
RTMP直播播放器功能介绍:
- [支持播放协议]高稳定、超低延迟(一秒内,行业内几无效果接近的播放端)、业内首屈一指的RTMP直播播放器SDK;
- [多实例播放]支持多实例播放;
- [事件回调]支持网络状态、buffer状态等回调;
- [视频格式]支持RTMP扩展H.265,H.264;
- [音频格式]支持AAC/PCMA/PCMU/Speex;
- [H.264/H.265软解码]支持H.264/H.265软解;
- [H.264硬解码]Android/iOS支持H.264硬解;
- [H.265硬解]Android/iOS支持H.265硬解;
- [H.264/H.265硬解码]Android支持设置Surface模式硬解和普通模式硬解码;
- [缓冲时间设置]支持buffer time设置;
- [首屏秒开]支持首屏秒开模式;
- [低延迟模式]支持类似于线上娃娃机等直播方案的超低延迟模式设置(公网200~400ms);
- [复杂网络处理]支持断网重连等各种网络环境自动适配;
- [快速切换URL]支持播放过程中,快速切换其他URL,内容切换更快;
- [音视频多种render机制]Android平台,视频:surfaceview/OpenGL ES,音频:AudioTrack/OpenSL ES;
- [实时静音]支持播放过程中,实时静音/取消静音;
- [实时快照]支持播放过程中截取当前播放画面;
- [渲染角度]支持0°,90°,180°和270°四个视频画面渲染角度设置;
- [渲染镜像]支持水平反转、垂直反转模式设置;
- [实时下载速度更新]支持当前下载速度实时回调(支持设置回调时间间隔);
- [解码前视频数据回调]支持H.264/H.265数据回调;
- [解码后视频数据回调]支持解码后YUV/RGB数据回调;
- [解码前音频数据回调]支持AAC/PCMA/PCMU/SPEEX数据回调;
- [音视频自适应]支持播放过程中,音视频信息改变后自适应;
- [扩展录像功能]完美支持和录像SDK组合使用(支持RTMP扩展H.265流录制,支持PCMA/PCMU/Speex转AAC后录制,支持设置只录制音频或视频)
RTSP直播播放器功能介绍:
- [支持播放协议]高稳定、超低延迟、业内首屈一指的RTSP直播播放器SDK;
- [多实例播放]支持多实例播放;
- [事件回调]支持网络状态、buffer状态等回调;
- [视频格式]支持H.265、H.264,此外,Windows/Android平台还支持RTSP MJPEG播放;
- [音频格式]支持AAC/PCMA/PCMU;
- [H.264/H.265软解码]支持H.264/H.265软解;
- [H.264硬解码]Android/iOS支持H.264硬解;
- [H.265硬解]Android/iOS支持H.265硬解;
- [H.264/H.265硬解码]Android支持设置Surface模式硬解和普通模式硬解码;
- [RTSP模式设置]支持RTSP TCP/UDP模式设置;
- [RTSP TCP/UDP自动切换]支持RTSP TCP、UDP模式自动切换;
- [RTSP超时设置]支持RTSP超时时间设置,单位:秒;
- [RTSP 401认证处理]支持上报RTSP 401事件,如URL携带鉴权信息,会自动处理;
- [缓冲时间设置]支持buffer time设置;
- [首屏秒开]支持首屏秒开模式;
- [复杂网络处理]支持断网重连等各种网络环境自动适配;
- [快速切换URL]支持播放过程中,快速切换其他URL,内容切换更快;
- [音视频多种render机制]Android平台,视频:surfaceview/OpenGL ES,音频:AudioTrack/OpenSL ES;
- [实时静音]支持播放过程中,实时静音/取消静音;
- [实时快照]支持播放过程中截取当前播放画面;
- [渲染角度]支持0°,90°,180°和270°四个视频画面渲染角度设置;
- [渲染镜像]支持水平反转、垂直反转模式设置;
- [实时下载速度更新]支持当前下载速度实时回调(支持设置回调时间间隔);
- [解码前视频数据回调]支持H.264/H.265数据回调;
- [解码后视频数据回调]支持解码后YUV/RGB数据回调;
- [解码前音频数据回调]支持AAC/PCMA/PCMU/SPEEX数据回调;
- [音视频自适应]支持播放过程中,音视频信息改变后自适应;
- [扩展录像功能]完美支持和录像SDK组合使用(支持RTSP H.265流录制,支持PCMA/PCMU转AAC后录制,支持设置只录制音频或视频)
上接口:
//
// 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 2Future<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 urlTextEditingController 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,);}@overridevoid initState() {print("initState called..");super.initState();}@overridevoid didChangeDependencies() {print('didChangeDependencies called..');super.didChangeDependencies();}@overridevoid deactivate() {print('deactivate called..');super.deactivate();}@overridevoid dispose() {print("dispose called..");player.dispose();super.dispose();}@overrideWidget 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);//第一次启动 为方便测试 设置个初始urlplayback_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一样优异的播放体验。