0

Hi,
I am running 3 threads that each start an ffmpeg process to extract 3 snapshots form a video file.
I need to be able to call this method multiple times, with different video files.
It writes the three snapshots to the system.
However If I try to delete these files using File.Delete, it throws an exception.

Here is the code:

namespace runFFmpeg
{
    public struct ThreadData
    {
        public string time;
        public string inputFilename;
        public string outputFilename;
    }
    /// <summary>
    /// Description of MyClass.
    /// </summary>
    public class FfmpegBitmapCapture
    {
        private string output1;
        private string output2;
        private string pathToFfmpg = "..\\..\\lib\\ffmpeg.exe";
        private SnapshotItem[] snapshotItems = new SnapshotItem[3];
        
        private TimeSpan executionTime;
        
        public SnapshotItem[] SnapshotItems
        {
            get { return snapshotItems; }
        }
        
        public TimeSpan ExecutionTime
        {
            get { return this.executionTime;}
        }
        
        
        public FfmpegBitmapCapture(string filename, int percentFirst, int percentSecond, int percentThird)
        {
            GetSnapshotTimes(percentFirst,percentSecond,percentThird,filename);
            SmallLogger.SmallLogger.LogMessageToFile("ffmpeg: filename " + filename);
            
            ThreadData tdStart = new ThreadData();
            tdStart.inputFilename = filename;
            tdStart.outputFilename = this.GetTempPath() + "vidLib_snapshot[1].jpg";

            tdStart.time = snapshotItems[0].Time.ToString();
            Thread startThread = new Thread(new ParameterizedThreadStart(ExtractSnapshot));
            
            ThreadData tdMiddle = new ThreadData();
            tdMiddle.inputFilename = filename;
            tdMiddle.outputFilename = this.GetTempPath() + "vidLib_snapshot[2].jpg";

            tdMiddle.time = snapshotItems[1].Time.ToString();
            Thread middleThread = new Thread(new ParameterizedThreadStart(ExtractSnapshot));

            ThreadData tdEnd = new ThreadData();
            tdEnd.inputFilename = filename;
            tdEnd.outputFilename = this.GetTempPath() + "vidLib_snapshot[3].jpg";
            tdEnd.time = snapshotItems[2].Time.ToString();
            Thread endThread = new Thread(new ParameterizedThreadStart(ExtractSnapshot));
            
            DateTime startTime = DateTime.Now;

            startThread.Start(tdStart);
            middleThread.Start(tdMiddle);
            endThread.Start(tdEnd);
            
            startThread.Join();
            middleThread.Join();
            endThread.Join();

            this.snapshotItems[0].Thumbnail = new Bitmap(tdStart.outputFilename);
            this.snapshotItems[1].Thumbnail = new Bitmap(tdMiddle.outputFilename);
            this.snapshotItems[2].Thumbnail = new Bitmap(tdEnd.outputFilename);

            try
            {
                File.Delete(tdStart.outputFilename);
                File.Delete(tdMiddle.outputFilename);
                File.Delete(tdEnd.outputFilename);
            }
            catch(Exception ex)
            {
                System.Console.Out.WriteLine(ex);
            }
            DateTime stopTime = DateTime.Now;
            
            this.executionTime = stopTime - startTime;
        }

        void ExtractSnapshot(object threadData)
        {
            ThreadData td = (ThreadData)threadData;
            string outFileName = td.outputFilename;

            //from http://dotnetperls.com/process-redirect-standard-output
            ProcessStartInfo start = new ProcessStartInfo();

            start.FileName = this.pathToFfmpg;
            start.Arguments = "-i \"" + td.inputFilename + "\"  -r 1 -f mjpeg -vframes 1 -ss " + td.time + " -y " + outFileName;
            //start.Arguments = "-h";
            start.UseShellExecute = false;
            start.RedirectStandardOutput = true;
            start.RedirectStandardError = true;
            start.CreateNoWindow = true;
            
            //using(Process process = Process.Start(start))
            //{
            Process process = new Process();
            
            process.StartInfo = start;
            process.Start();
            
            using(StreamReader reader = process.StandardOutput)
            {
                output1 = reader.ReadToEnd();
                
            }
            using (StreamReader reader2 = process.StandardError)
            {
                output2 = reader2.ReadToEnd();
            }
            process.WaitForExit();
            process.Close();

            
            //}
        }

        private string GetTempPath()
        {
            string path = System.Environment.GetEnvironmentVariable("TEMP");
            if (!path.EndsWith("\\")) path += "\\";
            return path;
        }
        
        private void GetSnapshotTimes(int percentFirst,
                                      int percentMiddle,
                                      int percentLast,
                                      string filename)
        {
            string outputList;
            TimeSpan middle;
            TimeSpan end;
            TimeSpan begin;
            
            ProcessStartInfo start = new ProcessStartInfo();
            //start.FileName = "C:\\Users\\daddy\\Downloads\\ffmpeg-latest\\bin\\ffmpeg.exe";
            start.FileName = this.pathToFfmpg;
            start.Arguments = "-i \"" + filename + "\"";
            start.UseShellExecute = false;
            start.RedirectStandardOutput = true;
            start.RedirectStandardError = true;
            start.CreateNoWindow = true;
            using(Process process = Process.Start(start))
            {
                using (StreamReader reader2 = process.StandardError)
                {
                    outputList = reader2.ReadToEnd();
                }
                process.WaitForExit();
            }
            Regex regex = new Regex("Duration: +(?<dur>\\d\\d:\\d\\d:\\d\\d.\\d+)");
            Match m = regex.Match(outputList);
            
            if(m.Success)
            {
                TimeSpan OneSecond = TimeSpan.Parse("00:00:01.00");
                long OneseconTicks = OneSecond.Ticks;
                string duration = m.Groups["dur"].Value;
                TimeSpan ts = TimeSpan.Parse(duration);
                long durTicks = ts.Ticks;
                if(durTicks <= OneseconTicks){
                    begin = TimeSpan.FromTicks((long)((double)durTicks * 0.05));
                    end = begin;
                    middle = begin;
                }
                else
                {
                    middle = TimeSpan.FromTicks((long)((double)durTicks * ((double)percentMiddle)/100.0));
                    end = TimeSpan.FromTicks((long)((double)durTicks * ((double)percentLast)/100.0));
                    begin = TimeSpan.FromTicks((long)((double)durTicks * ((double)percentFirst)/100.0));
                }
                this.snapshotItems[0].Time = begin;
                this.snapshotItems[1].Time = middle;
                this.snapshotItems[2].Time = end;
            }
        }
    }
}

Regards,
John

1
Contributor
1
Reply
4
Views
7 Years
Discussion Span
Last Post by mpegjohn
0

Hi,
I am running 3 threads that each start an ffmpeg process to extract 3 snapshots form a video file.
I need to be able to call this method multiple times, with different video files.
It writes the three snapshots to the system.
However If I try to delete these files using File.Delete, it throws an exception.

Here is the code:

namespace runFFmpeg
{
    public struct ThreadData
    {
        public string time;
        public string inputFilename;
        public string outputFilename;
    }
    /// <summary>
    /// Description of MyClass.
    /// </summary>
    public class FfmpegBitmapCapture
    {
        private string output1;
        private string output2;
        private string pathToFfmpg = "..\\..\\lib\\ffmpeg.exe";
        private SnapshotItem[] snapshotItems = new SnapshotItem[3];
        
        private TimeSpan executionTime;
        
        public SnapshotItem[] SnapshotItems
        {
            get { return snapshotItems; }
        }
        
        public TimeSpan ExecutionTime
        {
            get { return this.executionTime;}
        }
        
        
        public FfmpegBitmapCapture(string filename, int percentFirst, int percentSecond, int percentThird)
        {
            GetSnapshotTimes(percentFirst,percentSecond,percentThird,filename);
            SmallLogger.SmallLogger.LogMessageToFile("ffmpeg: filename " + filename);
            
            ThreadData tdStart = new ThreadData();
            tdStart.inputFilename = filename;
            tdStart.outputFilename = this.GetTempPath() + "vidLib_snapshot[1].jpg";

            tdStart.time = snapshotItems[0].Time.ToString();
            Thread startThread = new Thread(new ParameterizedThreadStart(ExtractSnapshot));
            
            ThreadData tdMiddle = new ThreadData();
            tdMiddle.inputFilename = filename;
            tdMiddle.outputFilename = this.GetTempPath() + "vidLib_snapshot[2].jpg";

            tdMiddle.time = snapshotItems[1].Time.ToString();
            Thread middleThread = new Thread(new ParameterizedThreadStart(ExtractSnapshot));

            ThreadData tdEnd = new ThreadData();
            tdEnd.inputFilename = filename;
            tdEnd.outputFilename = this.GetTempPath() + "vidLib_snapshot[3].jpg";
            tdEnd.time = snapshotItems[2].Time.ToString();
            Thread endThread = new Thread(new ParameterizedThreadStart(ExtractSnapshot));
            
            DateTime startTime = DateTime.Now;

            startThread.Start(tdStart);
            middleThread.Start(tdMiddle);
            endThread.Start(tdEnd);
            
            startThread.Join();
            middleThread.Join();
            endThread.Join();

            this.snapshotItems[0].Thumbnail = new Bitmap(tdStart.outputFilename);
            this.snapshotItems[1].Thumbnail = new Bitmap(tdMiddle.outputFilename);
            this.snapshotItems[2].Thumbnail = new Bitmap(tdEnd.outputFilename);

            try
            {
                File.Delete(tdStart.outputFilename);
                File.Delete(tdMiddle.outputFilename);
                File.Delete(tdEnd.outputFilename);
            }
            catch(Exception ex)
            {
                System.Console.Out.WriteLine(ex);
            }
            DateTime stopTime = DateTime.Now;
            
            this.executionTime = stopTime - startTime;
        }

        void ExtractSnapshot(object threadData)
        {
            ThreadData td = (ThreadData)threadData;
            string outFileName = td.outputFilename;

            //from http://dotnetperls.com/process-redirect-standard-output
            ProcessStartInfo start = new ProcessStartInfo();

            start.FileName = this.pathToFfmpg;
            start.Arguments = "-i \"" + td.inputFilename + "\"  -r 1 -f mjpeg -vframes 1 -ss " + td.time + " -y " + outFileName;
            //start.Arguments = "-h";
            start.UseShellExecute = false;
            start.RedirectStandardOutput = true;
            start.RedirectStandardError = true;
            start.CreateNoWindow = true;
            
            //using(Process process = Process.Start(start))
            //{
            Process process = new Process();
            
            process.StartInfo = start;
            process.Start();
            
            using(StreamReader reader = process.StandardOutput)
            {
                output1 = reader.ReadToEnd();
                
            }
            using (StreamReader reader2 = process.StandardError)
            {
                output2 = reader2.ReadToEnd();
            }
            process.WaitForExit();
            process.Close();

            
            //}
        }

        private string GetTempPath()
        {
            string path = System.Environment.GetEnvironmentVariable("TEMP");
            if (!path.EndsWith("\\")) path += "\\";
            return path;
        }
        
        private void GetSnapshotTimes(int percentFirst,
                                      int percentMiddle,
                                      int percentLast,
                                      string filename)
        {
            string outputList;
            TimeSpan middle;
            TimeSpan end;
            TimeSpan begin;
            
            ProcessStartInfo start = new ProcessStartInfo();
            //start.FileName = "C:\\Users\\daddy\\Downloads\\ffmpeg-latest\\bin\\ffmpeg.exe";
            start.FileName = this.pathToFfmpg;
            start.Arguments = "-i \"" + filename + "\"";
            start.UseShellExecute = false;
            start.RedirectStandardOutput = true;
            start.RedirectStandardError = true;
            start.CreateNoWindow = true;
            using(Process process = Process.Start(start))
            {
                using (StreamReader reader2 = process.StandardError)
                {
                    outputList = reader2.ReadToEnd();
                }
                process.WaitForExit();
            }
            Regex regex = new Regex("Duration: +(?<dur>\\d\\d:\\d\\d:\\d\\d.\\d+)");
            Match m = regex.Match(outputList);
            
            if(m.Success)
            {
                TimeSpan OneSecond = TimeSpan.Parse("00:00:01.00");
                long OneseconTicks = OneSecond.Ticks;
                string duration = m.Groups["dur"].Value;
                TimeSpan ts = TimeSpan.Parse(duration);
                long durTicks = ts.Ticks;
                if(durTicks <= OneseconTicks){
                    begin = TimeSpan.FromTicks((long)((double)durTicks * 0.05));
                    end = begin;
                    middle = begin;
                }
                else
                {
                    middle = TimeSpan.FromTicks((long)((double)durTicks * ((double)percentMiddle)/100.0));
                    end = TimeSpan.FromTicks((long)((double)durTicks * ((double)percentLast)/100.0));
                    begin = TimeSpan.FromTicks((long)((double)durTicks * ((double)percentFirst)/100.0));
                }
                this.snapshotItems[0].Time = begin;
                this.snapshotItems[1].Time = middle;
                this.snapshotItems[2].Time = end;
            }
        }
    }
}

Regards,
John

OK, I fixed the problem myself.
I found that the lines, such as:
this.snapshotItems[0].Thumbnail = new Bitmap(tdStart.outputFilename);
lock the bitmap files that have been written out.

I changed these lines to:

using(Bitmap bm = new Bitmap(dStart.outputFilename))
{
    this.snapshotItems[0].Thumbnail = bm;
}

This closes and disposes of the Bitmap, and I can then delete the file.

I am sure there are other solutions, any help appreciated.

John

This question has already been answered. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.