如何使用 C# 优雅地关闭 VLC

How to close VLC gracefully using C#

我正在 运行安装监控系统,想将一些闭路电视摄像机的视频录制到我的电脑上。

我可以像这样使用 VLC 命令行进行录制,

vlc rtsp://*username*:*password*@192.168.1.60:554/ch01/0  --qt-start-minimized --sout=#transcode{ab=128,channels=2,samplerate=44100,scodec=none}:file{dst=D:\CCTV\Concord19_05_2419-05-24_2111_C1.mp4,no-overwrite}

但是我想每半小时停止并重新开始录制,这样我得到的文件足够小,我可以使用。

我编写了一个 C# 应用程序来执行此操作,它只是终止所有 VLC 进程并启动新进程。它由任务调度程序在半小时触发。

当我 运行 在任务栏中显示正常的 VLC 实例时,这有效。但是我希望它们不在系统托盘中。我可以通过添加这个 VLC 选项来做到这一点,

--qt-start-minimized

如果我查看任务管理器,运行它在后台进程中。

我的代码是这样做的,

foreach(Process process in Process.GetProcesses().Where(x => x.ProcessName == "vlc"))
{
    Process.GetProcessById(id).CloseMainWindow();
}

但是 VLC 不再有主 window,所以这不起作用。

如果我这样做,

Process.GetProcessById(id).Kill();

视频损坏,因为 VLC 不正常存在。

我尝试了其他方法 Close、Dispose,但它们不起作用。

在我看来,我需要在调用 CloseMainWindow 之前先将这些 windows 最大化,或者找到其他方法退出它们,或者如果 VLC 中有一个选项可以每半分钟启动一个新文件小时?

"Kill is the only way to terminate processes that do not have graphical interfaces."

所以基本上,您必须完成这项工作的唯一机会是检查 VLC 进程是否提供 一种控制它的方法,同时 运行 在后台 :在这个这样,您可以先停止录制进程,然后然后终止进程

我不知道它公开了哪些功能,但您可以使用 或检查一些 dbus 命令?

尝试使用 RC(远程命令)界面调用 vlc 命令。 可以在此处找到文档:https://wiki.videolan.org/documentation:modules/rc/ 如果您使用远程命令启动 vlc,则可以通过 websocked 发送命令以停止录制或关闭 vlc。

尝试添加到您的命令中

--intf rc --rc-host="my-ip:my-port" --rc-quiet --rc-extend

可用命令列表为:

longhelp
+----[ Remote control commands ]
|
| add XYZ  . . . . . . . . . . . . add XYZ to playlist
| enqueue XYZ  . . . . . . . . . queue XYZ to playlist
| playlist . . . . .  show items currently in playlist
| play . . . . . . . . . . . . . . . . . . play stream
| stop . . . . . . . . . . . . . . . . . . stop stream
| next . . . . . . . . . . . . . .  next playlist item
| prev . . . . . . . . . . . .  previous playlist item
| goto . . . . . . . . . . . . . .  goto item at index
| repeat [on|off] . . . .  toggle playlist item repeat
| loop [on|off] . . . . . . . . . toggle playlist loop
| random [on|off] . . . . . . .  toggle random jumping
| clear . . . . . . . . . . . . . . clear the playlist
| status . . . . . . . . . . . current playlist status
| title [X]  . . . . . . set/get title in current item
| title_n  . . . . . . . .  next title in current item
| title_p  . . . . . .  previous title in current item
| chapter [X]  . . . . set/get chapter in current item
| chapter_n  . . . . . .  next chapter in current item
| chapter_p  . . . .  previous chapter in current item
|
| seek X . . . seek in seconds, for instance `seek 12'
| pause  . . . . . . . . . . . . . . . .  toggle pause
| fastforward  . . . . . . . .  .  set to maximum rate
| rewind  . . . . . . . . . . . .  set to minimum rate
| faster . . . . . . . . . .  faster playing of stream
| slower . . . . . . . . . .  slower playing of stream
| normal . . . . . . . . . .  normal playing of stream
| f [on|off] . . . . . . . . . . . . toggle fullscreen
| info . . . . .  information about the current stream
| stats  . . . . . . . .  show statistical information
| get_time . . seconds elapsed since stream's beginning
| is_playing . . . .  1 if a stream plays, 0 otherwise
| get_title . . . . .  the title of the current stream
| get_length . . . .  the length of the current stream
|
| volume [X] . . . . . . . . . .  set/get audio volume
| volup [X]  . . . . . . .  raise audio volume X steps
| voldown [X]  . . . . . .  lower audio volume X steps
| adev [X] . . . . . . . . . . .  set/get audio device
| achan [X]. . . . . . . . . .  set/get audio channels
| atrack [X] . . . . . . . . . . . set/get audio track
| vtrack [X] . . . . . . . . . . . set/get video track
| vratio [X]  . . . . . . . set/get video aspect ratio
| vcrop [X]  . . . . . . . . . . .  set/get video crop
| vzoom [X]  . . . . . . . . . . .  set/get video zoom
| snapshot . . . . . . . . . . . . take video snapshot
| strack [X] . . . . . . . . . set/get subtitles track
| key [hotkey name] . . . . . .  simulate hotkey press
| menu . . [on|off|up|down|left|right|select] use menu
|
| @name marq-marquee  STRING  . . overlay STRING in video
| @name marq-x X . . . . . . . . . . . .offset from left
| @name marq-y Y . . . . . . . . . . . . offset from top
| @name marq-position #. . .  .relative position control
| @name marq-color # . . . . . . . . . . font color, RGB
| @name marq-opacity # . . . . . . . . . . . . . opacity
| @name marq-timeout T. . . . . . . . . . timeout, in ms
| @name marq-size # . . . . . . . . font size, in pixels
|
| @name logo-file STRING . . .the overlay file path/name
| @name logo-x X . . . . . . . . . . . .offset from left
| @name logo-y Y . . . . . . . . . . . . offset from top
| @name logo-position #. . . . . . . . relative position
| @name logo-transparency #. . . . . . . . .transparency
|
| @name mosaic-alpha # . . . . . . . . . . . . . . alpha
| @name mosaic-height #. . . . . . . . . . . . . .height
| @name mosaic-width # . . . . . . . . . . . . . . width
| @name mosaic-xoffset # . . . .top left corner position
| @name mosaic-yoffset # . . . .top left corner position
| @name mosaic-offsets x,y(,x,y)*. . . . list of offsets
| @name mosaic-align 0..2,4..6,8..10. . .mosaic alignment
| @name mosaic-vborder # . . . . . . . . vertical border
| @name mosaic-hborder # . . . . . . . horizontal border
| @name mosaic-position {0=auto,1=fixed} . . . .position
| @name mosaic-rows #. . . . . . . . . . .number of rows
| @name mosaic-cols #. . . . . . . . . . .number of cols
| @name mosaic-order id(,id)* . . . . order of pictures
| @name mosaic-keep-aspect-ratio {0,1} . . .aspect ratio
|
| help . . . . . . . . . . . . . . . this help message
| longhelp . . . . . . . . . . . a longer help message
| logout . . . . . . .  exit (if in socket connection)
| quit . . . . . . . . . . . . . . . . . . .  quit vlc
|
+----[ end of help ]

这个问题和你的类似,这个具体的回答解释了为什么 CTRLC 不是正确的关闭方式:VLC screen capture using terminal.

用法示例:http://sureskumar.com/RemoteVLC/#examples(Arduino代码但易于理解)

感谢 Norcino,您的解决方案运行良好。我添加了你提到的选项,

-I rc --rc-host=192.168.1.4:10001 --rc-quiet

那我的C#是这样的,

KillSingleInstance(10001);

public void KillSingleInstance(int port)
{
    List<byte> ip = new List<byte>();

    ip.Add(192);
    ip.Add(168);
    ip.Add(1);
    ip.Add(4);

    IPAddress ipAddress = new IPAddress(ip.ToArray());
    IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);

    Socket sender = new Socket(ipAddress.AddressFamily,  
        SocketType.Stream, ProtocolType.Tcp); 

    sender.Connect(remoteEP);

    byte[] msg = Encoding.ASCII.GetBytes("quit\n"); 

    sender.Send(msg);

    sender.Shutdown(SocketShutdown.Both);  
    sender.Close();
}

VLC 实例完全 运行 在后台。

此外,它还有一个 try 和 catch 块等。将进行更多测试,但目前运行良好。