Выход не ждёт ядро mpv: под Wine это ожидание не кончалось
Журнал закрытия показал место точно: последняя запись «Закрытие: закрываю плеер», дальше ничего. Значит, зависание внутри mpv_terminate_destroy — она не просто отпускает клиента, а ждёт, пока ядро mpv свернёт работу и добьёт свои потоки. Под Linux это мгновенно, под Wine не кончалось вовсе, причём даже когда ничего не открывали. Теперь плеер отсоединяется через mpv_destroy: она отпускает клиента и возвращает управление сразу, а ядро без клиентов сворачивается само. Команда «завершиться» перед этим намеренно не посылается — её тоже выполняет ядро, и встать она могла бы точно так же. Если в библиотеке mpv_destroy не окажется, остаётся прежний путь с ожиданием, и в журнале будет видно, что пошли по нему. Отсюда следствие: libmpv больше не выгружается при выходе. Потоки ядра в этот момент могут ещё жить внутри неё, и выдёргивать её из-под них нельзя. Программа всё равно закрывается, память освободит система. Плеер получил свою строчку в журнале — теперь видно и отсоединение, и завершение, а не только шаги окна.
This commit is contained in:
parent
ad88683e8b
commit
1e6da9b592
3 changed files with 54 additions and 5 deletions
|
|
@ -399,8 +399,14 @@ begin
|
|||
FreeAndNil(FSettings);
|
||||
Log('Закрытие: закрываю плеер.');
|
||||
FreeAndNil(FPlayer);
|
||||
Log('Закрытие: выгружаю libmpv.');
|
||||
UnloadMpvLib;
|
||||
|
||||
{ Библиотеку не выгружаем.
|
||||
|
||||
Плеер отсоединяется от mpv, не дожидаясь, пока ядро добьёт свои
|
||||
потоки, — иначе под Wine ожидание не кончалось вовсе. Значит, в
|
||||
момент выхода эти потоки могут ещё жить внутри библиотеки, и
|
||||
выгружать её из-под них нельзя. Программа всё равно закрывается,
|
||||
и система освободит всё сама. }
|
||||
Log('Закрытие: освобождаю проект.');
|
||||
FreeAndNil(FProject);
|
||||
Log('Закрытие завершено.');
|
||||
|
|
|
|||
|
|
@ -104,6 +104,10 @@ var
|
|||
mpv_create: function: Pmpv_handle; cdecl;
|
||||
mpv_initialize: function(ctx: Pmpv_handle): cint; cdecl;
|
||||
mpv_terminate_destroy: procedure(ctx: Pmpv_handle); cdecl;
|
||||
{ Необязательная: отсоединяет клиента, не дожидаясь, пока ядро добьёт
|
||||
свои потоки. Есть в libmpv с давних версий, но если вдруг не найдётся,
|
||||
работаем без неё. }
|
||||
mpv_destroy: procedure(ctx: Pmpv_handle); cdecl;
|
||||
mpv_set_option_string: function(ctx: Pmpv_handle; name, data: PAnsiChar): cint; cdecl;
|
||||
mpv_set_property: function(ctx: Pmpv_handle; name: PAnsiChar; format: cint;
|
||||
data: Pointer): cint; cdecl;
|
||||
|
|
@ -279,6 +283,8 @@ begin
|
|||
Need('mpv_request_log_messages', Pointer(mpv_request_log_messages));
|
||||
Need('mpv_wait_event', Pointer(mpv_wait_event));
|
||||
Need('mpv_event_name', Pointer(mpv_event_name));
|
||||
{ Без Need: её отсутствие не повод отказываться от предпросмотра. }
|
||||
Bind('mpv_destroy', Pointer(mpv_destroy));
|
||||
|
||||
if Missing <> '' then
|
||||
begin
|
||||
|
|
|
|||
|
|
@ -97,6 +97,9 @@ type
|
|||
вовсе — он приходил из видеофайла, а не с звуковой дорожки. }
|
||||
procedure SelectExternalAudio;
|
||||
{ Цепочка смешивания звуковых дорожек с их громкостями. }
|
||||
{ Собственная запись в журнал программы. Идёт тем же путём, что и
|
||||
сообщения самого mpv: у окна для них уже есть обработчик. }
|
||||
procedure Note(const AText: string);
|
||||
procedure BuildAudioGraph;
|
||||
function SetOption(const AName, AValue: string): Integer;
|
||||
public
|
||||
|
|
@ -377,16 +380,50 @@ begin
|
|||
FPump.OnTimer := @PumpEvents;
|
||||
end;
|
||||
|
||||
procedure TMpvPlayer.Note(const AText: string);
|
||||
begin
|
||||
if Assigned(FOnLog) then
|
||||
FOnLog(Self, 'nlve', 'info', AText);
|
||||
end;
|
||||
|
||||
{ Закрытие плеера.
|
||||
|
||||
Порядок здесь не случайный, и стоил зависания под Wine.
|
||||
|
||||
mpv_terminate_destroy не просто отпускает клиента — она ждёт, пока ядро
|
||||
mpv свернёт всю свою работу и добьёт свои потоки. Под Wine это ожидание
|
||||
не кончалось никогда: журнал обрывался на «закрываю плеер», и дальше
|
||||
ничего. Под Linux та же функция отрабатывает мгновенно.
|
||||
|
||||
Поэтому отсоединяемся, не дожидаясь ядра: mpv_destroy отпускает клиента
|
||||
и возвращает управление сразу, а ядро без клиентов сворачивается само.
|
||||
Программа в этот момент и так закрывается — ждать её незачем.
|
||||
|
||||
Команду «завершиться» перед этим не посылаем намеренно: она тоже
|
||||
выполняется ядром и под Wine могла бы встать точно так же. Отсоединение
|
||||
ни от чего не зависит.
|
||||
|
||||
Окно, в которое рисовал mpv, убирается только после этого: в обратном
|
||||
порядке он успел бы обратиться к уже несуществующему окну. }
|
||||
destructor TMpvPlayer.Destroy;
|
||||
begin
|
||||
FPump.Enabled := False;
|
||||
FreeAndNil(FPump);
|
||||
{ Сначала гасим mpv, и только потом убираем окно, в которое он рисовал:
|
||||
в обратном порядке он успел бы обратиться к уже несуществующему окну. }
|
||||
if FHandle <> nil then
|
||||
begin
|
||||
mpv_terminate_destroy(FHandle);
|
||||
if Assigned(mpv_destroy) then
|
||||
begin
|
||||
Note('плеер: отсоединяюсь от mpv');
|
||||
mpv_destroy(FHandle);
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ Старая libmpv без mpv_destroy: другого способа нет, ждём. }
|
||||
Note('плеер: закрываю mpv с ожиданием');
|
||||
mpv_terminate_destroy(FHandle);
|
||||
end;
|
||||
FHandle := nil;
|
||||
Note('плеер: закрыт');
|
||||
end;
|
||||
{$IFDEF LCLGTK2}
|
||||
if (FVideoWin <> 0) and (FDisplay <> nil) then
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue