Flutter 使用Texture实现Linux渲染视频
Flutter视频渲染系列
第一章 Android使用Texture渲染视频
第二章 Windows使用Texture渲染视频
第三章 Linux使用Texture渲染视频(本章)
第四章 全平台FFI+CustomPainter渲染视频
文章目录
- Flutter视频渲染系列
- 前言
- 一、如何实现?
- 1、定义Texture控件
- 2、创建Texture对象
- (1)继承FlPixelBufferTexture
- (2)注册Texture
- 3、关联TextureId
- 4、写入rgba
- 二、示例
- 1.使用ffmpeg解码播放
- 三、完整代码
- 总结
前言
flutter渲染视频的方法有多种,比如texture、platformview、ffi,其中texture是通过flutter自己提供的一个texture对象与dart界面关联后进行渲染,很容易搜索到android和ios的相关资料,但是Linux上却几乎找不到任何资料。通过查看一些开源库的代码,才找到Linux上使用flutter texture的方法,在这里做一个简单的介绍。
一、如何实现?
1、定义Texture控件
在界面中定义一个Texture
Container(width: 640,height: 360,child: Texture(textureId: textureId,
))
2、创建Texture对象
(1)继承FlPixelBufferTexture
此处代码为dart_vlc源码,因为是一个独立对象所有可以直接拿来用,自己继承实现也基本差不多,所以就没必要造轮子了。
#ifndef VIDEO_OUTLET_H_
#define VIDEO_OUTLET_H_
#include <flutter_linux/flutter_linux.h>
#include <gtk/gtk.h>
struct _VideoOutletClass {FlPixelBufferTextureClass parent_class;
};
struct VideoOutletPrivate {int64_t texture_id = 0;uint8_t* buffer = nullptr;int32_t video_width = 0;int32_t video_height = 0;
};
G_DECLARE_DERIVABLE_TYPE(VideoOutlet, video_outlet, DART_VLC, VIDEO_OUTLET,FlPixelBufferTexture)
G_DEFINE_TYPE_WITH_CODE(VideoOutlet, video_outlet,fl_pixel_buffer_texture_get_type(),G_ADD_PRIVATE(VideoOutlet))
static gboolean video_outlet_copy_pixels(FlPixelBufferTexture* texture,const uint8_t** out_buffer,uint32_t* width, uint32_t* height,GError** error) {auto video_outlet_private =(VideoOutletPrivate*)video_outlet_get_instance_private(DART_VLC_VIDEO_OUTLET(texture));*out_buffer = video_outlet_private->buffer;*width = video_outlet_private->video_width;*height = video_outlet_private->video_height;return TRUE;
}
static VideoOutlet* video_outlet_new() {return DART_VLC_VIDEO_OUTLET(g_object_new(video_outlet_get_type(), nullptr));
}
static void video_outlet_class_init(VideoOutletClass* klass) {FL_PIXEL_BUFFER_TEXTURE_CLASS(klass)->copy_pixels = video_outlet_copy_pixels;
}
static void video_outlet_init(VideoOutlet* self) {}
#endif
(2)注册Texture
static FlTextureRegistrar* _registrar;
//创建自定义的texture对象auto texture=video_outlet_new();//注册对象fl_texture_registrar_register_texture(_registrar,FL_TEXTURE(texture));
3、关联TextureId
dart
int textureId = -1;if (textureId < 0) {//调用本地方法获取textureId methodChannel.invokeMethod('startPreview',<String,dynamic>{'path':'test.mov'}).then((value) {textureId = value;setState(() {print('textureId ==== $textureId');});});}
c++
//methodchannel的startPreview方法实现,此处略//texure指针的地址即为textureIdg_autoptr(FlValue) result = fl_value_new_int((int64_t)texture);//设置返回值response = FL_METHOD_RESPONSE(fl_method_success_response_new(result));
4、写入rgba
static FlTextureRegistrar* _registrar;
//取得自定义的内部对象
auto video_outlet_private =(VideoOutletPrivate*)video_outlet_get_instance_private(texture);
//设置视频帧宽高
video_outlet_private->video_width = width;
video_outlet_private->video_height = height;
//设置rgba数据
video_outlet_private->buffer = data[0];
//通知渲染
fl_texture_registrar_mark_texture_frame_available(_registrar, FL_TEXTURE(texture));
注:FlTextureRegistrar的获取方法为:
//定义TextureRegistrar对象
static FlTextureRegistrar* _registrar;
//插件注册代码,这里的插件名为ffplay_plugin,此方法为官方生成代码
void ffplay_plugin_register_with_registrar(FlPluginRegistrar* registrar) {FfplayPlugin* plugin = FFPLAY_PLUGIN(g_object_new(ffplay_plugin_get_type(), nullptr));g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();g_autoptr(FlMethodChannel) channel =fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar),"ffplay_plugin",FL_METHOD_CODEC(codec)); //获取TextureRegistrar对象 _registrar=fl_plugin_registrar_get_texture_registrar(registrar); fl_method_channel_set_method_call_handler(channel, method_call_cb,g_object_ref(plugin),g_object_unref);g_object_unref(plugin);
}
二、示例
1.使用ffmpeg解码播放
main.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
MethodChannel methodChannel = MethodChannel('ffplay_plugin');
void main() {runApp(MyApp());
}
class MyApp extends StatelessWidget {// This widget is the root of your application.@overrideWidget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo',theme: ThemeData(primarySwatch: Colors.blue,),home: MyHomePage(title: 'Flutter Demo Home Page'),);}
}class MyHomePage extends StatefulWidget {MyHomePage({Key? key, required this.title}) : super(key: key);final String title;@override_MyHomePageState createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {int _counter = 0;int textureId = -1;Future<void> _createTexture() async {print('textureId = $textureId');//调用本地方法播放视频if (textureId < 0) {methodChannel.invokeMethod('startPreview',<String,dynamic>{'path':'https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv'}).then((value) {textureId = value;setState(() {print('textureId ==== $textureId');});});}}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text(widget.title),),//控件布局body: Center(child: Row(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[if (textureId > -1)ClipRect (child: Container(width: 640,height: 360,child: Texture(textureId: textureId,)),),],),),floatingActionButton: FloatingActionButton(onPressed: _createTexture,tooltip: 'createTexture',child: Icon(Icons.add),),);}
}
定义一个插件我这里是fflay_plugin。
fflay_plugin.cc
相关对象的定义
static FlTextureRegistrar* _registrar;
class PlayData {public://Play中封装了ffmpegPlay* play;VideoOutlet* flutter_pixel_buffer;int64_t texture_id;
};
static std::map<int64_t, PlayData*> playMap;
获取FlTextureRegistrar对象
//插件注册代码,这里的插件名为ffplay_plugin,此方法为官方生成代码
void ffplay_plugin_register_with_registrar(FlPluginRegistrar* registrar) {FfplayPlugin* plugin = FFPLAY_PLUGIN(g_object_new(ffplay_plugin_get_type(), nullptr));g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();g_autoptr(FlMethodChannel) channel =fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar),"ffplay_plugin",FL_METHOD_CODEC(codec)); //获取TextureRegistrar对象 _registrar=fl_plugin_registrar_get_texture_registrar(registrar); fl_method_channel_set_method_call_handler(channel, method_call_cb,g_object_ref(plugin),g_object_unref);g_object_unref(plugin);
}
methodChannel部分
if (strcmp(method, "startPreview") == 0){//获取参数auto arguments = fl_method_call_get_args(method_call);auto path = fl_value_get_string(fl_value_lookup_string(arguments, "path")); //创建textureauto texture=video_outlet_new();//注册texturefl_texture_registrar_register_texture(_registrar,FL_TEXTURE(texture));PlayData* pd = new PlayData; //初始化播放器 pd->play = new Play;pd->flutter_pixel_buffer=texture;pd->texture_id = (int64_t)texture;playMap[pd->texture_id] = pd;//播放视频回调pd->play->Display = [=](unsigned char* data[8], int linesize[8], int width, int height, AVPixelFormat format) {//设置视频数据auto video_outlet_private =(VideoOutletPrivate*)video_outlet_get_instance_private(pd->flutter_pixel_buffer);video_outlet_private->video_width = width;video_outlet_private->video_height = height;video_outlet_private->buffer = data[0];//通知渲染fl_texture_registrar_mark_texture_frame_available(_registrar, FL_TEXTURE(pd->flutter_pixel_buffer));};//开始播放视频pd->play->Start(path, AV_PIX_FMT_RGBA);//返回textureIdg_autoptr(FlValue) result = fl_value_new_int((int64_t)texture);response = FL_METHOD_RESPONSE(fl_method_success_response_new(result));}
效果预览
三、完整代码
https://download.csdn.net/download/u013113678/87096317
包含完整代码的flutter项目,版本3.0.4、3.3.8都成功运行,需要自行安装ffmpeg库版本最好为4.3或5.0.1。目录说明如下。
注:由于笔者在Ubuntu上采用静态加载ffmpeg so库出现了glibc冲突问题没有解决,所以采用了动态加载so的方式,DllImportUtils的作用只是动态加载so,具体可查看《C++ 使用宏加载动态库》。
总结
以上就是今天要讲的内容,flutter在linux上渲染视频,还是有点不容易的,一是缺乏相关资料,二是flutter在Linux上的本地代码是另外一套封装与windows完全不相同。而且采用的是c语言自定义一套面向对象规则的方式,当然编译器是clang++我们可以使用c++的方式编码。总的来说,flutter是可以在Linux实现视频渲染的,如果要进一步优化则需要用gltexture或者本地窗口渲染。
Flutter 使用Texture实现Linux渲染视频相关推荐
- Flutter 使用Texture实现Windows渲染视频
Flutter视频渲染系列 第一章 Android使用Texture渲染视频 第二章 Windows使用Texture渲染视频(本章) 第三章 Linux使用Texture渲染视频 第四章 全平台FF ...
- Flutter 使用Texture实现Android渲染视频
Flutter视频渲染系列 第一章 Android使用Texture渲染视频(本章) 第二章 Windows使用Texture渲染视频 第三章 Linux使用Texture渲染视频 第四章 全平台FF ...
- D3D Surface/Texture SDL DDraw渲染视频的区别和疑问
1 D3D Surface用起来比较简单,窗口改变时视频模糊,貌似是初始化窗口过小.全屏时有锯齿. StretchRect的Rect是显示区域宽高,这个值固定是初始值.改成随窗口变化,失败. 2 ...
- Flutter 用Texture控件在Windows平台实现视频渲染
提示:阅读此文章之前需要有C++开发经验,知道如何利用channel在C++和Dart之间做通信. 前言 一.PlatformView与Texture是什么? 二.使用步骤 1.在Flutter需要显 ...
- 打造Flutter高性能富文本编辑器——渲染篇
本系列文章主要介绍Flutter富文本编辑的设计和实现,从协议层.渲染层.自定义扩展以及体验优化等方面,详细介绍如何实现一个功能完善.可扩展.高性能的Flutter富文本编辑器,以及闲鱼在实践过程中遇 ...
- OpenGL渲染视频(二)
目录 一.前言 二.openGL渲染介绍 1.OpenGl渲染管线的流程 2.顶点着色器的介绍 3.片元着色器的介绍 三.openGL着色器语言GLSL介绍 1.数据类型 2.限定符 3.二维图像渲染 ...
- 基于Linux的视频传输系统(上大学时參加的一个大赛的论文)
文件夹<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 1原创性 ...
- linux自学视频资料第四讲:目录
大家下午好! 今天linux自学视频第四讲:目录 这一讲大家要记住linux中的文件的权限(这在第三讲中有讲到)和目录的权限 首先大家要记住:u g o 这三个字母的定义 然后是 r w x 这三个 ...
- php实现视频转gif,在Linux上将视频转换成动态gif图片
本文记录一下在linux上将视频转换成动态gif图片的方法. 首先,需要在Linux系统上安装FFmpeg,我会用这个工具去解压从视频中解压出视频帧. 下面的指令会解压出独立的视频帧,将它们保存为GI ...
最新文章
- 面试问题-使用Java线程做数学运算
- Hibernate的命名查询(NamedQuery)
- 让 CPU 告诉你硬盘和网络到底有多慢
- 九十九、Python所学经验分享
- ux.form.field.Verify 验证码控件
- 为什么unity 安装完模块还是找不到sdk_Unity填坑笔记(四)——移植UWP平台
- 诗与远方:无题(三十七)- 凿壁偷光
- HUAS 1482 lsy的后宫(DP+矩阵快速幂)
- 【转】Java杂谈(九)--Struts
- 在线密码管理器LastPass遭入侵 官方建议修改主密码
- MySQL5.7创建数据库与添加用户、删除用户及授权、保证数据库账号安全
- 图片标注工具labeling的安装和使用
- 基于Python实现网页版之复杂图片去水印
- 如何在iconfont.cn 下载ttf格式的图标
- jquery.countdown.js一个时间倒计时的插件
- 爱思助手 for Mac(苹果手机助手)中文版
- 怎样关闭计算机自动开机,电脑定时开机,教您电脑定时开机怎么取消
- 51单片机程序加密c语言,51单片机24C04密码锁(C程序+Proteus仿真)
- python爬虫经典段子_Python爬虫实战:爬取内涵段子
- 防病毒Clamav使用及API调用测试