Log in

View Full Version : ffmpeg w/ poUsePipes (freepascal)


Sirber
17th November 2010, 02:47
In a single threaded GUI I use this function to run a cmdline app:

function Tfmain.CliRun(sCmd: string): integer;
var
aOutput: TStringList;
iCpt: integer;
begin
aOutput := TStringList.Create();
// http://wiki.lazarus.freepascal.org/Executing_External_Programs
// http://community.freepascal.org:10000/docs-html/fcl/process/tprocess.execute.html

oCli.CommandLine := sCmd;
oCli.Priority := ppIdle;
oCli.CurrentDirectory := sTemp;
oCli.Options := [poUsePipes, poStderrToOutPut];
{$IFDEF WIN32}oCli.Options := oCli.Options + [poNoConsole];{$ENDIF}
//oCli.ShowWindow := swoHide;
oCli.Execute();

oCliLogs.Clear();
oCliLogs.Add(sCmd);
oCliLogs.Add('');

while (oCli.Active = True) do
begin
// Do stuff!
Application.ProcessMessages();
Sleep(25);
Application.ProcessMessages();

//Look for logs
aOutput.LoadFromStream(oCli.Output);
if (aOutput.Count > 0) then
begin
for iCpt := 0 to aOutput.Count - 1 do
begin
Application.ProcessMessages();
oCliLogs.Add(aOutput.Strings[iCpt]);
end;
Application.ProcessMessages();
txtLog.Text := aOutput.Strings[aOutput.Count - 1];
end;
Application.ProcessMessages();
end;

aOutput.Free;
Result := oCli.ExitStatus;
end;


... and everything works well. I can fetch the text output from ffmpeg and ffmpeg encodes the files proprely.

But when I try to run ffmpeg via a thread, if I use "poUsePipes" ffmpeg hangs and does nothing (0% CPU, no text output).

procedure TMyThread.cliRun(sCmd:string);
var
newStatus: string;
aOutput: TStringList;
iCpt: integer;
begin
fStatusText := 'Warning: real-time logs unavalible in multi-threading mode.. yet.';
Synchronize(@Showstatus);
aOutput := TStringList.Create();

fmain.oCliLogs.Clear();
fmain.oCliLogs.Add(sCmd);
fmain.oCliLogs.Add('');

oCli := TProcess.Create(nil);
oCli.CommandLine := sCmd;
oCli.Priority := ppIdle;
oCli.CurrentDirectory := sTemp;
{fails}
oCli.Options := [poUsePipes, poStderrToOutPut];
{$IFDEF WIN32}oCli.Options := oCli.Options + [poNoConsole];{$ENDIF}

{works}
//oCli.Options := [poWaitOnExit];
//oCli.ShowWindow := swoHide;

oCli.Execute();

repeat
{ Logs }
//aOutput.LoadFromStream(oCli.Output);
{
if (aOutput.Count > 0) then
begin
for iCpt := 0 to aOutput.Count - 1 do
begin
oCliLogs.Add(aOutput.Strings[iCpt]);
end;
newStatus := aOutput.Strings[aOutput.Count - 1];
end;
}
//newStatus := 'encoding';

{ Thread management }
if (fStatusText <> newStatus) then
begin
fStatusText := newStatus;
Synchronize(@Showstatus);
end;

if (Terminated) then
oCli.Terminate(-1);
until not oCli.Running;

iExitCode := oCli.ExitStatus;
fmain.oCliLogs.Add('');
fmain.oCliLogs.Add('Ended with ExitCode: ' + IntToStr(iExitCode));

aOutput.Free;
oCli.Free;
end;


I'm using the latest build from: http://ffmpeg.arrozcru.org/autobuilds/

I don't get it... am I doing something wrong? :(

Sirber
17th November 2010, 03:05
kinda related: http://forum.lazarus.freepascal.org/index.php/topic,10922.0.html

Sirber
17th November 2010, 03:27
ffmpeg.exe, while using 0% CPU, uses ~12MB of RAM instead of 270MB for the same job whitout TThread :(.

Sirber
17th November 2010, 03:50
I'm gonna try TAsyncProcess. Since TProcess works well TAsyncProcess might.

ckmox
17th November 2010, 09:03
i got some tips about this problem of yours here -> http://forum.doom9.org/showthread.php?p=1458238#post1458238

and TAsyncProcess im afraid wont work well in windows OS that is, i already tried it the only way to make TProcess or TAsyncProcess on windows OS to be more responsive is through Multi-Threading or TThread

Sirber
17th November 2010, 13:26
but with TAsyncProcess, you don't have to "while process.running" so the UI can just wait for the events no?

ckmox
17th November 2010, 13:51
ok your ffmpeg code TProcess might be experiencing a dead lock have you read this part?

Reading large output

In the previous example we waited until the program exited. Then we read, what the program has written to its output. But suppose the program writes a lot of data to the output, the pipe becomes full and the called progam waits until the pipe has been read from. But the calling program doesn't read from it, until the called program has ended. A dead lock occurs.

The following example therefore doesn't use poWaitOnExit, but reads from the output, while the program is still running. The output is stored in a memory stream, that can be used later to read the output into a TStringList.


the above quote is taken from here -> http://wiki.lazarus.freepascal.org/Executing_External_Programs
and the example code or solution is on that link too

and for what i understand TAsyncProcess suppose to not wait on reading (the idle reading is the cause of the unresponsiveness) like TProcess does, so TAsyncProcess can be combo with Application.ProcessMessages to make the program more responsive but in my experience its not like that so i resorted on making thread (TThread)

Sirber
17th November 2010, 14:06
using TProcess in the main thread while it's running, reading the output works, but the same code inside another thread hangs. if I try to read the output while ffmpeg is hanged (.Output), the thread seems to die.

ckmox
17th November 2010, 14:40
using TProcess in the main thread while it's running, reading the output works, but the same code inside another thread hangs. if I try to read the output while ffmpeg is hanged (.Output), the thread seems to die.

so the problem is how you code the TThread because there are rules on doing it and the lazarus forum thread i gave before explained those things as they said on that forum thread the TThread class is not your usual class

Sirber
17th November 2010, 14:42
I think I'll try my luck on TAsyncProcess :(