Hello, 各位 iT 邦幫忙 的粉絲們大家好~~~
在本系列文因為工作上的產品應用需求,進而探索到很多層面的點滴事。透過每篇 EP 的分享把這些點滴整理,看起來或許像是個獨立的小品抒發文、也或許是一系列技術研究文!?
總之,就當作的隨手雜記文吧!
本篇是 莫名其妙就跟世界等級的 OpenSource 專案攪和了!? 系列文的 EP14。
好了,所以本回進入重頭戲。
如果想回應 EP01 所提及的,完全透過 C# 程式來執行出 EP13 的 gstreamer 轉檔處理,而不是透過命令的方式來讓 gstreamer 完成呢?!
那這時候就得仰賴 gstreamer-sharp 的使用了。
如果是要在 Windows 上使用 Gstreamer 的話,注意 Gstreamer 官網有特別提及的安裝版本為 msvc 版本:
(取自 gstreamer 官網 Windows 安裝)
並且在 Download Gstreamer 的網頁上也有特別標註兩點 Note:
(取自 gstreamer 官網 Download)
各位不要用錯囉!
接著再把上一回所使用的 gstreamer pipeline 指令:
filesrc location="c:/tmp/bbb_sunflower.mp4" ! qtdemux ! avdec_h264 ! clockoverlay time-format="%Y-%m-%d %H:%M:%S" valignment=top halignment=right xpad=12 ypad=6 shaded-background=true font-desc="Sans, 12" ! videoconvert ! qsvh264enc ! h264parse ! mp4mux ! filesink location="c:/tmp/new_bbb_sunflower.mp4"
而透過 gstreamer-sharp 的使用,就能透過以下 C# 程式敘述碼達成上述指令效果:
Gst.Application.Init();
GtkSharp.GstreamerSharp.ObjectManager.Initialize();
var mediaFilePath = System.IO.Path.Combine(OperatingSystem.IsWindows() ? "c:/" : "/", "tmp");
var input = $"{mediaFilePath}/bbb_sunflower.mp4";
var output = $"{mediaFilePath}/new_bbb_sunflower.mp4";
var pipeline = new Pipeline("convert-file-pipeline");
var filesrc = ElementFactory.Make("filesrc", "src");
var demux = ElementFactory.Make("qtdemux", "demux");
var dec = ElementFactory.Make("avdec_h264", "dec");
var overlay = ElementFactory.Make("clockoverlay", "overlay");
var convert = ElementFactory.Make("videoconvert", "convert");
var enc = ElementFactory.Make("qsvh264enc", "enc") ?? ElementFactory.Make("x264enc", "enc");
var parse = ElementFactory.Make("h264parse", "parse");
var mux = ElementFactory.Make("mp4mux", "mux");
var sink = ElementFactory.Make("filesink", "sink");
if (filesrc == null || demux == null || dec == null || overlay == null ||
convert == null || enc == null || parse == null || mux == null || sink == null)
{
Console.Error.WriteLine("Failed to create one or more elements.");
return;
}
filesrc.SetProperty("location", new GLib.Value(input));
overlay.SetProperty("time-format", new GLib.Value("%Y-%m-%d %H:%M:%S"));
overlay.SetProperty("valignment", new GLib.Value(2));
overlay.SetProperty("halignment", new GLib.Value(2));
overlay.SetProperty("xpad", new GLib.Value(12));
overlay.SetProperty("ypad", new GLib.Value(6));
overlay.SetProperty("shaded-background", new GLib.Value(true));
overlay.SetProperty("font-desc", new GLib.Value("Sans, 12"));
sink.SetProperty("location", new GLib.Value(output));
pipeline.Add(filesrc, demux, dec, overlay, convert, enc, parse, mux, sink);
filesrc.Link(demux);
dec.Link(overlay);
overlay.Link(convert);
convert.Link(enc);
enc.Link(parse);
parse.Link(mux);
mux.Link(sink);
demux.PadAdded += (o, e) =>
{
var sinkPad = dec.GetStaticPad("sink");
if (sinkPad == null || sinkPad.IsLinked)
return;
var caps = e.NewPad.CurrentCaps ?? e.NewPad.QueryCaps(null);
var name = caps?.ToString() ?? "";
if (!name.Contains("video"))
return;
var res = e.NewPad.Link(sinkPad);
Console.WriteLine($"Linked demux:{e.NewPad.Name} -> dec:sink = {res}");
};
var loop = new GLib.MainLoop();
var bus = pipeline.Bus;
bus.AddSignalWatch();
bus.Message += (o, e) =>
{
switch (e.Message.Type)
{
case MessageType.Error:
e.Message.ParseError(out var err, out var dbg);
Console.Error.WriteLine($"Error: {err.Message}{Environment.NewLine}{dbg}");
loop.Quit();
break;
case MessageType.Eos:
Console.WriteLine("Done.");
loop.Quit();
break;
}
};
pipeline.SetState(State.Playing);
loop.Run();
pipeline.SetState(State.Null);
(上述 C# 程式敘述經 "咒語" 產生,再經過人工初步校閱修改後完成)
透過 LINQPad 的直接執行:
透過 LINQPad 的執行完成: