Пытаюсь работать с ffmpeg.exe и ffplay.exe (http://ffmpeg.org/) цель - захват видео с экрана и потом проиграть. Думал что сделаю быстро(наивный).
Проблема с управлением через TProcess данного exe. Я написал маленькую серию тестов (попробую покороче)(проигрывание файла).
Система: Win10(64) lazarus32 (2.0.10) FPS: 3.2.0
- Код: Выделить всё
MyProc:=TProcess.Create(FormMain);
MyProc.PipeBufferSize:=1024; //это значение по умолчанию, но я напишу т.к. важно для понимания
MyProc.Options:= [poUsePipes];
//я исполняю по 1 строчке, но для краткости, отставлю всё здесь
MyProc.Executable:='calc'; //работает хорошо, как и должно, ничего в консоли не поймали (внизу код) ОК
MyProc.Executable:='help'; //сработало поймали консоль в мемо, после отработки вышло один раз, прочитали 1024 (смотрите буфер) и вышли - ОК
MyProc.Executable:='D:\vizion\test\test2.bat'; //это батник с паузами. Проверяю нормально ли работает ожидание, сумели ли словить
//я подозреваю, что будет работать запись в стрим TProcess.Input (я не проверял, но вроде всё хорошо)
//Внизу дам описание проблем следующего кода
MyProc.Executable:=path_ffmpeg+'ffplay.exe';
MyProc.Parameters.Add('D:\vizion\outfolder\output.mkv');
MyProc.Execute();
Application.ProcessMessages;
while MyProc.Running do begin
Label1.Caption:='run';
Application.ProcessMessages;
if MyProc.Output.NumBytesAvailable > 0 then
begin
MemoCmd.Lines.Add('can be read');
MemoCmd.Lines.LoadFromStream(MyProc.Output);
end;
end;
Label1.Caption:='not run';
MyProc.Terminate(0);
MyProc.Free;
Подаём экзешник с полным путём (ffplay.exe) и параметр к нему. Всё правильно исходи и из документации, и руками, когда я работаю с консолью всё хорошо
Но при указании [poUsePipes] я не получаю данных (код внизу) ни единого байтика, и само проигрывание не работает (чёрный экран консоли).
Execute без [poUsePipes] работает, а именно, вызывается консоль туда пишутся данные, открывается окно с проигрывателем и файл проигрывается.
ВАЖНО: Консоль там не простая, там отображено динамически данные типа FPS в реальном времени. Возможно поэтому захват консоли не работает, я не имел с таким дело.
При ошибках (например файла не существует) пайп работает как и должно, т.е. я могу всё уловить.
Примечание: Если Tprocess или TUTFProcess на форме как компоненты, т.е. они статические
то при вызове повторно, окошко с видео появляется, т.е. я один раз клацаю на кнопку, второй раз. Потом закрываю первое висящую консоль, и появляется проигрыватель(играет видео), вторая консоль видна, но данные я не могу с неё получить. Я проверил все настройки, но не понимаю почему так.
И последнее, проблема в том что мне надо прервать запись/проигрывание, для этого я должен в консоль написать пару чаров(насколько я понимаю), но,
1. Я не получил первичный ответ от процесса, может он занят, не знаю я
2. При попытки записи нет эффекта или ошибка памяти...
Вот ответ по поводу работы с ffmpeg, я могу плохо объяснять
https://stackoverflow.com/questions/797 ... eo-capture
Возможно, я должен был написать всё раньше т.к. плохо биться долго головой о стену.
Да, я мог бы скачать длл ки, и заголовочные, но я думал что через консоль то проще. + нет зависимости о заголовков + документация для EXE для всех языков с примерами + могу написать хоть автоматическое обновление
Пожалуйста подскажите, в чём может быть проблема.
upd:
пытался читать "нормальным методом" для больших данных в консоли, через TTimer(1000)
висит намертво вот на этой строке
- Код: Выделить всё
BytesRead : longint;
Buffer : array[1..BUF_SIZE] of byte;
...
BytesRead := MyGlobalProc.Output.Read(Buffer, BUF_SIZE);
Величина буфера совпадает с PipeBufferSize
Поигрался с выводом логов. Нашёл настройку ffmpeg вывод статичных логов, читать их не получается (после любых операций остаётся 2 байта на чтение), хотя в консоли красным по чёрному написана ошибка =)))
upd:
Можно настроить вывод ffmpeg более дружелюбнее, я перенаправил весь вывод в файл
можно это делать как стандартными способами операционных систем(наверно), так и сам ffmpeg имет систему репортов, необходимо указать параметр в Environment (TProcess)
К примеру:
- Код: Выделить всё
MyGlobalProc.Environment.Add('FFREPORT=file='''+path_ffmpeg+'fflog.log'':level=24'); //24 - уровень лога в файл
А вывод логов на уровне консоли отключить:
- Код: Выделить всё
ffplay.exe output.mkv -loglevel +quiet
позволит не получать ничего в консоль и процесс будет как бы висеть, если всё хорошо
зато можно работать по привычному, прямо с файлом. Хотя, не хорошо... лучше бы работать с памятью и не трогать диск
upd:
Стена оказалась сильнее =))). Я всё сделал через консоль, но при указании [poNoConsole] в TProcess я не могу корректно закрыть консольное приложение. on_close/exit не отрабатывается у процесса без консоли, например надо закончить захват экрана, и при выходе ffmpeg(в onclose) завершает концовку файла и закрывает медиа контейнер.
Terminate пробовал , пробовал PostMessage - говорит что WM_CLOSE для окон, хотя бы консольных. Пробовал через taskkill, не хочет работать без ключа /f который принудительно kill приложение.
[poNoConsole] - это WinApi CreateProcess с параметром CREATE_NO_WINDOW (как то так). А начиналось всё не так плохо...