td_fplayer 0.0.1-beta.7 copy "td_fplayer: ^0.0.1-beta.7" to clipboard
td_fplayer: ^0.0.1-beta.7 copied to clipboard

A Video Player Flutter plugin based on ijkplayer, support most popular protocols and codecs.

td_fplayer #

pub package

基于 ijkplayer 的 Flutter 视频播放器插件,支持 Android 和 iOS 平台。

本项目基于 fplayer 进行二次开发,替换为标准 ijkplayer 内核。

特性 #

  • ✅ 支持 Android 和 iOS 双平台
  • ✅ 支持常见视频格式(MP4、FLV、RTMP、HLS 等)
  • ✅ 支持硬件解码
  • ✅ 支持倍速播放
  • ✅ 支持清晰度切换
  • ✅ 支持视频列表播放
  • ✅ 支持全屏模式
  • ✅ 支持亮度和音量手势调节
  • ✅ 支持播放进度手势调节
  • ✅ 支持视频截图(iOS)
  • ✅ 内置美观的播放控制面板

安装 #

pubspec.yaml 中添加依赖:

dependencies:
  td_fplayer: ^0.0.1-beta.1

快速开始 #

基本使用 #

import 'package:flutter/material.dart';
import 'package:td_fplayer/td_fplayer.dart';

class VideoPlayerPage extends StatefulWidget {
  @override
  _VideoPlayerPageState createState() => _VideoPlayerPageState();
}

class _VideoPlayerPageState extends State<VideoPlayerPage> {
  final FPlayer player = FPlayer();

  @override
  void initState() {
    super.initState();
    _initPlayer();
  }

  Future<void> _initPlayer() async {
    // 基础配置
    await player.setOption(FOption.hostCategory, "request-screen-on", 1);
    await player.setOption(FOption.hostCategory, "request-audio-focus", 1);
    
    // 硬件解码配置(防止花屏)
    await player.setOption(FOption.playerCategory, "mediacodec", 1);
    await player.setOption(FOption.playerCategory, "mediacodec-auto-rotate", 1);
    await player.setOption(FOption.playerCategory, "mediacodec-handle-resolution-change", 1);
    
    // 缓冲配置(防止花屏)
    await player.setOption(FOption.playerCategory, "packet-buffering", 1);
    
    // 设置视频源并播放
    await player.setDataSource(
      'http://player.alicdn.com/video/aliyunmedia.mp4',
      autoPlay: true,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('视频播放器')),
      body: FView(
        player: player,
        width: double.infinity,
        height: 200,
        color: Colors.black,
        panelBuilder: fPanelBuilder(
          title: '视频标题',
        ),
      ),
    );
  }

  @override
  void dispose() {
    player.release();
    super.dispose();
  }
}

完整示例 #

import 'package:flutter/material.dart';
import 'package:td_fplayer/td_fplayer.dart';
import 'package:screen_brightness/screen_brightness.dart';

class VideoScreen extends StatefulWidget {
  final String url;

  const VideoScreen({super.key, required this.url});

  @override
  VideoScreenState createState() => VideoScreenState();
}

class VideoScreenState extends State<VideoScreen> {
  final FPlayer player = FPlayer();

  // 视频列表
  List<VideoItem> videoList = [
    VideoItem(
      title: '第一集',
      subTitle: '视频1副标题',
      url: 'http://player.alicdn.com/video/aliyunmedia.mp4',
    ),
    VideoItem(
      title: '第二集',
      subTitle: '视频2副标题',
      url: 'https://www.runoob.com/try/demo_source/mov_bbb.mp4',
    ),
  ];

  // 倍速列表
  Map<String, double> speedList = {
    "2.0": 2.0,
    "1.5": 1.5,
    "1.0": 1.0,
    "0.5": 0.5,
  };

  // 清晰度列表
  Map<String, ResolutionItem> resolutionList = {
    "480P": ResolutionItem(
      value: 480,
      url: 'https://www.runoob.com/try/demo_source/mov_bbb.mp4',
    ),
    "270P": ResolutionItem(
      value: 270,
      url: 'http://player.alicdn.com/video/aliyunmedia.mp4',
    ),
  };

  int videoIndex = 0;

  @override
  void initState() {
    super.initState();
    startPlay();
  }

  void startPlay() async {
    // 基础配置
    await player.setOption(FOption.hostCategory, "enable-snapshot", 1);
    await player.setOption(FOption.hostCategory, "request-screen-on", 1);
    await player.setOption(FOption.hostCategory, "request-audio-focus", 1);
    
    // 播放器配置
    await player.setOption(FOption.playerCategory, "reconnect", 20);
    await player.setOption(FOption.playerCategory, "framedrop", 20);
    await player.setOption(FOption.playerCategory, "enable-accurate-seek", 1);
    // soundtouch: 变速播放时的音频处理
    // 1 = 变速不变调(音调正常,但直播录制等不规则音频可能有杂音)
    // 0 = 变速变调(无杂音,但加速声音变尖、减速声音变低沉)
    await player.setOption(FOption.playerCategory, "soundtouch", 0);
    
    // 硬件解码配置
    await player.setOption(FOption.playerCategory, "mediacodec", 1);
    await player.setOption(FOption.playerCategory, "mediacodec-auto-rotate", 1);
    await player.setOption(FOption.playerCategory, "mediacodec-handle-resolution-change", 1);
    
    // 缓冲配置(0=快速首帧,1=稳定但慢)
    await player.setOption(FOption.playerCategory, "packet-buffering", 0);

    setVideoUrl(videoList[videoIndex].url);
  }

  Future<void> setVideoUrl(String url) async {
    try {
      await player.setDataSource(url, autoPlay: true, showCover: true);
    } catch (error) {
      print("播放异常: $error");
    }
  }

  @override
  Widget build(BuildContext context) {
    double videoHeight = MediaQuery.of(context).size.width * 9 / 16;
    
    return Scaffold(
      appBar: AppBar(title: Text('视频播放')),
      body: Column(
        children: [
          FView(
            player: player,
            width: double.infinity,
            height: videoHeight,
            color: Colors.black,
            fsFit: FFit.contain,
            fit: FFit.fill,
            panelBuilder: fPanelBuilder(
              title: '视频标题',
              subTitle: '视频副标题',
              isSnapShot: true,
              isVideos: true,
              videoList: videoList,
              videoIndex: videoIndex,
              speedList: speedList,
              isResolution: true,
              resolutionList: resolutionList,
              onError: () async {
                await player.reset();
                setVideoUrl(videoList[videoIndex].url);
              },
              onVideoEnd: () async {
                var index = videoIndex + 1;
                if (index < videoList.length) {
                  await player.reset();
                  setState(() => videoIndex = index);
                  setVideoUrl(videoList[index].url);
                }
              },
            ),
          ),
        ],
      ),
    );
  }

  @override
  void dispose() async {
    super.dispose();
    try {
      await ScreenBrightness().resetScreenBrightness();
    } catch (e) {
      print(e);
    }
    player.release();
  }
}

API 说明 #

FPlayer 主要方法 #

方法 说明
setDataSource(url, {autoPlay, showCover}) 设置视频源
start() 开始播放
pause() 暂停播放
stop() 停止播放
reset() 重置播放器
release() 释放播放器资源
seekTo(msec) 跳转到指定位置
setSpeed(speed) 设置播放速度
setVolume(volume) 设置音量
takeSnapShot() 截图(仅 iOS)
setOption(category, key, value) 设置播放器选项

FView 参数 #

参数 类型 说明
player FPlayer 播放器实例
width double 播放器宽度
height double 播放器高度
color Color 背景颜色
fit FFit 视频填充模式
fsFit FFit 全屏模式填充
panelBuilder FPanelWidgetBuilder 控制面板构建器

fPanelBuilder 参数 #

参数 类型 说明
title String 视频标题
subTitle String 视频副标题
isSnapShot bool 是否显示截图按钮
isVideos bool 是否显示视频列表
videoList List<VideoItem> 视频列表
videoIndex int 当前视频索引
speedList Map<String, double> 倍速列表
isResolution bool 是否显示清晰度
resolutionList Map<String, ResolutionItem> 清晰度列表
onError Function 错误回调
onVideoEnd Function 播放完成回调
onVideoPrepared Function 准备完成回调
onVideoTimeChange Function 进度变化回调

平台支持 #

平台 最低版本 推荐版本
Android API 21 (Android 5.0) API 24+
iOS iOS 12.0 iOS 13.0+

注意事项 #

iOS #

  • ⚠️ iOS 模拟器不支持视频播放,请使用真机测试
  • 需要在 Info.plist 中添加网络权限(如播放 HTTP 视频):
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

Android #

  • 需要在 AndroidManifest.xml 中添加网络权限:
<uses-permission android:name="android.permission.INTERNET"/>

花屏问题 #

如果在 Android 上遇到播放开始时花屏(1-2秒后恢复正常),可以尝试以下方案:

方案1:开启缓冲(推荐,首帧会变慢约1-2秒)

await player.setOption(FOption.playerCategory, "packet-buffering", 1);
await player.setOption(FOption.playerCategory, "min-frames", 25);

方案2:关闭硬件解码(最稳定,但耗电)

await player.setOption(FOption.playerCategory, "mediacodec", 0);

鸣谢 #

许可证 #

MIT License

支持作者 #

如果这个项目对你有帮助,欢迎请作者喝杯咖啡 ☕

微信            支付宝
微信 支付宝

联系方式 #

如有问题或建议,欢迎联系作者:📧 [email protected]

1
likes
0
points
418
downloads

Publisher

unverified uploader

Weekly Downloads

A Video Player Flutter plugin based on ijkplayer, support most popular protocols and codecs.

License

unknown (license)

Dependencies

battery_plus, flutter, plugin_platform_interface, screen_brightness

More

Packages that depend on td_fplayer

Packages that implement td_fplayer