当前位置: 首页 > news >正文

【Flutter】双路视频播放方案

最近在做双路视频播放,就是在一个页面播放两个视频。我遇到的问题就是音频焦点冲突问题,在下面说明。

什么是双路视频播放(来自AI)

双路视频播放(Dual-Video Playback),从字面上理解,就是指在一个屏幕或应用界面上,同时解码和渲染两个独立的视频流

可以把它想象成有两列火车在两条并行的轨道上同时行驶,你可以同时看到两列火车的状态。这两个视频流可以有多种关系和布局方式。

核心特征

  1. 两个独立的视频源: 这不是将一个视频画面分割成两半,而是实实在在地处理两个不同的视频文件或网络流。例如,一个是 video_A.mp4,另一个是 video_B.mp4

  2. 同时播放: 两个视频在时间上是同步或并行播放的。播放/暂停/快进等操作可能联动控制两个视频,也可能允许独立控制。

  3. 精确同步(关键特性): 在很多场景下,双路视频播放的难点和核心在于保持两个视频画面的精确时间同步。例如,如果视频A的第5秒100毫秒对应的是视频B的第5秒100毫秒,那么在播放时必须保证它们始终对齐,不能出现一个快一个慢的情况。

  4. 灵活的布局: 两个视频的画面可以有多种呈现方式:

    • 画中画 (Picture-in-Picture, PiP):一个小视频窗口悬浮在一个大视频窗口之上。
    • 左右分屏 (Side-by-Side):屏幕一分为二,左边播放一个视频,右边播放另一个。
    • 上下分屏 (Top-and-Bottom):屏幕一分为二,上边播放一个视频,下边播放另一个。
    • 叠加融合 (Overlay/Blending):一个视频作为背景,另一个半透明地叠加在上面。

常见的应用场景

双路视频播放技术非常有价值,因为它能提供单一视频无法实现的信息维度和交互体验。

应用领域具体场景描述示例
在线教育/网络课程一路视频播放老师的讲课画面,另一路同步播放课件PPT或屏幕操作的录像。网易云课堂、Coursera等平台,老师头像在角落,主屏幕是课件。
视频剪辑/后期制作在调色或添加特效时,一路播放原始素材,另一路实时播放处理后的效果,方便进行对比。Adobe Premiere Pro, Final Cut Pro 中的对比视图功能。
体育赛事直播/分析一路播放赛场的全景视角,另一路播放某个运动员的特写视角或精彩回放。足球比赛中,同时展示球场全景和某个球星的个人镜头。
安防监控在一个屏幕上同时显示来自不同摄像头的实时监控画面。大楼的安保中心,监控墙上显示着多个区域的实时视频。
无障碍功能 (Accessibility)一路播放主视频内容,另一路在角落同步播放手语翻译的视频。很多新闻发布会或官方视频会提供手语翻译版本。
3D/VR/360°视频这是一种特殊形式的双路视频,系统为左眼和右眼分别渲染一个视频流,从而创造出立体感和沉浸感。YouTube VR, Oculus TV 等 VR 应用。
互动视频/游戏允许用户在不同视角或故事线之间切换,系统在后台可能需要同时准备好多个视频流以实现无缝切换。一些互动电影或真人游戏。

技术挑战

实现稳定流畅的双路视频播放并非易事,尤其是在移动端。

  1. 性能消耗巨大: 解码两个视频流(尤其是高清视频)需要双倍的CPU/GPU计算资源。这会显著增加设备的功耗、发热量,并可能导致卡顿或掉帧。这也是为什么你之前会遇到内存溢出等问题的原因之一,处理双路视频对内存管理的要求更高。

  2. 同步难题: 保持两个视频流的精确同步是一个巨大的挑战。网络延迟的抖动(Jitter)、解码速度的差异都可能导致音画或两个画面之间出现偏移。需要复杂的时钟同步机制来校准。

  3. 音轨处理: 两个视频通常都有自己的音轨。如何处理音频?

    • 只播放其中一个视频的音频?
    • 将两个音轨混合(Mix)在一起?
    • 让用户自己选择听哪一个?
      这都需要在产品设计和技术实现上仔细考虑。
  4. 复杂的播放器控制逻辑: 一个播放器现在需要管理两个视频源的状态,播放/暂停、快进/快退、缓冲状态、错误处理等逻辑都变得复杂了一倍。

总而言之,双路视频播放是一项强大的功能,它通过在同一时间呈现更多维度的视觉信息,极大地丰富了应用的功能和用户体验,但同时也对应用的性能优化和技术实现提出了更高的要求。

 

初方案

`video_player` 插件

创建两个独立的 `VideoPlayerController` 实例,分别控制两个视频的播放。

代码

写在开头,重点就是被注释掉的那句,其实没必要往下看。

    VideoPlayerController controller1 = VideoPlayerController.networkUrl(Uri.parse(videoUrl),//videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true), //是的,一开始没加这句!!!这就是问题所在);VideoPlayerController controller2 = VideoPlayerController.networkUrl(Uri.parse(videoUrl),//videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true),);

 组件代码,只是简单的模拟

@override
Widget build(BuildContext context) {return Scaffold(body: Center(child: Row(children: <Widget>[Expanded(child: _controller1.value.isInitialized? AspectRatio(aspectRatio: _controller1.value.aspectRatio,child: VideoPlayer(_controller1), //这里): Container(),),Expanded(child: _controller2.value.isInitialized? AspectRatio(aspectRatio: _controller2.value.aspectRatio,child: VideoPlayer(_controller2),//这里): Container(),),],),),floatingActionButton: FloatingActionButton(onPressed: () {togglePlayPauseBoth();},child: Icon(_controller1.value.isPlaying ? Icons.pause : Icons.play_arrow,),),);
}void setVolumeBoth(double volume) {controller1?.setVolume(volume);  //注意这里少了一个}void togglePlayPauseBoth() {final bool isPlaying = controller1?.value.isPlaying ?? false;if (isPlaying) {pauseBoth();} else {playBoth();}}void playBoth() {controller1?.play();controller2?.play();}void pauseBoth() {controller1?.pause();controller2?.pause();}void seekBoth(Duration position) {controller1?.seekTo(position);controller2?.seekTo(position);}

问题描述

点击播放只有第一个视频播放,而且播放按钮play_arrow -> pause -> play_arrow。

原因分析

经过了一些不必要的弯路,我终于看到了日志

D/AudioManager(31189): dispatching onAudioFocusChange(-1) ...

 这一行日志就是问题的“确凿证据”。它告诉我们,系统正在向您的应用发送一个“音频焦点丢失” (AUDIOFOCUS_LOSS) 的通知。

问题根源:音频焦点冲突

  1. 什么是音频焦点? 在Android系统中,为了避免多个应用同时播放声音造成混乱,只有一个应用可以在同一时间“持有”音频焦点。
  2. 发生了什么? 当您调用 playBoth() 时,视频播放器1(controller1)和视频播放器2(controller2同时向系统请求音频焦点。
  3. 系统如何反应? Android系统看到来自同一个应用的第二个音频请求,会认为第一个请求应该被放弃。因此,它会立即给第一个请求者发送一个AUDIOFOCUS_LOSS通知。
  4. video_player插件的默认行为video_player插件在收到“音频焦点丢失”的通知后,会非常“懂事”地自动暂停播放。

其他方案

1、使用 `multi_video_player` 插件
2、使用 `video_player_mux` 插件

 怎么使用我也只看了官网例子,没有实践,有空补上。

一些废话,记录bug解决过程

没有发日志之前AI越走越弯 

问题1:

 一开始这里出现的问题是点击播放只有第一个视频播放,而且播放按钮play_arrow -> pause -> play_arrow。

一开始没给AI日志信息,所以分析是两个控制器状态不统一,给出了解决方案1。

解决方案1:

核心是将播放/暂停的命令统一处理,并建立一个单向的同步机制:始终以后置视频的状态为准,强制前置视频跟随。

问题2:

由于上诉修改产生了问题2。因为强制两个视频状态同步,主打同生共死,所以两个视频他们一起停了,按钮play_arrow -> pause -> play_arrow。

解决方案2:

撤回解决方法1。

后面还在ai的指导下尝试了

1、将一个视频静音---->没用。

2、只播放一个视频永远只让一个播放器(主播放器)真正执行play()pause()操作,另一个播放器(从播放器)只通过seekTo()来被动地同步画面,从而绝不请求音频焦点。---->卡顿非常明显,pass。

 

http://www.dtcms.com/a/309025.html

相关文章:

  • 《R for Data Science (2e)》免费中文翻译 (第3章) --- Data transformation(1)
  • Jupyter Notebook 使用指南
  • Idea集成Jenkins Control插件,在IDEA中触发Jenkins中项目的构建
  • 【数据可视化-78】2025年上半年广东省各市GDP排名深度解析与可视化:Python + Pyecharts 深度洞察(含完整数据、代码)
  • 【Linux学习|黑马笔记|Day1】Linux初识、安装VMware Workstation、安装CentOS7、远程连接、虚拟机快照
  • Cradle:颠覆AI Agent 操作本地软件,AI驱动的通用计算机控制框架,如何让基础模型像人一样操作你的电脑?
  • 九、Maven入门学习记录
  • 嵌入式筑基之STM32启动流程
  • AG-UI 协议全面解析--下一代 AI Agent 交互框架医疗应用分析(上)
  • SQL注入SQLi-LABS 靶场less25a-28a详细通关攻略
  • LoRA低秩适配的原理
  • anaconda searchanaconda show | conda 检索包资源安装指定版本包指定源安装命令package
  • Mysql-视图,函数,存储过程,触发器
  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段(12):文法+单词
  • conda issue
  • C++-2025.7.31
  • LaTeX 表格制作全面指南
  • js防抖、节流和扁平化实现
  • 链特异性文库是什么?为什么它在转录组测序中越来越重要?
  • 【Kubernetes 指南】基础入门——Kubernetes 201(三)
  • 第13届蓝桥杯C++青少组中/高级组选拔赛2022年3月13日真题
  • pdw估计edw怎么估计
  • 数据结构: 双向链表
  • Servlet修改新增思路
  • 数据大集网:引领精准获客新时代的优质平台
  • 数据结构:多项式加法(Polynomial Addition)
  • 从零开始搞定类和对象(上)
  • Python 环境配置
  • 【科普】贝叶斯神经网络与分形神经网络
  • 0731 IO进程基础