MTVF — Flutter 开发视频播放器实现超分辨率
MTVF — Flutter 开发视频播放器实现超分辨率
现在网站视频大都来源采集站,视频画质倍严重压缩。但是我们可以通过超分辨率技术来改善画质。文章介绍如何使用 Flutter 的 media_kit 插件开发视频播放器,并结合 GLSL 实现超分辨率。
效果预览
下面是 MTVF.app 利用 media_kit + glsl 实现的视频播放器,可设置不同的超分策略:

Flutter
Flutter 是由 Google 开发的一个开源UI软件开发工具包,首次发布于2017年。它使用Dart 语言作为开发语言,并通过自绘引擎(Skia)渲染UI,能够在多个平台上创建高性能、高保真的应用程序,包括移动端(iOS、Android)、Web、桌面端(Windows、macOS、Linux)以及嵌入式设备。
MPV + GLSL 超分辨率
MPV 是跨平台开源播放器,支持加载 GLSL 着色器(Shader) 做实时视频后处理(放大、锐化、降噪、色彩)。GLSL:OpenGL Shading Language,在 GPU 上并行运行的小程序,用来逐像素处理画面。
MPV 把视频帧当成纹理传给 GPU → GLSL 着色器对每个输出像素做:
- 分析邻域像素
- 用算法 / 模型重建高分辨率细节
- 输出放大 + 清晰化的帧
常用超分 Shader(MPV 生态)
- Anime4K(动漫专用):线条强化、边缘修复、x2/x4 放大,轻量快
- AMD FSR(通用):EASU 放大 + RCAS 锐化,全显卡兼容
- NVIDIA NIS:类似 FSR,N 卡优化
- RAVU / NNEDI3:AI 向,质量极高、性能开销大
- SuperXBR:边缘保护强,适合像素风、老动画
media_kit
media_kit 是一个强大的跨平台音视频播放解决方案,支持 Android、iOS、macOS、Windows、Linux 和 Web 平台。它基于 Dart 实现,底层依赖 FFmpeg 和 libmpv,提供高性能、可定制的播放体验,适用于多种场景。
核心功能
- 支持多种格式:支持 MP4、MP3、MKV、FLV、HLS、DASH 等格式。
- 硬件加速:默认启用 GPU 渲染,支持 4K/8K 视频播放。
- 高级功能:支持字幕、音轨切换、画中画模式、后台播放等。
- 跨平台一致性:提供统一的 API 接口,适配多平台。
- 自定义能力:支持自定义视频渲染控件和播放控制。
实现流程
利用 media_kit 插件的 libmpv 模式加载 GLSL 实现超分辨率
添加依赖
这里要使用Predidit 改进的 media_kit,在项目中添加如下依赖:
dependencies:
media_kit:
git:
url: https://github.com/Predidit/media-kit.git
ref: 4cd7c29566da395229c398d2ec4d0ef96b5e8970
path: ./media_kit
media_kit_video:
git:
url: https://github.com/Predidit/media-kit.git
ref: 4cd7c29566da395229c398d2ec4d0ef96b5e8970
path: ./media_kit_video
media_kit_libs_video:
git:
url: https://github.com/Predidit/media-kit.git
ref: 4cd7c29566da395229c398d2ec4d0ef96b5e8970
path: ./libs/universal/media_kit_libs_video
dependency_overrides:
media_kit_libs_ios_video:
git:
url: https://github.com/Predidit/media-kit.git
ref: 4cd7c29566da395229c398d2ec4d0ef96b5e8970
path: ./libs/ios/media_kit_libs_ios_video
media_kit_libs_android_video:
git:
url: https://github.com/Predidit/media-kit.git
ref: 4cd7c29566da395229c398d2ec4d0ef96b5e8970
path: ./libs/android/media_kit_libs_android_video
media_kit_libs_ohos:
git:
url: https://github.com/Predidit/media-kit.git
ref: 4cd7c29566da395229c398d2ec4d0ef96b5e8970
path: ./libs/ohos/media_kit_libs_ohos
- 完整依赖见 Kazumi | pubspec.yaml
添加 GLSL
在项目根目录下创建 assets/shaders 文件夹,添加 shaders/xxx.glsl 文件,并在 pubspec.yaml 中添加如下配置:
flutter:
assets:
- assets/shaders/
加载 GLSL
软件启动时,将 assets/shaders 文件夹下的 GLSL 文件复制到手机 /data/data/com.example.app/files/shaders 文件夹下:
import 'dart:io';
import 'package:mtvf/utils/log_util.dart';
import 'package:path/path.dart' as path;
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
class ShadersUtil {
static final ShadersUtil _singleton = ShadersUtil._internal();
factory ShadersUtil() => _singleton;
ShadersUtil._internal();
late Directory shadersDirectory;
Future<void> copyShadersToExternalDirectory() async {
final assetManifest = await AssetManifest.loadFromAssetBundle(rootBundle);
final assets = assetManifest.listAssets();
final directory = await getApplicationSupportDirectory();
shadersDirectory = Directory(path.join(directory.path, 'shaders'));
if (!await shadersDirectory.exists()) {
await shadersDirectory.create(recursive: true);
Log.logger('ShaderManager: Create GLSL Shader: ${shadersDirectory.path}');
}
final shaderFiles = assets.where(
(String asset) => asset.startsWith('assets/shaders/') && asset.endsWith('.glsl'),
);
int copiedFilesCount = 0;
for (var filePath in shaderFiles) {
final fileName = filePath.split('/').last;
final targetFile = File(path.join(shadersDirectory.path, fileName));
if (await targetFile.exists()) {
Log.logger('ShaderManager: GLSL Shader exists, skip: ${targetFile.path}');
continue;
}
try {
final data = await rootBundle.load(filePath);
final List<int> bytes = data.buffer.asUint8List();
await targetFile.writeAsBytes(bytes);
copiedFilesCount++;
Log.logger('ShaderManager: Copy: ${targetFile.path}');
} catch (e) {
Log.logger('ShaderManager: Copy: ($filePath), $e');
}
}
Log.logger('ShaderManager: $copiedFilesCount GLSL files copied to ${shadersDirectory.path}');
}
}
定义 glsl 枚举,便于切换:
enum MVPShader {
off('关闭', []),
anime4kHighQuality('高质量', [
'Anime4K_Clamp_Highlights.glsl', // 保留抗振铃,可选移除(再省10%性能)
'Anime4K_Restore_CNN_M.glsl', // 降级VL→M(耗时从20ms→5ms)
'Anime4K_Upscale_CNN_x2_M.glsl', // 降级VL→M(核心Upscale)
'Anime4K_AutoDownscalePre_x2.glsl', // 仅保留2x降采样(移除x4,省显存)
'Anime4K_Upscale_CNN_x2_S.glsl', // 第二层Upscale降级为S(进一步控耗时)
]),
anime4kBalanced('均衡版', [
'Anime4K_AutoDownscalePre_x2.glsl', // 智能降采样预处理
'Anime4K_Upscale_CNN_x2_M.glsl', // Anime4K 中档超分(x2,平衡画质与性能)
'Anime4K_Restore_CNN_M.glsl', // CNN 细节修复(M 级,适度增强)
'Adaptive_sharpen_lite_RT.glsl', // 自适应锐化(轻量版,补充细节)
]),
anime4kLightWeight('轻量版', [
'Anime4K_Clamp_Highlights.glsl', // 可选移除(追求极致流畅)
'Anime4K_Restore_CNN_M.glsl', // 仅保留单次Restore(移除重复的S级)
'Anime4K_Upscale_CNN_x2_M.glsl', // 核心Upscale用M级保画质
'Anime4K_AutoDownscalePre_x2.glsl', // 移除x4(移动端无用)
'Anime4K_Upscale_CNN_x2_S.glsl', // 第二层Upscale用S级控耗时
]),
// ==================== 手机端超分组合推荐 ====================
mobileLite('日常版', [
'AMD_FSR1_lite_RT.glsl', // AMD FSR1 轻量版(性能优先,适合日常观看)
'Adaptive_sharpen_lite_luma_RT.glsl', // 轻度锐化(Luma 优化,低功耗)
]),
mobileHDR('HDR 增强', [
'AMD_FSR1_EASU.glsl', // AMD 边缘自适应超分(EASU 独立版,画质优秀)
'AMD_FSR1_RCAS_glsl', // AMD 锐化(补偿 EASU 的柔和)
'Adaptive_sharpen_RT.glsl', // 二次锐化(强化细节)
]),
// ==================== 强效画质增强组合(推荐用于真人电影) ====================
movieSharpUltra('强锐化版', [
'FSRCNNX_x2_16_0_4_1.glsl', // FSRCNN 高阶超分(x2,16 通道,画质最强)
'Adaptive_sharpen_RT.glsl', // 全量自适应锐化(强力增强细节)
'AMD_CAS_AIO_RT.glsl', // AMD 对比度自适应锐化(全功能版,增强清晰度)
]),
movieDetailPlus('细节增强版', [
'AiUpscale_Fast_2x_Photo_RT.glsl', // AI 照片/实拍视频超分(快速版,针对实拍优化)
'USM.glsl', // 反锐化掩模(传统但有效的细节增强)
'AMD_FSR1_RCAS_RT.glsl', // 后期锐化补偿
]),
movieCinemaPro('专业影院版', [
'ArtCNN_C4F32_i2.glsl', // ArtCNN 高质量超分(C4F32,电影级画质)
'Adaptive_sharpen_RT.glsl', // 精细锐化
'colorlevel_expand.glsl', // 色彩层次扩展(增强电影感)
]),
final List<String> value;
final String label;
const MVPShader(this.label, this.value);
static MVPShader from(int index) {
return MVPShader.values[index];
}
}
使用 media_kit 加载 glsl:
/// 构建着色器绝对路径
String buildShadersAbsolutePath(String baseDirectory, List<String> shaders) {
List<String> absolutePaths = shaders.map((shader) {
return path.join(baseDirectory, shader);
}).toList();
if (Platform.isWindows) {
return absolutePaths.join(';');
}
return absolutePaths.join(':');
}
/// 设置着色器
Future<void> setShader(List<String> shaders) async {
var pp = mediaPlayer!.platform as NativePlayer;
await pp.waitForPlayerInitialization;
await pp.waitForVideoControllerInitializationIfAttached;
if (shaders.isEmpty) {
await pp.command(['change-list', 'glsl-shaders', 'clr', '']);
Log.logger('清空着色器');
return;
}
final shaderString = PlayerUtils().buildShadersAbsolutePath(ShadersUtil().shadersDirectory.path, shaders);
try {
await pp.command(['change-list', 'glsl-shaders', 'set', shaderString]);
Log.logger('着色器设置成功: $shaderString');
} catch (e) {
Log.logger('执行失败: $e');
}
}
除了实现超分,glsl还可以实现镜像和视觉辅助效果:
mirrorRT('镜像', ['Mirror_RT.glsl']),
protanopia('红/绿滤镜', ['Protanopia.glsl']),
deuteranopia('绿/红滤镜', ['Deuteranopia.glsl']),
tritanopia('蓝/黄滤镜', ['Tritanopia.glsl']),
grayscale('黑/白滤镜', ['Grayscale.glsl']);
依赖数据
文章使用的 glsl 可在 MTVF | shaders 下载。 更多的 glsl 可在 Anime4K 与 mpv_PlayKit获取。
参考文献
[1] Predidit | media-kit:改进的 media-kit 插件。
[2] Predidit | Kazumi:一款使用 Flutter 开发的基于自定义规则的番剧采集与在线观看程序。
[3] MTVF | shaders:MTVF 使用的 glsl 集合。
更多推荐


所有评论(0)