Gstreamer:将一个带有两个水槽的垃圾箱连接到 playbin2

本文关键字:垃圾箱 playbin2 连接 两个 一个 Gstreamer | 更新日期: 2023-09-27 18:30:23

我想读取SDP文件并将视频流编码为h.264,将音频流编码为aac。然后我想将这些流多路复用到 avi 流中,然后多路复用到一个文件。我提前不知道SDP文件的内容,所以使用playbin2似乎是最简单的。

所以,我想我可以做这样的事情:

                             RawToAviMux Bin
                       ______________________________________
                ----- |ghostpad----x264enc
              /       |                   '
playbin2------        |                    avimux--filesink
              '       |                    /
               -------| ghostpad----ffenc_aac
                      |_______________________________________
 setting playbin2's videosink to an instance of RawToAviMux
      and playbin2's audiosink to the same instance of RawToAviMux

但是,我无法使管道进入播放状态。

这是代码:

            recorder = new Gst.BasePlugins.PlayBin2();
            recorder.PlayFlags &= ~((Gst.BasePlugins.PlayBin2.PlayFlagsType)(1 << 2));
            recorder.Bus.AddSignalWatch();
            recorder.Bus.EnableSyncMessageEmission();
            RawToAviMuxer aviMuxer = new RawToAviMuxer(fileName);               
            recorder.VideoSink = aviMuxer;
            recorder.AudioSink = aviMuxer;
            recorder.SetState(Gst.State.Ready);
            recorder.Uri = @"file:///" + filePath.Replace('''', '/');
            recorder.SetState(Gst.State.Paused);
            recorder.SetState(Gst.State.Playing);
            Gst.State currentState;
            Gst.State playingState = Gst.State.Playing;
            Gst.StateChangeReturn stateReturn = recorder.GetState(out currentState, out playingState, Gst.Clock.Second);
            if (stateReturn != Gst.StateChangeReturn.Failure)
                return true;
            return false;

与 RawToAviMuxer 作为

public class RawToAviMuxer : Gst.Bin
{
    bool test = false;
    public RawToAviMuxer(string outputFileName)
        : base("rawToAviMux")
    {
        Gst.Element x264Enc = Gst.ElementFactory.Make("x264enc");
        Gst.Element ffenc_aac = Gst.ElementFactory.Make("ffenc_aac");
        x264Enc["bframes"] = (uint)0;
        x264Enc["b-adapt"] = false;
        x264Enc["bitrate"] = (uint)1024;
        x264Enc["tune"] = 0x4;
        x264Enc["speed-preset"] = 3;
        x264Enc["sliced-threads"] = false;
        x264Enc["profile"] = 0;
        x264Enc["key-int-max"] = (uint)30;
        Gst.GhostPad videoToX264Pad = new Gst.GhostPad("video_sink", x264Enc.GetStaticPad("sink"));
        Gst.GhostPad audioToAACPad = new Gst.GhostPad("audio_sink", ffenc_aac.GetStaticPad("sink"));
        test = this.AddPad(videoToX264Pad);
        test = this.AddPad(audioToAACPad);
        Gst.Element aviMux = Gst.ElementFactory.Make("avimux");
        Gst.Element fileSink = Gst.ElementFactory.Make("filesink");
        test = this.Add(new Gst.Element[]{x264Enc, ffenc_aac, aviMux, fileSink});
        test = x264Enc.Link(aviMux);
        test = ffenc_aac.Link(aviMux);
        test = aviMux.Link(fileSink);
        fileSink["location"] = outputFileName;
    }
}

我已经在调试器中逐步完成,所有链接都成功。

更新

好的,所以我使用 Gst.Parse.Launch 尝试了以下管道:

uridecodebin uri=file:///C:/Users/Jonathan/AppData/Local/Temp/192.168.0.215_5000.sdp !
x264enc byte-stream=true bframes=0 b-adapt=0 tune=0x4 speed-preset=3 sliced-threads=false 
profile=0 ! mux. ffenc_aac ! mux. avimux name=mux ! filesink location=C:'Users'Jonathan'Desktop'test.avi

我仍然无法摆脱暂停。

我正在使用Windows构建,所以我担心可能有什么问题?

我也无法将消息处理程序附加到总线上,以便我可以弄清楚发生了什么,这真的开始变得烦人了。

然而,我确实发现了这个,

如果我直接通过 udpsrc 元素抓取流,提前知道格式是什么,它不适用于仅使用 rtph264depay 元素。管道中必须有一个 h264parse 元素。这可能是uridecodebin对我不起作用的原因?

解决我最终做了以下事情:

            if (!gst_is_init)
            {                
                Gst.Application.Init();
                gst_is_init = true;
            }
            if(recorder != null)
            {
                recorder.SetState(Gst.State.Null);
                recorder.Dispose();
            }
            string videoDepay, audioDepay, strExtension, strMuxer;
            GetGstElements(stream.VideoCaps, out videoDepay, out strMuxer, out strExtension);
            GetGstElements(stream.AudioCaps, out audioDepay, out strMuxer, out strExtension);
            fileName = Path.ChangeExtension(fileName, strExtension);
            //recorder = new Gst.Pipeline("recordingPipe");
            string pipeString = String.Format("udpsrc port={0} ! {1} {2} ! {3} ! queue ! mux. udpsrc port={4} ! {1} {5} ! {6} ! mux. {7} name=mux ! filesink location={8}",
                portToUse, "application/x-rtp,", stream.VideoCaps, videoDepay, (portToUse + 2), stream.AudioCaps, audioDepay, strMuxer, fileName.Replace("''", "''''"));
            recorder = (Gst.Pipeline)Gst.Parse.Launch(pipeString);                
            recordingFileName = fileName;
                 recorder.SetState(Gst.State.Ready);                
            recorder.SetState(Gst.State.Paused);                
            recorder.SetState(Gst.State.Playing);
            Gst.State currentState;                
            Gst.StateChangeReturn stateReturn = recorder.GetState(out currentState, Gst.Clock.Second);            
            if (stateReturn != Gst.StateChangeReturn.Failure)
                return true;
            return false;

您必须为所有流提供一个解析器,以便管道进入播放状态。因此,在传入 h264 流的情况下,我需要使用 rtph264depay !h264解析。此外,NALU 和字节流必须匹配才能使时间正确。

此外,为了使文件可用,您必须在处置管道之前向下游发送 EOS。

                recorder.SendEvent(Gst.Event.NewEos());
                System.Threading.Thread.Sleep(100);
                recorder.SetState(Gst.State.Paused);
                recorder.SetState(Gst.State.Ready);
                recorder.SetState(Gst.State.Null);
                recorder.Dispose();              

Gstreamer:将一个带有两个水槽的垃圾箱连接到 playbin2

是的,这行不通。这是您可以做到的。Playbin2是一个模块化组件,它由一个uridecodebin和一个playsinkbin组成。您只需使用和 uridecodebin,设置媒体文件 uri,为焊盘添加添加信号处理程序,并将新创建的焊盘连接到 rawtoavimux 组件的接收器焊盘。

rawtoavimux的一种替代方法是使用encodebin。使用尿毒杆菌!编码箱可以潜在地进行智能转码,如果一个或多个流的格式已经正确,这将避免解码和重新编码。