C#调用FFMPEG实现桌面录制(视频+音频+生成本地文件)

不得不说FFMPEG真是个神奇的玩意,所接触的部分不过万一。网上有个很火的例子是c++方面的,当然这个功能还是用c++来实现比较妥当。

然而我不会c++

因为我的功能需求比较简单,只要实现基本的录制就可以了,其实就是一句命令的事

先来代码:RecordHelper类

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.DirectX;
using Microsoft.DirectX.DirectSound;
using System.Runtime.InteropServices;

namespace ClassTool
{
    public class RecordHelper
    {
        #region 模拟控制台信号需要使用的api

        [DllImport("kernel32.dll")]
        static extern bool GenerateConsoleCtrlEvent(int dwCtrlEvent, int dwProcessGroupId);

        [DllImport("kernel32.dll")]
        static extern bool SetConsoleCtrlHandler(IntPtr handlerRoutine, bool add);

        [DllImport("kernel32.dll")]
        static extern bool AttachConsole(int dwProcessId);

        [DllImport("kernel32.dll")]
        static extern bool FreeConsole();

        #endregion

        // ffmpeg进程
        static Process p = new Process();

        // ffmpeg.exe实体文件路径
        static string ffmpegPath = AppDomain.CurrentDomain.BaseDirectory + "ffmpeg\\ffmpeg.exe";

        /// <summary>
        /// 获取声音输入设备列表
        /// </summary>
        /// <returns>声音输入设备列表</returns>
        public static CaptureDevicesCollection GetAudioList()
        {
            CaptureDevicesCollection collection = new CaptureDevicesCollection();

            return collection;
        }

        /// <summary>
        /// 功能: 开始录制
        /// </summary>
        public static void Start(string audioDevice, string outFilePath)
        {
            if (File.Exists(outFilePath))
            {
                File.Delete(outFilePath);
            }

            /*转码,视频录制设备:gdigrab;录制对象:桌面;
             * 音频录制方式:dshow;
             * 视频编码格式:h.264;*/
            ProcessStartInfo startInfo = new ProcessStartInfo(ffmpegPath);
            startInfo.WindowStyle = ProcessWindowStyle.Normal;
            startInfo.Arguments = "-f gdigrab -framerate 15 -i desktop -f dshow -i audio=\"" + audioDevice + "\" -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -acodec libmp3lame \"" + outFilePath + "\"";

            p.StartInfo = startInfo;

            p.Start();
        }

        /// <summary>
        /// 功能: 停止录制
        /// </summary>
        public static void Stop()
        {
            AttachConsole(p.Id);
            SetConsoleCtrlHandler(IntPtr.Zero, true);
            GenerateConsoleCtrlEvent(0, 0);
            FreeConsole();
        }
    }
}

开始那几个api接口是用来模拟ctrl+c命令的。本来以为在停止录制的时候直接kill掉进程就好,结果导致生成的视频文件直接损坏了。手动使用ffmpeg.exe的时候发现ctrl+c可以直接结束录制并且不会损坏视频文件,于是采用这种方法,在点击停止按钮时模拟ctrl+c来退出ffmpeg。

ffmpeg的命令参数里,gdigrab是ffmpeg内置的屏幕录制设备,但是这个设备不能同时采集音频,于是又用到了后面的dshow。这里有个问题很奇怪,用ffmpeg获取音频设备列表时,设备的名称如果超过31个字符的话会被截断,而若是将完整的设备名传到参数里则无法进行音频采集,只能将截断的设备名称传进去,不知道为什么……

posted @ 2015-07-21 16:55  Pavel_Yang  阅读(14369)  评论(5编辑  收藏  举报