现在网站视频大都来源采集站,视频画质倍严重压缩。但是我们可以通过超分辨率技术来改善画质。文章介绍如何使用 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

添加 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 可在 Anime4Kmpv_PlayKit获取。

参考文献

[1] Predidit | media-kit:改进的 media-kit 插件。
[2] Predidit | Kazumi:一款使用 Flutter 开发的基于自定义规则的番剧采集与在线观看程序。
[3] MTVF | shaders:MTVF 使用的 glsl 集合。

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐