THMonster / Revda

Tools to play live stream with danmaku.
GNU General Public License v2.0
214 stars 12 forks source link

直播下播后,对应的 dmlive 和 mpv 进程退出了,但是 ffmpeg 进程却没有正常退出。 #49

Closed unisgn closed 1 year ago

unisgn commented 1 year ago

这个问题通常在主播下播后,或主播网络断了重新开播的情况下发生,不容易捕捉复现的条件,但是有一种人工触发的方式: 打开一个直播,在任务管理器里先杀掉 ffmpeg 进程,此时 ffmpeg 进程会重新启动,然而 mpv 只会重复播放缓冲区的内容,然后再杀掉 mpv 进程,dmlive 进程会退出,但是 ffmpeg 进程会一直保留。

有一个临时解决办法是在 dmlive/src/ffmpeg/mod.rs::FfmpegControl.run 方法里创建 ffmpeg 进程的时候,将 kill_on_drop(false) 改为 killl_on_drop(true),但是我不太明白这样做会不会有其他副作用。

另外想请教下,当 ffmpeg 进程被杀掉或意外终止的时候,为啥不直接关掉 mpv 终止 dmlive 呢,好让用户及早知道出现了异常,却选择了重新启动 ffmpeg 进程呢?因为即使重新启动了 ffmpeg 进程,mpv 里始终都是在重复播放缓冲区的内容,对用户而言反而成了负担,因为可能看了半天才发现在重复播放,意识到出现了异常,而程序又不能自动纠错,只能自己关掉 mpv 重新打开。

THMonster commented 1 year ago

打开一个直播,在任务管理器里先杀掉 ffmpeg 进程,此时 ffmpeg 进程会重新启动,然而 mpv 只会重复播放缓冲区的内容

不应该是这样啊?正常情况下你这样杀了ffmpeg和按alt+r是一样的,为什么你只会重复播放缓冲区的内容?

THMonster commented 1 year ago

你是不是mpv有什么特殊的设置?我这杀了ffmpeg或者ffmpeg出了什么问题(通常是直播流出了问题,像断流或者下播)是会自动刷新的(就和alt+r)一样,这也是预期的状态。我刚也试了好几次,都正常工作的呀。

THMonster commented 1 year ago

等等,你说的这个:

然而 mpv 只会重复播放缓冲区的内容

确定是在重复播放缓冲区的内容,还是dmlive在疯狂刷新?

你提及的那段代码,我记得好像就是为了解决某个race condition(它所表现出的现象就是dmlive无法停止地刷新,而这种情况有点像你所说的“mpv 只会重复播放缓冲区的内容“)。

你换成原版的dmlive也有这个问题吗?

unisgn commented 1 year ago

你是不是mpv有什么特殊的设置?我这杀了ffmpeg或者ffmpeg出了什么问题(通常是直播流出了问题,像断流或者下播)是会自动刷新的(就和alt+r)一样,这也是预期的状态。我刚也试了好几次,都正常工作的呀。

确实,我的 mpv 里设置了 loop=inf,这应该就是导致重复播放缓冲区内容的原因。

以下内容的前提是去掉了这个设置。

我现在大概了解为啥您会让在 ffmpeg 遇到异常的时候,重新启动 ffmpeg 进程,大概是为了在遇到断流或网络异常时,可以自动尝试刷新,然而对这个策略,我想提两个问题:

1,正常播放情况下,我用杀掉 ffmpeg 进程的方式模拟断流或网络异常的方式,期待的效果是 mpv 会先静止下来,待 ffmpeg 重启后,mpv 会恢复正常播放,然而我这里的实际情况是 mpv 一直处于静止画面,即使进程里已经看到 ffmpeg 重新起来了。换句话说,这个策略没有起到效果。不知道这个情况属于预期的情况,还是我的操作不当。 2,这个策略大概主要是为了应对断流或网络异常,然而却对下播的情况产生了副作用。期待的效果是,主播下播了,mpv 窗口自动关闭,dmlive, ffmpeg 进程自动终止。然而实际效果是,由于无法判断是下播了还是临时断流了,ffmpeg 会不断尝试刷新, mpv 窗口也会一直开着,需要用户自行关闭,这也无可厚非,但是有一个致命问题是,此时关闭 mpv 窗口后,dmlive 进程终止了,但是 ffmpeg 进程却还在一直运行着,这就相当于内存泄漏了。

如果 kill_on_drop() 那里改成 true 会有副作用的话,是不是可以在 mpv/dmlive 进程终止时,向 ffmpeg 进程发送终止信号呢?我看到代码里也有终止 ffmpeg 的内容。

THMonster commented 1 year ago

1,正常播放情况下,我用杀掉 ffmpeg 进程的方式模拟断流或网络异常的方式,期待的效果是 mpv 会先静止下来,待 ffmpeg 重启后,mpv 会恢复正常播放,然而我这里的实际情况是 mpv 一直处于静止画面,即使进程里已经看到 ffmpeg 重新起来了。换句话说,这个策略没有起到效果。不知道这个情况属于预期的情况,还是我的操作不当。

我这无法复现你这情况,我kill掉ffmpeg就正常刷新了。你还是得看看是不是你自己有什么特殊设置,或者多个环境下测测看能否复现。

2,这个策略大概主要是为了应对断流或网络异常,然而却对下播的情况产生了副作用。期待的效果是,主播下播了,mpv 窗口自动关闭,dmlive, ffmpeg 进程自动终止。然而实际效果是,由于无法判断是下播了还是临时断流了,ffmpeg 会不断尝试刷新, mpv 窗口也会一直开着,需要用户自行关闭,这也无可厚非,但是有一个致命问题是,此时关闭 mpv 窗口后,dmlive 进程终止了,但是 ffmpeg 进程却还在一直运行着,这就相当于内存泄漏了。

我当然考虑到了下播还是断流的问。你少考虑了一点,如果主播不小心点了下播呢?你一检测到下播就关直播了?还有就是被超管掐了直播的情况,这种情况就会表现为下播。所以我的设计是有一个检测的时间,大约是在一分钟内,如果这一分钟内的数次检测全是下播状态,才会退出。关于你说ffmpeg还一直运行,这不是正常状态,我这无法复现,正常状态他是会一起退出的,所以你看你能不能换一个新的环境测一下能不能复现。

如果 kill_on_drop() 那里改成 true 会有副作用的话,是不是可以在 mpv/dmlive 进程终止时,向 ffmpeg 进程发送终止信号呢?我看到代码里也有终止 ffmpeg 的内容。

你的上述两点不成立,这段好像没法回答。

unisgn commented 1 year ago

我这无法复现你这情况,我kill掉ffmpeg就正常刷新了。你还是得看看是不是你自己有什么特殊设置,或者多个环境下测测看能否复现。

测出来了,去掉 keep-open=yes 后就像您说的一样正常工作了。 看来我得为 dmlive 建立一个专门的 profile,可是又没地方传进去,我再想想办法。

建议将这些影响正常工作的 mpv 参数放入相关文档里,避免他人遇到同样的问题,或者遇到问题不知道怎么解决。

THMonster commented 1 year ago

我把这两个选项显式设置为no了,这样应该不会被个人的设置影响到了。你有空的话试试看? https://github.com/THMonster/dmlive/tree/dev

unisgn commented 1 year ago

显示指定参数后,正常工作了。👍