• Stars
    star
    781
  • Rank 58,232 (Top 2 %)
  • Language
    Dart
  • License
    MIT License
  • Created over 5 years ago
  • Updated almost 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

ijkplayer for flutter

ijkplayer

pub package

ijkplayer,通过纹理的方式接入 bilibili/ijkplayer

使用前请完整阅读本 README 并参阅 example/lib/main.dart

有关 android 可能跑不起来的问题会详细解释

iOS 模拟器不显示图像,所以调试请使用真机(iOS10 iOS 12.1.4 亲测可用,其他版本有问题可反馈) android 模拟器 mac android sdk 自带的 emulator(API28 android9)可用,其他类型的没有亲测不保证

  • android: 我这里 sdk 自带的模拟器可用(音视频均正常)
  • iOS: 库中包含了真机和模拟器的库文件,但是模拟器有声音,无图像

在正式使用前,可以先 star 一下仓库, download 代码跑一下 example 尝试 (clone 也可以)

English Readme

https://github.com/CaiJingLong/flutter_ijkplayer/blob/master/README-EN.md

安装

pub package

最新版本请查看 pub

pubspec.yaml

dependencies:
  flutter_ijkplayer: ${lastes_version}

原生部分说明

自定义编译和原生部分源码

自定义编译的主要目的是修改支持的格式, 因为默认包含了一些编解码器,解复用,协议等等, 这些格式可能你的项目用不到, 这时候可以修改 ffmpeg 的自定义编译选项, 以便于可以缩小库文件的体积, 以达到给 app 瘦身的目的

当前的编译规则文件,修改编译选项,这个参考 bilibili/ijkplayerffmpeg,ffmpeg 的相关信息也可以通过搜索引擎获取

自定义编译选项的完整过程请看文档, 否则不保证编译出来的代码不报错, 具体的更改方案也请查看编译文档, 本篇不再提及

iOS

因为 iOS 部分代码的库文件比较大,为了方便管理版本, 所以创建了一个 pod 依赖托管 iOS 的 ijkplayer 库 pod 库托管在 github 仓库内 ,因为网速原因,源码托管在 azure

因为 framework 文件的大小超过了 100M,所以采用了压缩的方式储存 没有采用通用的 tar.gz 或 zip,而是使用 tar.xz 的方式压缩,这个压缩格式压缩率高,但是压缩和解压缩的的速度慢,综合考虑使用高压缩率的方式来快速获取源文件并解压缩
如果有朋友愿意提供 cdn 加速,可以联系我 😁

iOS 的原始代码来自于 https://github.com/jadennn/flutter_ijk 中提供的 iOS 代码, 但在这基础上有了修改, 不能直接使用这个仓库的源码, 修改后的项目源码托管在gitee

运行慢的问题

最新的 0.3.3 版本的 pod 库(版本号 0.1.0)库文件托管在 azure, 在美西下载速度可以达到 4~5M/s 只需要 20 秒左右就可以下载完, 10 多秒解压缩, 国内则会慢很多, 下载速度 1.5M/s 左右, 所以请耐心等待

0.3.2 以前的 pod 源码托管在 github, 国外下载速度能达到 5~6M/s, 国内速度则不足 100k, 所以可能需要 20 分钟, 建议没有用过这个库的人使用最新版本(0.3.3+)或使用代理

Android

现在的 ffmpeg 编译基本是参考的 GSYVideoPlayer中的 ex-so 的规则, 但当前项目的 c 语言源码有修改(截取视频帧), 所以你不能直接拿别的项目的 so 文件来用, 修改的内容可以在gitee查到

入门示例

import 'package:flutter_ijkplayer/flutter_ijkplayer.dart';


class HomePageState extends State<HomePage> {
  IjkMediaController controller = IjkMediaController();

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

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Plugin example app'),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.videocam),
            onPressed: _pickVideo,
          ),
        ],
      ),
      body: Container(
        // width: MediaQuery.of(context).size.width,
        // height: 400,
        child: ListView(
          children: <Widget>[
            buildIjkPlayer(),
          ]
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.play_arrow),
        onPressed: () async {
          await controller.setNetworkDataSource(
              'https://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_20mb.mp4',
              // 'rtmp://172.16.100.245/live1',
              // 'https://www.sample-videos.com/video123/flv/720/big_buck_bunny_720p_10mb.flv',
//              "https://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4",
              // 'http://184.72.239.149/vod/smil:BigBuckBunny.smil/playlist.m3u8',
              // "file:///sdcard/Download/Sample1.mp4",
              autoPlay: true);
          print("set data source success");
          // controller.playOrPause();
        },
      ),
    );
  }

  Widget buildIjkPlayer() {
    return Container(
      // height: 400, // 这里随意
      child: IjkPlayer(
        mediaController: controller,
      ),
    );
  }
}

使用

设置

每个 ijkplayer 对应一个 IjkMediaController;

IjkMediaController controller = IjkMediaController();

将 controller 设置给 ijkplayer

  var ijkplayer = IjkPlayer(
    mediaController: controller,
  );

关于销毁

用户在确定不再使用 controller 时,必须自己调用 dispose 方法以释放资源,如果不调用,则会造成资源无法释放(后台有音乐等情况),一般情况下,在 ijkplayer 所属的页面销毁时同步销毁

因为一个controller可能被多个IjkPlayer附着, 导致一个controller同时控制多个IjkPlayer,所以原则上不能与IjkPlayerdispose达成一致,所以这里需要调用者自行 dispose,

controller.dispose();

控制器的使用

设置资源

// 根据你的资源类型设置,设置资源本身是耗时操作,建议await

// 网络
await controller.setNetworkDataSource("https://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_20mb.mp4");

// 设置请求头, 使用headers参数
await controller.setNetworkDataSource(url, headers: <String,String>{});

// 应用内资源
await controller.setAssetDataSource("assets/test.mp4");

// 文件
await controller.setFileDataSource(File("/sdcard/1.mp4"));

// 预览相册视频, photo_manager 插件提供, 在androidQ/iOS下 数百m的video文件就不需要额外缓存即可使用, 可以节省储存空间
await controller.setPhotoManagerDataSource(await assetEntity.getMediaUrl());

// 通过数据源的方式, 这个方式的好处是可以将不同的数据混合到统一数据类型的List中
var dataSource = DataSource.file(File("/sdcard/1.mp4"));
var dataSource = DataSource.network("https://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_20mb.mp4", headers:<String,String>{});
var dataSource = DataSource.asset("assets/test.mp4");
var dataSource = DataSource.photoManagerUrl(await assetEntity.getMediaUrl());
await controller.setDataSource(dataSource);

// 还可以添加autoplay参数,这样会在资源准备完成后自动播放
await controller.setNetworkDataSource("https://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_20mb.mp4",autoPlay : true);

//或者也可以在设置资源完毕后自己调用play
await controller.setNetworkDataSource("https://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_20mb.mp4");
await controller.play();

播放器的控制

// 播放或暂停
await controller.playOrPause();

// 不管当前状态,直接play
await controller.play();

// 不管当前状态,直接pause
await controller.pause();

// 停止
// 这里要说明,ijkplayer的stop会释放资源,导致play不能使用,需要重新准备资源,所以这里其实采用的是回到进度条开始,并暂停
await controller.stop();

// 进度跳转
await controller.seekTo(0.0); //这里是一个double值, 单位是秒, 如1秒100毫秒=1.1s 1分钟10秒=70.0

// 进度跳转百分比
await controller.seekToProgress(0.0); //0.0~1.0

// 暂停其他所有的播放器(适用于ListView滚出屏幕或界面上有多个播放器的情况)
await controller.pauseOtherController();

// 设置媒体音量,这个可以用于做视频静音而不影响系统音量
controller.volume = 100; //范围0~100

// 设置系统音量
await controller.setSystemVolume(100); // 范围0~100

获取播放信息

  // 包含了一些信息,是否在播放,视频宽,高,视频角度,当前播放进度,总长度等信息
  VideoInfo info = await controller.getVideoInfo();

截取视频帧

视频帧的截图

Uint8List的格式导出,可以使用Image控件查看

var uint8List = await controller.screenShot();
var provider = MemoryImage(uint8List);
Widget image = Image(image:provider);

但是有 2 个问题:

  1. 这个和显示中的视频不总完全一样, 这个是因为截取的是解码后的完整视频帧, 可能比当前播放的略快 1~2 帧. 如果你不能接受这种不同步,请不要使用这个功能,或提交可行的 PR
  2. 硬解的情况下不支持截图, 因为只有软解码才有视频帧(这个问题我会在后面尝试解决, 但不保证实现时间)

在设置播放资源前设置软解码

资源监听

使用 stream 的形式向外广播一些信息的变化,原则上以 stream 结尾的属性都是可监听的

// 当纹理id发生变化时的回调,这个对于用户不敏感
Stream<int> textureIdStream = controller.textureIdStream;

// 播放状态的监听,true为正在播放,false为暂停
Stream<bool> playingStream = controller.playingStream;

// 当有调用controller.refreshVideoInfo()时,这个方法会回调,一般用于controllerUI的自定义,以便于监听当前信息(播放进度,播放状态,宽,高,方向变化等)
Stream<VideoInfo> videoInfoStream = controller.videoInfoStream;

// 音量的变化,这里需要注意,这个变化指的是当前媒体的音量变化,而不是系统的音量变化
Stream<bool> volumeStream = controller.playingStream;

// 当前Controller状态的监听,取值范围可以查看
Stream<IjkStatus> ijkStatusStream = controller.ijkStatusStream;

倍速播放

调用代码:

controller.setSpeed(2.0);

支持的倍率默认为 1.0, 上限不明,下限请不要小于等于 0,否则可能会 crash

变调的问题: 由于变速变调的问题, 如果需要不变调, 需要一个 option 的支持, 这个 option 默认开启, 如果要关闭这个, 可以使用如下代码

IjkMediaController(needChangeSpeed: false); // 这个设置为false后, 则变速时会声音会变调的情况发生

IjkStatus 说明

名称 说明
noDatasource 初始状态/调用reset()
preparing 设置资源中
setDatasourceFail 设置资源失败
prepared 准备好播放
pause 暂停
error 发生错误
playing 播放中
complete 播放完毕后
disposed 调用 dispose 后的状态

自定义 Option

**本功能可能会出问题,导致不能播放等等情况,**如果发现设置选项后不能使用或出现异常,请停止使用此功能

支持自定义 IJKPlayer 的 option,这个 option 会直接传输至 android/iOS 原生,具体的数值和含义你需要查看bilibili/ijkplayer的设置选项

但这个设置后的选项不是即时生效的 只有在你重新 setDataSource 以后才会生效

设置方法setIjkPlayerOptions

void initIjkController() async {
  var option1 = IjkOption(IjkOptionCategory.format, "fflags", "fastseek");// category, key ,value

  controller.setIjkPlayerOptions(
    [TargetPlatform.iOS, TargetPlatform.android],
    [option1].toSet(),
  );

  await controller.setDataSource(
    DataSource.network(
        "http://img.ksbbs.com/asset/Mon_1703/05cacb4e02f9d9e.mp4"),
    autoPlay: true,
  );
}

第一个参数是一个数组,代表了你 option 目标设备的类型(android/iOS)

第二个参数是一个Set<IjkOption>,代表了 Option 的集合,因为 category 和 key 均相同的情况下会覆盖,所以这里使用了 set

setIjkPlayerOptions对应的,还有一个addIjkPlayerOptions方法,区别在于 set 是会清空以前所有的配置选项, add 是添加, 只覆盖 category 和 key 均相同的配置选项

IjkOptionCategory

含义请查看 bilibili/ijkplayer 的说明或自行搜索

name
format
codec
sws
player
设置软解码

android 软解码的开启方式: 通过设置分类为 player, key 为 mediacodec, 值为 0

mediaController.setIjkPlayerOptions(
  [
    TargetPlatform.android,
  ],
  [
    IjkOption(IjkOptionCategory.player, "mediacodec", 0),
  ],
);

ios 对应的 key 则是 videotoolbox

mediaController.setIjkPlayerOptions(
  [
    TargetPlatform.ios,
  ],
  [
    IjkOption(IjkOptionCategory.player, "videotoolbox", 0),
  ],
);

释放资源

await controller.reset(); // 这个方法调用后,会释放所有原生资源,但重新设置dataSource依然可用

await controller.dispose(); //这个方法调用后,当前控制器理论上不再可用,重新设置dataSource无效,且可能会抛出异常,确定销毁这个controller时再调用

自定义控制器 UI

使用IJKPlayercontrollerWidgetBuilder属性可以自定义控制器的 UI,默认使用defaultBuildIjkControllerWidget方法构建

签名如下: typedef Widget IJKControllerWidgetBuilder(IjkMediaController controller);

返回的 Widget 会被覆盖在 Texture 上

IJKPlayer(
  mediaController: IjkMediaController(),
  controllerWidgetBuilder: (mediaController){
    return Container(); // 自定义
  },
);

内置的播放器 UI 使用的类为: DefaultIJKControllerWidget

这个类提供了一些属性进行自定义, 除controller外所有属性均为可选:

name type default desc
doubleTapPlay bool false 双击播放暂停
verticalGesture bool true 纵向手势
horizontalGesture bool true 横向手势
volumeType VolumeType VolumeType.system 纵向手势改变的声音类型(系统,媒体)
playWillPauseOther bool true 播放当前是否暂停其他媒体
currentFullScreenState bool false 如果你是自定义全屏界面, 这个必须设置为 true
showFullScreenButton bool true 是否显示全屏按钮
fullscreenControllerWidgetBuilder IJKControllerWidgetBuilder 可以自定义全屏的界面
fullScreenType FullScreenType 全屏的类型(旋转屏幕,或是使用 RotateBox)
hideSystemBarOnFullScreen bool true 进入全屏时,是否自动隐藏状态栏(请看额外说明 1)
onFullScreen void Function(bool) null 全屏状态改变时的回调, 参数为 true 是全屏状态, false 为普通状态

额外说明 1: ios 需要向 Info.plist 添加一条属性

<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>

自定义纹理界面

使用textureBuilder属性自定义纹理界面,在 0.1.8 和之前的版本该属性名是playerBuilder

默认的方法buildDefaultIjkPlayer接受 context,controller,videoInfo 参数返回 Widget

IJKPlayer(
  mediaController: IjkMediaController(),
  textureBuilder: (context,mediaController,videoInfo){
    return Texture(); // 自定义纹理界面
  },
);

根据当前状态构建一个 widget

根据 Controller 当时 IjkStatus 的值构建 Widget,这个 Widget 会根据当前 status 变化而呈现出不同的界面

Widget buildIjkPlayer() {
  return IjkPlayer(
    mediaController: mediaController,
    stateWidgetBuilder: _buildStatusWidget,
  );
}

Widget _buildStatusWidget(
  BuildContext context,
  IjkMediaController controller,
  IjkStatus status,
) {
  if (status == IjkStatus.noDatasource) {
    return Center(
      child: Text(
        "no data",
        style: TextStyle(color: Colors.white),
      ),
    );
  }

  // you can custom your self status widget
  return IjkStatusWidget.buildStatusWidget(context, controller, status);
}

进度

目前正处于初始开发阶段,可能有各种问题,欢迎提出,但不一定会实现,也不一定会修改 😌

最初准备参考官方 video_player 的 api 方式进行开发,但是觉得调用的方式比较奇怪

需要自定义 LifeCycle 进行管理,而且自定义控制器不太方便,遂决定重写 api 的代码结构,同时清晰逻辑

目前属于公开测试使用阶段,不保证不出 bug,也不保证今后 api 不发生重大变更

目前的进度可以查看TODOLIST

UI 控制功能包含常见的播放停止,手势拖动

LICENSE

MIT

More Repositories

1

flutter_photo

Pick image/video from album by flutter. Support ios and android. UI by flutter, no native.
Dart
303
star
2

json2dart

Dart
128
star
3

dart_image_size_getter

Use dart file api to get image size, needn't use decode. just read the metadata.
Dart
61
star
4

flutter_page_indicator

Dart
46
star
5

flutter_city_picker

Dart
37
star
6

flutter_load_widget

Dart
35
star
7

BuildGoForAndroid

This project demonstrates how to compile the go source code into a dynamic library for Android and use it in Android.
C
24
star
8

example_for_flutter_ffi

create a example for https://flutter.dev/docs/development/platform-integration/c-interop .
CMake
23
star
9

python_get_city_datas

爬取中国省市资料
Python
22
star
10

add_flutter_to_exists_ios_example

Objective-C
21
star
11

flutter_like_wechat_input

flutter 仿微信聊天输入框 没有单独写插件 建议复制代码和资源 经轻度修改和封装以在自己的项目中使用
Dart
20
star
12

flutter_gps

Dart
15
star
13

flutter_vertical_marquee

flutter vertical marquee
Dart
15
star
14

flutter_dialog_examples

Dart
14
star
15

clean_flutter_builds

批量清理flutter的构建文件
Dart
14
star
16

flutter_long_tap_menu

Dart
12
star
17

upload_flutter_aar_to_maven

Dart
10
star
18

log4d

Dart's log packages, in order to support long logs and coloring, can accept logs and save them on the desktop through simple cli.
Dart
9
star
19

m3u8_download

Use dart write, support linux and macOS, no support live stream.
Dart
8
star
20

flutter_provide_example

Dart
8
star
21

flutter-go-example

Dart
8
star
22

picgo-plugin-azure

TypeScript
6
star
23

flutter_bluetooth_spp

bluetooth spp for flutter, only support android.
Kotlin
6
star
24

image_region_decoder

Use the platform API to partially load the image
Dart
6
star
25

ok_route

Dart
5
star
26

example_flutter_plugin_local_maven_aar

How to write flutter plugin when SDK only provides aar file.
Ruby
5
star
27

flutter-wanandroid

wanandroid with flutter
Dart
5
star
28

flutter_index_widget

Dart
4
star
29

find_env_shell

Configure different environment for each project.
Shell
4
star
30

Flutter-FixImage

A Image Widget that can be used with BoxFit.
Dart
4
star
31

flutter_sub_navigator_example

Example of inserting a secondary routing node.
Dart
4
star
32

flutter_bluetooth_ble

bluetooth ble, support android/ios.
Dart
4
star
33

bmff

The package provides a library for reading ISO Base Media File Format (BMFF) files.
Dart
3
star
34

copy_with_for_dart

Dart
3
star
35

action_auto_label

TypeScript
3
star
36

flutter_ijkplayer_pod

Shell
3
star
37

amap_base_flutter

高德地图&导航flutter插件 基于AndroidView和UiKitView,可以嵌入Widget树中。
Dart
3
star
38

buff

A buffer for dart
Dart
3
star
39

md_picture_migrate_cli

Dart
2
star
40

action-dart-compile

2
star
41

android-cameraX-example

Kotlin
2
star
42

flutter_mvvm_demo

Dart
2
star
43

flutter_route_anim_example

Page Transition of flutter, use pageTransitionsTheme and PageTransitionsBuilder.
Dart
2
star
44

pdf_kt

Wrap pdf of itext
Kotlin
2
star
45

dart_project

Dart
2
star
46

dart_hashcodes

Dart
2
star
47

localization_error_example

Dart
2
star
48

github_auth

HTML
2
star
49

flutter_plugin_example

一个 flutter的插件示例 http://www.kikt.top/posts/flutter/channel/flutter-channel1/
Dart
2
star
50

Android-CustomRatingBar

a custom rating bar
Java
2
star
51

ios_swipe_gesture_example

ios原生和flutter侧滑退出手势的处理
Objective-C
2
star
52

action-version-merge

TypeScript
1
star
53

dart_datetime_helper

Dart
1
star
54

codable-generator-python

coable generator python3
Python
1
star
55

ios-viewctl-modal-anim

Simple left and right translation, switch animation
Swift
1
star
56

add_flutter_to_exists_android

Dart
1
star
57

gradle_wrapper_downloader

一个代理下载 gradle wrapper 的下载器
Dart
1
star
58

dart-unix-exec

Dart
1
star
59

libvips_android_script

How to compile libvips libraries for android with conan.
Python
1
star
60

Android-BluetoothLibrary

Kotlin
1
star
61

flare_1.5.0_example

Dart
1
star
62

flutter_desktop_example_1

Dart
1
star
63

Android-ReboundScrollView

Java
1
star
64

log4d-doc

1
star
65

flutter_frame_stack_example

Dart
1
star
66

JavaFX-tornadofx-template

JavaFx tornadofx template (gradle)
Kotlin
1
star
67

excel_kt

Kotlin
1
star
68

analyzer_example

Simple example for use analyzer to convert dart code.
Dart
1
star
69

dingtalk_bot_sender

钉钉机器人发送聊天消息的 dart 库
Dart
1
star
70

qwik-tauri-app-template

A template for tauri and qwik
TypeScript
1
star
71

subscription_cli

You can download or execute tasks through custom rules.
Dart
1
star
72

Flutter_IndexStack_Lazy_init_example

Dart
1
star
73

ios-refresh-loadmore-tableview

simple refresh loadmore tableview
Swift
1
star
74

upload_image

Upload image for blog or other, now support azure.
Dart
1
star
75

androidview-notch-error

Dart
1
star
76

FoldTextView

Java
1
star
77

flutter_umeng_statistics

Java
1
star
78

KRecyclerViewAdapter

have scroll load more 's recyclerview adapter
Kotlin
1
star
79

swift-image-gen

generator image struct for swift
Python
1
star
80

flutter-ocproject-use-swift-plugin

Dart
1
star
81

android_compile_ffmpeg4_example

C
1
star
82

tauri-umijs-template

A template for tauri + umijs
TypeScript
1
star
83

flutter_form_example

Example of flutter form.
Dart
1
star