Search code examples
c#videoffmpeg

How to pause/resume ffmpeg video capture in windows from C# application


I am using ffmpeg to capture screen and audio using a C# application. The command I am using to execute ffmpeg as follows:

ffmpeg -f gdigrab -i desktop -f dshow -i audio="Microphone (Realtek High Definition Audio)" -v
codec libx264 output.mp4

Now I want to pause/resume recording and want to control it from the C# application. Is there anyway I can achieve that?


Solution

  • Add Helper class to project as below:

    static class Helper
    {
        public static T[] ToArray<T>(this ICollection collection)
        {
            var items = new T[collection.Count];
            collection.CopyTo(items, 0);
    
            return items;
        }
    }
    

    Add a class to your project as below:

     public static class ProcessExtensions
        {
            #region Methods
    
            public static void Suspend(this Process process)
            {
                Action<ProcessThread> suspend = pt =>
                {
                    var threadHandle = NativeMethods.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pt.Id);
    
                    if (threadHandle != IntPtr.Zero)
                    {
                        try
                        {
                            NativeMethods.SuspendThread(threadHandle);
                        }
                        finally
                        {
                            NativeMethods.CloseHandle(threadHandle);
                        }
                    };
                };
    
                var threads = process.Threads.ToArray<ProcessThread>();
    
                if (threads.Length > 1)
                {
                    Parallel.ForEach(threads, new ParallelOptions { MaxDegreeOfParallelism = threads.Length }, pt =>
                    {
                        suspend(pt);
                    });
                }
                else
                {
                    suspend(threads[0]);
                }
            }
    
            public static void Resume(this Process process)
            {
                Action<ProcessThread> resume = pt =>
                {
                    var threadHandle = NativeMethods.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pt.Id);
    
                    if (threadHandle != IntPtr.Zero)
                    {
                        try
                        {
                            NativeMethods.ResumeThread(threadHandle);
                        }
                        finally
                        {
                            NativeMethods.CloseHandle(threadHandle);
                        }
                    }
                };
    
                var threads = process.Threads.ToArray<ProcessThread>();
    
                if (threads.Length > 1)
                {
                    Parallel.ForEach(threads, new ParallelOptions { MaxDegreeOfParallelism = threads.Length }, pt =>
                    {
                        resume(pt);
                    });
                }
                else
                {
                    resume(threads[0]);
                }
            }
    
            #endregion
    
            #region Interop
    
            static class NativeMethods
            {
                [DllImport("kernel32.dll")]
                [return: MarshalAs(UnmanagedType.Bool)]
                public static extern bool CloseHandle(IntPtr hObject);
    
                [DllImport("kernel32.dll")]
                public static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
    
                [DllImport("kernel32.dll")]
                public static extern uint SuspendThread(IntPtr hThread);
    
                [DllImport("kernel32.dll")]
                public static extern uint ResumeThread(IntPtr hThread);
            }
    
            [Flags]
            enum ThreadAccess : int
            {
                TERMINATE = (0x0001),
                SUSPEND_RESUME = (0x0002),
                GET_CONTEXT = (0x0008),
                SET_CONTEXT = (0x0010),
                SET_INFORMATION = (0x0020),
                QUERY_INFORMATION = (0x0040),
                SET_THREAD_TOKEN = (0x0080),
                IMPERSONATE = (0x0100),
                DIRECT_IMPERSONATION = (0x0200)
            }
    
            #endregion
        }
    

    Start ffmpeg as below:

    process =new Process();
    
    process.StartInfo.FileName = "ffmpeg";
    process.StartInfo.Arguments = "-i foo.VOB blabla.mp4";
    
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    
    process.Start();
    

    Use process.Suspend(); for Pause and process.Resume(); for Resume. Note that ffmpeg MUST start from your application. I tested it in windows application and it worked fine.