Is there a way to manually close an EXIFTOOL process that is stuck? Or perhaps force a Task.WhenAll to finish?

30 Views Asked by At

I am building an application that imports numerous video files from a file picker and runs them all through EXIFTOOL to get the metadata of each file. A list of VideoFileModel is returned after all of the videos have been processed. This all works great 99.99% of the time; however, I have come across one video file that halts execution of my application. I am not sure if the video is corrupted or what. It is the only one I have come across that provides this error but surely this will happen again one day so I need a fix.

When my application launches the process for EXIFTOOL for this video, the process window stays open and execution stops. If I physical close the process window, the data is processed and execution continues with no errors. It seems that the process is stuck. Execution is halted because of the following await:

var metaDataResults = await System.Threading.Tasks.Task.WhenAll(metaTasks);

My code after this relies of the data that is being returned to metaDataResults. I have tried to kill the process manually with process.Kill() and process.Close() but the window stays open until I physically close it. I have heard that there can result a “Dead Lock” in EXIFTOOL if standard output and standard error are both redirecting. I am not redirecting standard error only output. I have tested with standard error and is returns nothing.

Below is the code from initial button click:

private async void ImportVideoButton_Click(object sender, RoutedEventArgs e)
{
    OpenFileDialog openFileDialog = new OpenFileDialog();
    openFileDialog.Multiselect = true;

    if (openFileDialog.ShowDialog() == true)
    {                    
        List<Task<Models.VideoFileModel>> metaTasks = new List<Task<VideoFileModel>>();
        
        foreach (string file in openFileDialog.FileNames)
        {
            foreach (var video in _viewModel.AllLightningVideos)
            {
                if (file == video.VideoPath)
                {
                    video.VideoName = video.VideoName + "_";
                }
            }             
            metaTasks.Add(System.Threading.Tasks.Task.Run(() => _viewModel.ProcessMetaData(file)));
        }
        
        // EXECUTION STOPS AT THE CODE BELOW PRESUMMINGLY BECUASE THE PROCESS WILL NOT FINISH
        var metaDataResults = await System.Threading.Tasks.Task.WhenAll(metaTasks);

ProcessMetaData returns a VideoFileModel after calling the method getExifDataViaTool. Below is the code for that method:

public static Dictionary<string, string> getExifDataViaTool(string sourceFile, string parameters = "-a -api largefilesupport=1")
{
    var result = new Dictionary<string, string>();
    sourceFile = Regex.Replace(sourceFile, @"(\\*)" + "\"", @"$1\$0");
    sourceFile = Regex.Replace(sourceFile, @"^(.*\s.*?)(\\*)$", "\"$1$2$2\"");
    var argumentsString = parameters + " " + sourceFile;
    System.Diagnostics.Process process = new System.Diagnostics.Process();
    System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
    string ExifToolPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "FFMPEG\\exiftool.exe");
    startInfo.FileName = ExifToolPath;
    startInfo.Arguments = argumentsString;
    startInfo.RedirectStandardOutput = true;            
    //startInfo.RedirectStandardError = true;
    startInfo.UseShellExecute = false;
    startInfo.CreateNoWindow = false;
    startInfo.WindowStyle = ProcessWindowStyle.Hidden;
    process.StartInfo = startInfo;
    process.Start();

    string output = process.StandardOutput.ReadToEnd();                 
    process.WaitForExit(1000);
    
    string[] lines = output.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);

    foreach (var line in lines)
    {
        var pair = line.Split(new char[] { ':' }, 2);
        if (pair.Length >= 2)
        {
            var key = pair[0].TrimEnd();
            var value = pair[1].TrimStart();
            result[key] = value;
            Debug.WriteLine(key + " : :" + value);
        }
    }            
    return result;            
}

Any help would be appreciated!

0

There are 0 best solutions below