问题
I want to read in an SDP file and encode the video stream into h.264 and the audio stream into aac. Then I want to multiplex those streams into an avi stream and then to a file. I don't know the contents of the SDP file ahead of time, so it seems easiest to use playbin2.
So, I thought I could do something like this:
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
However, I cannot get the pipeline into the playing state.
Here is the 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;
With RawToAviMuxer as
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;
}
}
I have stepped through in the debugger and all of the links are successful.
update
Ok, so I tried the following pipeline with 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
I still can't get it out of paused.
I am using the windows build, so I am worried maybe there is something wrong with that?
I also can't attach a message handler to the bus so that I can figure out what is going on, which is really starting to get annoying.
I did just find this however,
If I directly grab the streams via an udpsrc element, knowing what the formats are ahead of time, it does not work with just an rtph264depay element. There must be an h264parse element in the pipeline. This may be the reason that uridecodebin isn't working for me?
solved I ended up doing the following:
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;
You have to have a parser for all streams, for the pipeline to go to playing. So, in the case of an incomming h264 stream, I would need to use rtph264depay ! h264parse. In addition the NALU and byte-stream must match for the timing to be right.
Also, in order for the file to be usable, you have to send an EOS downstream before disposing of the pipeline.
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();
回答1:
Yes, this won't work. Here is how you can do it. Playbin2 is a modular component, it consists of an uridecodebin and a playsinkbin. You can just use and uridecodebin, set your media file uri, add signal handlers for pad-added and connect the newly created pads to the sink-pads of your rawtoavimux component.
One alternative for rawtoavimux would be to use encodebin. Using uridecodebin ! encodebin can potentially to smart transcoding which would avoid the decoding and re-encoding if the format of one or more stream is already in the correct format.
来源:https://stackoverflow.com/questions/10048757/gstreamer-link-a-bin-with-two-sinks-to-playbin2