Flutter 使用Texture实现Android渲染视频

这篇具有很好参考价值的文章主要介绍了Flutter 使用Texture实现Android渲染视频。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Flutter视频渲染系列

第一章 Android使用Texture渲染视频(本章)
第二章 Windows使用Texture渲染视频
第三章 Linux使用Texture渲染视频
第四章 全平台FFI+CustomPainter渲染视频
第五章 Windows使用Native窗口渲染视频
第六章 桌面端使用texture_rgba_renderer渲染视频



前言

flutter渲染视频的方法有多种,比如texture、platformview、ffi,其中texture是通过flutter自己提供的一个texture对象与dart界面关联后进行渲染,很容易搜索到android和ios的相关资料,但是大部分资料不够详细,尤其是jni渲染部分基本都略过了,对于使用flutter但不熟悉安卓的情况下,是比较难搞清楚通过texure拿到surface之后该怎么渲染。所以本文将说明整体的渲染流程。


一、如何实现?

1、定义Texture控件

在界面中定义一个Texture

Container(
  width: 640,
  height: 360,
  child: Texture(
  textureId: textureId,
))

2、创建Texture对象

java

TextureRegistry.SurfaceTextureEntry entry =flutterEngine.getRenderer().createSurfaceTexture();

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');
  });
  });
  }

java

 //methodchannel的startPreview方法实现,此处略
TextureRegistry.SurfaceTextureEntry entry =flutterEngine.getRenderer().createSurfaceTexture();
result.success(entry.id());

4、写入rgba

java

TextureRegistry.SurfaceTextureEntry entry = flutterEngine.getRenderer().createSurfaceTexture();
SurfaceTexture surfaceTexture = entry.surfaceTexture();
Surface surface = new Surface(surfaceTexture);
String path = call.argument("path");
//调用jni并传入surface
native_start_play(path,surface);

jni c++

ANativeWindow *a_native_window = ANativeWindow_fromSurface(env,surface);
ANativeWindow_setBuffersGeometry(a_native_window,width,height,WINDOW_FORMAT_RGBA_8888);
ANativeWindow_Buffer a_native_window_buffer;   
ANativeWindow_lock(a_native_window,&a_native_window_buffer,0);
uint8_t *first_window = static_cast<uint8_t *>(a_native_window_buffer.bits);
//rgba数据
uint8_t *src_data = data[0];
int dst_stride = a_native_window_buffer.stride * 4;
//ffmpeg的linesize
int src_line_size = linesize[0];
for(int i = 0; i < a_native_window_buffer.height;i++){
    memcpy(first_window+i*dst_stride,src_data+i*src_line_size,dst_stride);
}
ANativeWindow_unlockAndPost(a_native_window);

其中jni方法定义:

extern "C" JNIEXPORT void JNICALL Java_com_example_ffplay_1plugin_FfplayPlugin_native_1start_1play( JNIEnv *env, jobject /* this*/,  jstring path,jobject surface) ;

二、示例

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.
  @override
  Widget 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');
  });
  });
  }
  }
  @override
  Widget 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。
fflayplugin.java

if (call.method.equals("startPreview")) {
      //创建texture
      TextureRegistry.SurfaceTextureEntry entry =flutterEngine.getRenderer().createSurfaceTexture();
      SurfaceTexture surfaceTexture = entry.surfaceTexture();
      Surface surface = new Surface(surfaceTexture);
      //获取参数
      String path = call.argument("path");
      //调用jni开始渲染
      native_start_play(path,surface);
      //返回textureId
      result.success(entry.id());
    }
public native void native_start_play(String path, Surface surface);

native-lib.cpp

extern "C" JNIEXPORT void
JNICALL
Java_com_example_ffplay_1plugin_FfplayPlugin_native_1start_1play(
        JNIEnv *env,
        jobject /* this */,  jstring path,jobject surface) {
    //获取用于绘制的NativeWindow
    ANativeWindow *a_native_window = ANativeWindow_fromSurface(env,surface);
    //转换视频路径字符串为C中可用的
    const char *video_path = env->GetStringUTFChars(path,0);
    //初始化播放器,Play中封装了ffmpeg
    Play *play=new Play;
    //播放回调
    play->Display=[=](unsigned char* data[8], int linesize[8], int width, int height, AVPixelFormat format)
        {
        //设置NativeWindow绘制的缓冲区
        ANativeWindow_setBuffersGeometry(a_native_window,width,height,WINDOW_FORMAT_RGBA_8888);
        //绘制时,用于接收的缓冲区
        ANativeWindow_Buffer a_native_window_buffer;
        //加锁然后进行渲染
        ANativeWindow_lock(a_native_window,&a_native_window_buffer,0);
        uint8_t *first_window = static_cast<uint8_t *>(a_native_window_buffer.bits);
        uint8_t *src_data = data[0];
        //拿到每行有多少个RGBA字节
        int dst_stride = a_native_window_buffer.stride * 4;
        int src_line_size = linesize[0];
        //循环遍历所得到的缓冲区数据
        for(int i = 0; i < a_native_window_buffer.height;i++){
            //内存拷贝进行渲染
            memcpy(first_window+i*dst_stride,src_data+i*src_line_size,dst_stride);
        }
        //绘制完解锁
        ANativeWindow_unlockAndPost(a_native_window);
};
    //开始播放
    play->Start(video_path,AV_PIX_FMT_RGBA);
    env->ReleaseStringUTFChars(path,video_path);
}

效果预览
android TV横屏
Flutter 使用Texture实现Android渲染视频


三、完整代码

https://download.csdn.net/download/u013113678/87094784
包含完整代码的flutter项目,版本3.0.4、3.3.8都成功运行,目录说明如下。
Flutter 使用Texture实现Android渲染视频


总结

以上就是今天要讲的内容,flutter在安卓上渲染视频还是相对容易实现的。因为资料比较多,但是只搜索fluter相关的资料只能了解调texture的用法,无法搞清楚texture到ffmpeg的串连,我们需要单独去了解安卓调用ffmpeg渲染才能找到的它们之间的关联。总的来说,实现相对容易效果也能接受。文章来源地址https://www.toymoban.com/news/detail-402245.html

到了这里,关于Flutter 使用Texture实现Android渲染视频的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Flutter视频播放器在iOS端和Android端都能实现全屏播放

    Flutter开发过程中,对于视频播放的三方组件有很多,在Android端适配都挺好,但是在适配iPhone手机的时候,如果设置了 UIInterfaceOrientationLandscapeLeft 和 UIInterfaceOrientationLandscapeRight 都为false的情况下,无法做到全屏播放,因为FLutter的 SystemChrome.setPreferredOrientations 方法不适配iOS端

    2024年02月05日
    浏览(37)
  • 【unity shader】水体渲染基础-基于texture distortion的流体流动材质

    当液体静止时,它在视觉上与固体没有太大区别。 但大多数时候,我们的性能不一定支持去实现特别复杂的水物理模拟, 需要的只是在常规的静态材料的表面上让其运动起来。我们可以对网格的 UV 坐标实现动态变化,从而让表面的纹理效果实现变形的动态变化。 1.1. uv实时

    2024年02月03日
    浏览(44)
  • Android视频融合特效播放与渲染

    一个有趣且很有创意的视频特效项目。 https://github.com/duqian291902259/AlphaPlayerPlus 前言 直播产品,需要更多炫酷的礼物特效,比如飞机特效,跑车特效,生日蛋糕融特效等,融合了直播流画面的特效。所以在字节开源的alphaPlayer库和特效VAP库的基础上进行改造,实现融合特效渲染

    2023年04月13日
    浏览(27)
  • Flutter 使用 Key 强制重新渲染小部件

    Key 在 Flutter 中是一个抽象类,它有两个主要的子类:LocalKey 和 GlobalKey。LocalKey 只在当前小部件树中唯一,而 GlobalKey 在整个应用程序中是全局唯一的。 Key 的主要作用是标识小部件。当 Flutter 进行小部件树的重建时,它会根据 Key 来判断哪些小部件需要重新创建,哪些小部件

    2024年02月09日
    浏览(29)
  • Android 循环录像,保留加锁视频,flutter框架

    return 0; } } /** 获取所有的视频信息 @return */ public List getAllDriveVideo() { List driveVideoList = new ArrayList(); String selectQuery = \\\"SELECT * FROM \\\" + VIDEO_TABLE_NAME; SQLiteDatabase db = this.getWritableDatabase(); Cursor cursor = db.rawQuery(selectQuery, null); // looping through all rows and adding to list if (cursor.moveToFirst()) { do

    2024年04月13日
    浏览(23)
  • android开发教程视频孙老师,flutter中文网

    1.网络 2.Java 基础容器同步设计模式 3.Java 虚拟机内存结构GC类加载四种引用动态代理 4.Android 基础性能优化Framwork 5.Android 模块化热修复热更新打包混淆压缩 6.音视频FFmpeg播放器 网络协议模型 应用层 :负责处理特定的应用程序细节 HTTP、FTP、DNS 传输层 :为两台主机提供端到端

    2024年03月15日
    浏览(35)
  • Android 使用FFmpeg3.3.9基于命令实现视频压缩

    前言 首先利用linux平台编译ffmpeg的so库,具体详情请查看文章:Android NDK(ndk-r16b)交叉编译FFmpeg(3.3.9)_jszlittlecat_720的博客-CSDN博客    点击Create JNI function for compressVideo 自动打开native-lib.cpp并创建完成Java_com_suoer_ndk_ffmpegtestapplication_VideoCompress_compressVideo 方法  在此方法下实现压缩

    2024年02月02日
    浏览(40)
  • Android - 使用GSY实现视频播放和画中画悬浮窗

    0. 现完成功能: 悬浮窗区分横屏竖屏两种尺寸 悬浮窗可以在页面上随意拖动 在播放视频时按返回键/Home键/离开当前页时触发开启 悬浮窗显示在退到后台/在应用内/桌面 带播放进度开启悬浮窗,带播放进度回到应用内页面 权限:每次开启前判断有无权限,没权限并且请求过

    2023年04月11日
    浏览(27)
  • libVLC 提取视频帧使用OpenGL渲染

    在上一节中,我们讲解了如何使用QWidget渲染每一帧视频数据。 由于我们不停的生成的是QImage对象,因此对 CPU 负荷较高。其实在绘制这块我们可以使用 OpenGL去绘制,利用 GPU 减轻 CPU 计算负荷,本节讲解使用OpenGL来绘制每一帧视频数据。 libVLC 提取视频帧使用QWidget渲染-CSDN博

    2024年04月10日
    浏览(34)
  • Linux平台下基于OpenGL实现YUV视频渲染

    源码详见https://github.com/samxfb/linux-opengl-render

    2024年01月21日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包