Reading Data From External Program
Reading Data From External Program
How does one read data returned by an external program?
Do I want to use exec or open pipe? Specifically, I want to read frames of video using ffmpeg.
Tnank you.
Do I want to use exec or open pipe? Specifically, I want to read frames of video using ffmpeg.
Tnank you.
-
- Posts: 862
- Joined: May 05, 2015 5:35
- Location: Germany
Re: Reading Data From External Program
I regulary use ffmpeg for audio conversion. The easiest way of access is by a pipe:To see how to capture video frames have a look at this page.
Code: Select all
#Include "crt\stdio.bi"
Dim As String ffmpeg = "C:\programs\ffmpeg.exe" 'replace with the full path of your ffmpeg.exe
Dim As String order = ffmpeg + " ?" 'replace the question mark with the command string you wish to send to ffmpeg
Dim As Any Ptr ffmpg = popen(StrPtr(order), @"r")
Sleep
pclose(ffmpg)
End
Re: Reading Data From External Program
Thanks, but how do I read the frame data into an array in FB?
I already have:
const H = 720: const W = 1280
dim shared as ubyte frame(H*W*3) 'Allocate a buffer To store one frame
In my PureBasic version I use:
pixct = ReadProgramData(readFrame, @frame(0), H * W * 3)
If pixct = 0: Break: EndIf ;NO MORE FRAMES TO READ
How is this accomplished in FB? I'm looking for the equivalent of "ReadProgramData".
There is also this:
https://batchloaf.wordpress.com/2017/02 ... ment-24886
I already have:
const H = 720: const W = 1280
dim shared as ubyte frame(H*W*3) 'Allocate a buffer To store one frame
In my PureBasic version I use:
pixct = ReadProgramData(readFrame, @frame(0), H * W * 3)
If pixct = 0: Break: EndIf ;NO MORE FRAMES TO READ
How is this accomplished in FB? I'm looking for the equivalent of "ReadProgramData".
There is also this:
https://batchloaf.wordpress.com/2017/02 ... ment-24886
-
- Posts: 8586
- Joined: May 28, 2005 3:28
- Contact:
Re: Reading Data From External Program
Normally you send/write a command and receive/read the result but FreeBASIC pipes are not bidirectional !
(so far I know)
Joshy
(so far I know)
Joshy
Re: Reading Data From External Program
This is gotten around by using separate input and output pipes.FreeBASIC pipes are not bidirectional !
(so far I know)
Re: Reading Data From External Program
It seems I can send commands to ffmpeg, and it responds, but I need to set up a second pipe to read in the received data which I don't know how to do.
-
- Posts: 862
- Joined: May 05, 2015 5:35
- Location: Germany
Re: Reading Data From External Program
The simplest way is:chris319 wrote:Thanks, but how do I read the frame data into an array in FB?
- -Open the output file
-Transfer the data to the array
-Close/kill the output file
In all modesty: https://www.freebasic-portal.de/code-be ... i-297.htmlchris319 wrote:It seems I can send commands to ffmpeg, and it responds, but I need to set up a second pipe to read in the received data which I don't know how to do.
If required I could translate the description to english, but I think the (english) comments should be sufficient to get along with it.
I've never tried , but the piping should work if ffmpeg's output is redirected to stdout.
Re: Reading Data From External Program
The library presented here provides 5 functions - integrated via #Include:
1. bipOpen (ProgrammName, [showmode]) - Opens the (console) program ProgrammName and sets up two unidirectional pipes for communication. The optional parameter showmode defines the appearance of the called program. For possible parameters see https://docs.microsoft.com/en-us/window ... dfrom=MSDN. The default is SW_NORMAL. The return value is a pointer to the corresponding HANDLE array (HandlePointer).
2. bipClose (HandlePointer) - Ends the program, closes the pipes, clears the handles, releases the memory and sets the HandlePointer to 0.
3. bipWrite (HandlePointer, text, ["b"]) - Sends a string for standard input of the opened program. If the optional parameter "b" (for binary) is set, the string is sent unchanged, otherwise a Chr (13,10) is added.
4. bipRead (HandlePointer, [timeout]) - Reads the standard output of the program. The default for timeout is 100ms.
5. bipReadLine (HandlePointer, [separator], [timeout]) - Reads a line from the started program, analogous to the "Line Input" command. The optional separator parameter is either an "a" (for any) followed by a list of characters, each of which ends the line, or an "e" (for exact), followed by one or more characters to represent the separator , The default is "a" & Chr (13,10). The default for timeout is 100ms.
1. bipOpen (ProgrammName, [showmode]) - Opens the (console) program ProgrammName and sets up two unidirectional pipes for communication. The optional parameter showmode defines the appearance of the called program. For possible parameters see https://docs.microsoft.com/en-us/window ... dfrom=MSDN. The default is SW_NORMAL. The return value is a pointer to the corresponding HANDLE array (HandlePointer).
2. bipClose (HandlePointer) - Ends the program, closes the pipes, clears the handles, releases the memory and sets the HandlePointer to 0.
3. bipWrite (HandlePointer, text, ["b"]) - Sends a string for standard input of the opened program. If the optional parameter "b" (for binary) is set, the string is sent unchanged, otherwise a Chr (13,10) is added.
4. bipRead (HandlePointer, [timeout]) - Reads the standard output of the program. The default for timeout is 100ms.
5. bipReadLine (HandlePointer, [separator], [timeout]) - Reads a line from the started program, analogous to the "Line Input" command. The optional separator parameter is either an "a" (for any) followed by a list of characters, each of which ends the line, or an "e" (for exact), followed by one or more characters to represent the separator , The default is "a" & Chr (13,10). The default for timeout is 100ms.
Code: Select all
#Include Once "windows.bi"
Type bipdata
hProcessHandle As HANDLE
hWritePipe As HANDLE
hReadPipe As HANDLE
End Type
Function bipOpen(PrgName As String, showmode As Short = SW_NORMAL) As bipdata Ptr
Dim As STARTUPINFO si
Dim As PROCESS_INFORMATION pi
Dim As SECURITY_ATTRIBUTES sa
Dim As HANDLE hReadPipe, hWritePipe, hReadChildPipe, hWriteChildPipe
Dim pPipeHandles As bipdata Ptr
'set security attributes
sa.nLength = SizeOf(SECURITY_ATTRIBUTES)
sa.lpSecurityDescriptor = NULL 'use default descriptor
sa.bInheritHandle = TRUE
'create one pipe for each direction
CreatePipe(@hReadChildPipe,@hWritePipe,@sa,0) 'parent to child
CreatePipe(@hReadPipe,@hWriteChildPipe,@sa,0) 'child to parent
GetStartupInfo(@si)
si.dwFlags = STARTF_USESTDHANDLES Or STARTF_USESHOWWINDOW
si.wShowWindow = showmode 'appearance of child process window
si.hStdOutput = hWriteChildPipe
si.hStdError = hWriteChildPipe
si.hStdInput = hReadChildPipe
CreateProcess(0,PrgName,0,0,TRUE,CREATE_NEW_CONSOLE,0,0,@si,@pi)
CloseHandle(hWriteChildPipe)
CloseHandle(hReadChildPipe)
pPipeHandles = Allocate (SizeOf(bipdata)) 'area for storing the handles
pPipeHandles->hProcessHandle = pi.hProcess 'handle to child process
pPipeHandles->hWritePipe = hWritePipe
pPipeHandles->hReadPipe = hReadPipe
Return pPipeHandles 'pointer to handle array
End Function
Sub bipClose(ByRef pPipeHandles As bipdata Ptr)
If pPipeHandles = 0 Then Return
TerminateProcess(pPipeHandles->hProcessHandle, 0)
CloseHandle(pPipeHandles->hWritePipe)
CloseHandle(pPipeHandles->hReadPipe)
DeAllocate(pPipeHandles)
pPipeHandles = 0
End Sub
Function bipWrite(pPipeHandles As bipdata Ptr, text As String, mode As String = "") As Integer
Dim As Integer iNumberOfBytesWritten
'Dim As String txt = text
'? Len(text);" ";
If pPipeHandles = 0 Then Return 0
If LCase(mode) <> "b" Then 'not binary mode
text += Chr(13,10)
EndIf
WriteFile(pPipeHandles->hWritePipe,StrPtr(text),Len(text),@iNumberOfBytesWritten,0)
Return iNumberOfBytesWritten
End Function
Function bipRead(pPipeHandles As bipdata Ptr, timeout As UInteger = 100) As String
'returns the whole pipe content until the pipe is empty or timeout occurs.
' timeout default is 100ms to prevent a deadlock
Dim As Integer iNumberOfBytesRead, iTotalBytesAvail, iBytesLeftThisMessage
Dim As String buffer, retText
Dim As Double tout = Timer + Cast(Double,timeout) / 1000
If pPipeHandles = 0 Then Return "" 'no valid pointer
Do
PeekNamedPipe(pPipeHandles->hReadPipe,0,0,0,@iTotalBytesAvail,0)
If iTotalBytesAvail Then
buffer = String(iTotalBytesAvail,Chr(0))
ReadFile(pPipeHandles->hReadPipe,StrPtr(buffer),Len(buffer),@iNumberOfBytesRead,0)
retText &= buffer
ElseIf Len(retText) Then
Exit Do
EndIf
Loop Until Timer > tout
Return retText
End Function
Function bipReadLine(pPipeHandles As bipdata Ptr, separator As String = "a" & Chr(13,10), timeout As UInteger = 100) As String
'returns the pipe content till the first separator if any, or otherwise the whole pipe
' content on timeout. timeout default is 100ms to prevent a deadlock
Dim As Integer iNumberOfBytesRead, iTotalBytesAvail, iBytesLeftThisMessage, endPtr
Dim As String buffer, retText, mode
Dim As Double tout = Timer + Cast(Double,timeout) / 1000
If pPipeHandles = 0 Then Return "" 'no valid pointer
mode = LCase(Left(separator,1))
separator = Mid(separator,2)
Do
PeekNamedPipe(pPipeHandles->hReadPipe,0,0,0,@iTotalBytesAvail,0)
If iTotalBytesAvail Then
buffer = String(iTotalBytesAvail,Chr(0))
PeekNamedPipe(pPipeHandles->hReadPipe,StrPtr(buffer),Len(buffer),@iNumberOfBytesRead, _
@iTotalBytesAvail,@iBytesLeftThisMessage) 'copy pipe content to buffer
Select Case mode
Case "a" 'any
endPtr = InStr(buffer, Any separator) 'look for line end sign
Case "e" 'exact
endPtr = InStr(buffer, separator) 'look for line end sign
End Select
If endPtr Then 'return pipe content till line end
Select Case mode
Case "a"
Do While (InStr(separator,Chr(buffer[endPtr - 1]))) And (endPtr < Len(buffer))
endPtr += 1
Loop
endPtr -= 1
Case "e"
endPtr += Len(separator)
End Select
retText = Left(buffer,endPtr)
ReadFile(pPipeHandles->hReadPipe,StrPtr(buffer),endPtr,@iNumberOfBytesRead,0) 'remove read bytes from pipe
Select Case mode
Case "a"
Return RTrim(retText,Any separator) 'remove line end sign from returned string
Case "e"
Return Left(retText,Len(retText) - Len(separator))
End Select
EndIf
EndIf
Loop Until Timer > tout
If iTotalBytesAvail Then 'return all pipe content
buffer = String(iTotalBytesAvail,Chr(0))
ReadFile(pPipeHandles->hReadPipe,StrPtr(buffer),Len(buffer),@iNumberOfBytesRead,0)
Return buffer
EndIf
Return ""
End Function
Last edited by chris319 on Mar 03, 2020 21:11, edited 1 time in total.
-
- Posts: 862
- Joined: May 05, 2015 5:35
- Location: Germany
Re: Reading Data From External Program
@chris319: Thank you for taking the work out of my hands to translate the description. May I add your translation to the code example?
Re: Reading Data From External Program
Yes, of course.grindstone wrote:@chris319: Thank you for taking the work out of my hands to translate the description. May I add your translation to the code example?
Re: Reading Data From External Program
The difference between your code and what I use in the PureBasic version is that in the PB version I specify the number of bytes to be read into an array from ffmpeg:
Code: Select all
ReadProgramData(readFrame, @frame(0), #H*#W*3)