popen() -- for "pipe open" -- is a very useful system call provided in many flavors of Unix. It runs a command passed in as a string then returns a file handle so that the parent process can read or write to the process as if it was a file; data passed this way is connected to the standard input or the standard output of the child process.
I created this because I wanted to process very long MP3 files in Matlab. Originally I wrote mp3read to allow me to decode just a small section of a long MP3 file without having to decode the whole thing, but every time I wanted to read another segment, I had to open the file again, then seek through to the point I wanted to read.
Instead, by using popen to open an MP3 decoding process that writes to standard output, I can "pull" as many frames as I want from the file, then put the process to sleep while I deal with those frames, then, on my next read from popen, the process is reawoken and the next block of data can be accessed. But this could be used for any application where there are long data streams to read or write, and you want to handle them a bit at a time.
Two functions are provided, popenr.c for reading from command pipes, and popenw.w for writing to command pipes. Reading and writing to the same command is not supported at present.
Great work, thank you very much. I needed it to parse FFMPEG pipe output to obtain a video frame without writing it in to a file. It worked like a charm except a signed/unsigned problem. Original code reads proper values if they are below 128, but reads zero if they are 128 or above.
To fix this I changed line 243 of popenr.c from: char *pc = (char *)pd;
To: unsigned char *pc = (unsigned char *)pd;
By the way, the below function would read a frame from FFMPEG without writing to a file thanks to popen.
Use it like: frame = ReadVideoFrame('a.avi',[1080,1920,3],'00:00:05.10');
function image_correctly_rotated = ReadVideoFrame(video_name,video_frame_size,time)
pipe = popenr(['export DYLD_LIBRARY_PATH=""; ' ['/opt/local/bin/ffmpeg -i ' video_name ' -r 1 -vframes 1 -ss ' time ' -f image2pipe -vcodec ppm pipe:1']]);
data = uint8(popenr(pipe,[prod(video_frame_size)+17,1],'uint8'));
image_wrongly_rotated = reshape(data(18:end),[video_frame_size(3) video_frame_size(2) video_frame_size(1)]);
image_correctly_rotated = permute(image_wrongly_rotated,[3,2,1]);
you could also do it using java:
function [ in, out, err ] = popen( cmd )
% invoke process
rt = java.lang.Runtime.getRuntime();
p = rt.exec(cmd);
% get streams
err = java.io.BufferedReader(java.io.InputStreamReader(p.getErrorStream()));
in = java.io.BufferedReader(java.io.InputStreamReader(p.getInputStream()));
out = java.io.PrintWriter(p.getOutputStream());
This is great extension, which providing powerful tool to for interface with other applications.
I've been using two alternatives until now:
1. Output from other apps. to temporary files, and then command 'load ...' from Matlab,
2. Executing them with 'system(...)', which gives output string, then parsing it with 'sscanf(...)'.
Both alternatives waste a lot more time. For my files, 'popenr(...)' is even quicker than loading mat-files with the same data!
Thank you very much.