2012-04-06 9 views
1

Ich möchte in einer SDP-Datei lesen und den Video-Stream in H.264 und den Audio-Stream in AAC zu kodieren. Dann möchte ich diese Streams in einen AVI-Stream und dann in eine Datei multiplexen. Ich kenne den Inhalt der SDP-Datei nicht im Voraus, daher scheint es am einfachsten zu sein, playbin2 zu verwenden.Gstreamer: Verknüpfen Sie ein Bin mit zwei Senken zu playbin2

Also, ich dachte, dass ich etwas tun könnte:

       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 

Allerdings kann ich nicht die Pipeline in das Spiel Zustand erhalten. Hier

ist der Code:

  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; 

Mit RawToAviMuxer als

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; 
    } 
} 

Ich habe in den Debugger und alle Links sind trat durch erfolgreich.

Update

Ok, also habe ich versucht, die folgende Pipeline mit 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 

Ich kann es immer noch nicht pausiert raus aus.

Ich benutze die Windows-Build, also mache ich mir Sorgen, vielleicht ist da etwas nicht in Ordnung?

Ich kann auch keinen Message-Handler an den Bus anschließen, so dass ich herausfinden kann, was los ist, was wirklich nervig wird.

Ich habe gerade dies jedoch zu finden,

Wenn ich direkt die Ströme über ein udpsrc Element greifen, zu wissen, was die Formate der Zeit voraus sind, ist es nicht nur mit einem rtph264depay Element funktioniert. In der Pipeline muss ein harliches Element vorhanden sein. Dies könnte der Grund sein, dass Uridecodebin für mich nicht funktioniert?

gelöst landete ich Sie folgendermaßen vorgehen:

  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; 

Sie haben einen Parser für alle Ströme haben, für die Pipeline zu spielen zu gehen. Also, im Falle eines eingehenden h264-Streams, müsste ich rtph264depay verwenden! h264parse. Außerdem müssen NALU und Byte-Stream übereinstimmen, damit das Timing richtig ist.

Damit die Datei verwendet werden kann, müssen Sie vor dem Entsorgen der Pipeline einen EOS Downstream senden.

   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();    

Antwort

1

Ja, das wird nicht funktionieren. Hier ist, wie Sie es tun können. Playbin2 ist eine modulare Komponente, es besteht aus einer Uridecodebin und einer Playskin. Sie können einfach und uridecodebin verwenden, Ihre Mediendatei uri einstellen, Signalhandler für pad-added hinzufügen und die neu erstellten Pads mit den Sink-Pads Ihrer rawtoavimux-Komponente verbinden.

Eine Alternative für rawtoavimux wäre die Verwendung von Encoderbin. Verwenden von Uridecodebin!Encodebin kann möglicherweise Smart-Transcodierung, die die Decodierung und Neucodierung vermeiden würde, wenn das Format eines oder mehrerer Streams bereits im richtigen Format ist.

+0

Ok, ich sehe den Uridecodebin Weg, es jetzt zu tun, danke! Allerdings kann ich den Encoder in gst-inspect nicht finden. –

+0

Es ist etwas neu. Ein paar Abweichungen können Sie neuere Gtreamer-Versionen (z. B. die Gstreamer-Entwickler-PPA auf Ubuntu) bekommen. – ensonic

+0

Nun, diese spezielle Komponente verwendet die Windows-Builds. Ich glaube nicht, dass sie es schon haben. Jedenfalls muss ich es bis dahin umcodieren. Vielen Dank! –

Verwandte Themen