flutter 视频解码器fijkplayer使用

本文介绍了在Flutter中进行视频监控项目时遇到的H265视频流无法在iOS模拟器及真机上播放的问题。通过引入fijkplayer插件,成功实现了视频播放,并展示了如何自定义UI界面以满足更多功能需求。此外,还提供了自定义UI界面的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       本人做视频监控项目的时候,需要去展示视频流到用户端,一开始使用flutter自带的VideoPlayer播放监控视频,一开始没有发现有什么问题,因为使用多的是Android模拟器,一直没有使用iso模拟器或者真机测试能不能播放,直到开发接近尾声,在ios模拟器上测试的时候发现了问题,视频流为H264的时候能正常播放,但是视频流为H265的时候一直转圈,模拟器和真机播放不了(Android模拟器和真机都是可以播放的)。后来就打算换一个三方插件来调整播放。

  1. 在pubspec.yaml导入引用的fijkplayer插件
     # 视频解码器 软解码
      fijkplayer: ^0.10.1
  2. 状态详解
    状态名播放器表现
    idle闲置状态,刚完成构造的 FijkPlayer 处于此状态。
    此状态下播放器占用少量内存,无额外线程启动。
    idle 状态只能通过 setDataSource 转换为 initialized 状态
    initialized初始化完成状态,和 idle 状态相比,仅是多了输入媒体数据源的信息。 同样无额外线程打开。
    asyncPreparing异步准备状态,在 initialized 状态调用 prepareAsync 到达此状态。
    这不是一个稳定状态,此状态等待特定任务完成后自动转化为 prepared 状态。
    这一状态的主要准备工作是 探测媒体文件类型,打开媒体文件,打开解码器以及新建解码线程,新建数据 read 线程,打开音频输出设备,新建视频输出线程等。
    preparedasyncPreparing 完成指定任务后自动转化为此状态。
    此状态下已经开始缓冲解码了一部分音视频数据,可以随时进行播放。
    started媒体(视频、音频)正在播放中。
    paused媒体(视频、音频)播放暂停。
    completed媒体(视频、音频)播放完成。 可重新从头开始播放。
    stopped播放器各种线程占用资源都已经释放。 音频设备关闭。
    end播放器中所有需要手动释放的内存都释放完成。
    处于此状态的播放器只能等待垃圾回收进行内存释放。
    error播放器出现错误。

  3. 简单使用代码如下
    import 'package:fijkplayer/fijkplayer.dart';
    import 'package:flutter/material.dart';
    
    class VideoScreen extends StatefulWidget {
      final String url;//视频地址
    
      VideoScreen({@required this.url});
    
      @override
      _VideoScreenState createState() => _VideoScreenState();
    }
    
    class _VideoScreenState extends State<VideoScreen> {
      final FijkPlayer player = FijkPlayer();
    
      _VideoScreenState();
    
      @override
      void initState() {
        super.initState();
        //传入视频地址,视频是否自动播放
        player.setDataSource(widget.url, autoPlay: true);
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(title: Text("视频监控")),
            body: Container(
              alignment: Alignment.center,
              child: FijkView(
                player: player,
              ),
            ));
      }
    
      @override
      void dispose() {
        super.dispose();
        player.release();
      }
    }
     
  4. 使用后能够正常播放,但是你发现UI界面太丑了,或者功能不够自己使用,需要更多的功能使用才行,别急!三方提供者早就想到了这里,所以提供了可以自己定的UI界面设置。需要修改panelBuilder更改UI界面,废话不多说,上代码。 首先加入自定的UI界面代码
    class CustomFijkPanel extends StatefulWidget {
      final FijkPlayer player;
      final BuildContext buildContext;
      final Size viewSize;
      final Rect texturePos;
    
      const CustomFijkPanel({
        @required this.player,
        this.buildContext,
        this.viewSize,
        this.texturePos,
      });
    
      @override
      _CustomFijkPanelState createState() => _CustomFijkPanelState();
    }
    
    class _CustomFijkPanelState extends State<CustomFijkPanel> {
    
      FijkPlayer get player => widget.player;
      bool _playing = false;
    
      @override
      void initState() {
        super.initState();
        widget.player.addListener(_playerValueChanged);
      }
    
      void _playerValueChanged() {
        FijkValue value = player.value;
    
        bool playing = (value.state == FijkState.started);
        if (playing != _playing) {
          setState(() {
            _playing = playing;
          });
        }
      }
    
      @override
      Widget build(BuildContext context) {
        Rect rect = Rect.fromLTRB(
            max(0.0, widget.texturePos.left),
            max(0.0, widget.texturePos.top),
            min(widget.viewSize.width, widget.texturePos.right),
            min(widget.viewSize.height, widget.texturePos.bottom));
    
        return Positioned.fromRect(
          rect: rect,
          child: Container(
            alignment: Alignment.bottomLeft,
            child: IconButton(
              icon: Icon(
                _playing ? Icons.pause : Icons.play_arrow,
                color: Colors.white,
              ),
              onPressed: () {
                _playing ? widget.player.pause() : widget.player.start();
              },
            ),
          ),
        );
      }
    
      @override
      void dispose() {
        super.dispose();
        player.removeListener(_playerValueChanged);
      }
    }

        这里是使用时候的代码

FijkView(
  player: player,
  panelBuilder: (FijkPlayer player, FijkData data, BuildContext context, Size viewSize, Rect texturePos) {
    return CustomFijkPanel(
      player: player,
      buildContext: context,
      viewSize: viewSize,
      texturePos: texturePos);
  },
)

到这里就完成了,简单使用、自定义使用,如果还需要看详细信息,可参考他们提供的官方文档,地址如下:fijkplayer -- Flutter plugin for ijkplayer - fijkplayer -- Flutter plugin for ijkplayer

<think>好的,用户现在想了解如何集成FijkPlayerFlutter项目中。之前已经介绍过Flutter中的视频播放框架,其中提到FijkPlayer是基于ijkplayer的高级选项,支持多种流媒体协议和硬解加速。现在需要详细说明集成步骤。 首先,用户可能已经有一定的Flutter开发经验,但可能对集成第三方插件不熟悉。需要先明确安装步骤,包括在pubspec.yaml中添加依赖。记得提醒用户注意版本号,可能最新版已经更新,建议查看pub.dev获取最新版本。 接下来,添加依赖后,用户需要运行flutter pub get,这个步骤虽然基础,但新手可能会忘记,所以需要明确写出。然后,对于Android和iOS的不同配置,可能需要分别处理。比如,Android的Gradle配置可能需要设置minSdkVersion,而iOS可能需要修改Podfile或设置部署目标版本。 权限配置也是关键,比如网络权限和明文传输,特别是Android 9以上需要允许明文。需要给出具体的AndroidManifest.xml修改示例,确保用户可以直接复制粘贴。iOS的后台播放权限同样重要,避免应用被拒绝或功能不可用。 然后,基本使用部分需要给出代码示例,包括初始化控制器、播放控制等。可能用户需要知道如何显示播放器界面,如何管理生命周期,比如在页面退出时释放资源。需要提醒controller.dispose()的重要性,避免内存泄漏。 高级配置部分,比如设置日志级别、硬解码选项,这些是提升播放性能的关键。用户可能需要知道如何调试问题,所以开启日志是有帮助的。另外,自定义选项如超时时间和重连次数对于处理网络不稳定情况也很重要。 最后,常见问题部分需要涵盖初始化失败、黑屏、声音不同步等典型问题,给出解决方案。用户在实际使用中可能会遇到这些问题,提前给出提示能减少他们的困扰。同时,提醒包体积增加和协议问题,避免法律风险。 整个过程中,需要保持步骤清晰,代码示例准确,并且语言简洁明了。考虑到用户可能有不同的需求,比如直播或点播,可能需要进一步说明不同场景下的配置调整。确保用户能够顺利集成FijkPlayer,并解决可能遇到的问题。</think>以下是Flutter集成FijkPlayer的详细指南,包含关键步骤和开发注意事项: --- ### 一、环境准备 1. **添加依赖** 在`pubspec.yaml`中: ```yaml dependencies: fijkplayer: ^0.10.2 # 检查最新版本 # 可选日志增强 fijkplayer_skin: ^0.0.1 ``` 2. **平台配置** - **Android**: - `android/app/build.gradle`中设置: ```gradle minSdkVersion 21 # 最低要求 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } ``` - **iOS**: - Podfile添加: ```ruby platform :ios, '11.0' # 最低iOS版本 post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['ENABLE_BITCODE'] = 'NO' end end end ``` --- ### 二、权限配置 1. **Android** ```xml <!-- AndroidManifest.xml --> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WAKE_LOCK"/> <!-- 允许明文传输 --> <application android:usesCleartextTraffic="true" ...> ``` 2. **iOS** ```xml <!-- Info.plist --> <key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict> <!-- 后台播放 --> <key>UIBackgroundModes</key> <array> <string>audio</string> </array> ``` --- ### 三、基础使用 ```dart import 'package:fijkplayer/fijkplayer.dart'; class VideoPage extends StatefulWidget { @override _VideoPageState createState() => _VideoPageState(); } class _VideoPageState extends State<VideoPage> { final FijkPlayer player = FijkPlayer(); @override void initState() { super.initState(); // 设置数据源 player.setDataSource( "https://example.com/video.mp4", autoPlay: true ); } @override Widget build(BuildContext context) { return FijkView( player: player, panelBuilder: fijkPanel2Builder(), // 使用内置控制面板 ); } @override void dispose() { super.dispose(); player.release(); // 必须释放资源 } } ``` --- ### 四、高级配置 1. **播放器参数调整** ```dart // 初始化时配置 player.setOption(FijkOption.hostCategory, "request-screen-on", 1); player.setOption(FijkOption.playerCategory, "mediacodec", 1); // 硬解 // 设置日志级别 FijkLog.setLogLevel(FijkLogLevel.Debug); ``` 2. **自定义播放器UI** 通过继承`FijkPanelWidget`实现: ```dart class CustomPanel extends FijkPanelWidget { @override Widget build(BuildContext context) { return GestureDetector( onTap: () => toggleControls(), child: Stack( children: [ buildCover(), // 视频画面 buildTopBar(), // 自定义顶部栏 buildBottomBar(), // 自定义控制栏 buildLoading(), // 加载指示 ], ), ); } } ``` --- ### 五、常见问题处理 1. **初始化失败** - 检查是否添加`android:hardwareAccelerated="true"` - 确认NDK版本兼容(建议r21+) 2. **黑屏无画面** ```dart player.setOption(FijkOption.formatCategory, "safe", 0); // 关闭安全模式 ``` 3. **音画不同步** ```dart player.setOption(FijkOption.playerCategory, "framedrop", 5); player.setOption(FijkOption.playerCategory, "start-on-prepared", 1); ``` --- ### 六、优化建议 1. **预加载机制** ```dart // 预初始化播放器 final prePlayer = FijkPlayer(); prePlayer.setDataSource(url, autoPlay: false); // 实际播放时直接切换 player.reset().then((_) { player.setDataSource(prePlayer.dataSource); }); ``` 2. **缓存配置** ```dart player.setOption(FijkOption.playerCategory, "infbuf", 1); // 无限缓冲 player.setOption(FijkOption.formatCategory, "probesize", "102400"); // 探测大小 ``` --- **注意事项**: - 包体积增加约3-5MB(需权衡使用) - 遵循LGPL协议(若修改源码需开源) - 直播流建议设置超时参数: ```dart player.setOption(FijkOption.playerCategory, "reconnect", 5); // 重连次数 ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A HandSome Man

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值