I'm trying to extract metadata from video files by running ffprobe
using nativeProcess
. The code below works just as it should for one file, but causes an error when trying to loop through a series of files.
I know the cause of the problem is that Air tries to start a new nativeProcess
before the old one is finished. I know it's something to do with listening to the air.NativeProcessExitEvent.EXIT
. I just can't get it to work. Any suggestions would be greatly appreciated.
function fileOpen(){
var directory = air.File.userDirectory;
try
{
directory.browseForDirectory("Select Directory");
directory.addEventListener(air.Event.SELECT, directorySelected);
}
catch (error)
{
air.trace("Failed:", error.message)
}
function directorySelected(event)
{
directory = event.target ;
var files = directory.getDirectoryListing();
for(i=0; i < files.length; i++){
getMetadata(files[0].nativePath)
//wait here for nativeProcess to finish
}
}
}
function getMetadata(filePathIn){
if(air.NativeProcess.isSupported)
{
}
else
{
air.trace("NativeProcess not supported.");
}
fileIn = filePathIn.toString()
var nativeProcessStartupInfo = new air.NativeProcessStartupInfo();
var file = air.File.applicationStorageDirectory.resolvePath("ffprobe");
nativeProcessStartupInfo.executable = file;
args = new air.Vector["<String>"]();
args.push("-sexagesimal","-show_format","-loglevel","quiet","-show_streams","-print_format","json",filePathIn)
nativeProcessStartupInfo.arguments = args;
process = new air.NativeProcess();
process.start(nativeProcessStartupInfo);
process.addEventListener(air.ProgressEvent.STANDARD_OUTPUT_DATA, onOutputData);
process.addEventListener(air.ProgressEvent.STANDARD_ERROR_DATA, onErrorData);
process.addEventListener(air.NativeProcessExitEvent.EXIT, onExit);
process.addEventListener(air.IOErrorEvent.STANDARD_OUTPUT_IO_ERROR, onIOError);
process.addEventListener(air.IOErrorEvent.STANDARD_ERROR_IO_ERROR, onIOError);
}
function onOutputData()
{
var fileMetadataJSON = process.standardOutput.readUTFBytes(process.standardOutput.bytesAvailable);
air.trace(fileMetadataJSON)
}
function onErrorData(event)
{
air.trace("ERROR -", process.standardError.readUTFBytes(process.standardError.bytesAvailable));
}
function onExit(event)
{
air.trace("Process exited with ", event.exitCode);
}
function onIOError(event)
{
air.trace(event.toString());
}
Here an outline that should give you an idea of what to do:
directorySelected()
method, promote the local variable files
(an Array) to a member variable. This will make the list of files that was selected available so that other methods can access it.for
loop in your directorySelected()
method. Instead of running the loop and trying to run the native process here, call a new method, let's call it dequeueFileAndRunNativeProcess()
.dequeueFileAndRunNativeProcess()
method should check the length of the files
array, and if it is greater than 0, it should pop()
the first file in the files
array and execute the native process on it.onExit()
method, call the dequeueFileAndRunNativeProcess()
method again.The idea here is to move the code that runs the native process into a method that you can trigger from two places: once immediately after the user finishes browsing for files, and then again after the native process finishes it's work. The process ends when the files
array has no more files in it.