I'm trying to test udp streaming on localhost but it's not showing anything:
videotestsrc (or audiotestsrc) -> udpsink (port: 5078, host: 127.0.0.1)
Here is the code:
console_out_inf("TESTING", "Starting work with test elements");
gint port = 5078;
// TEST PIPELINE OUT
gst_bin_add_many(GST_BIN(GSD->pipetest_out), GSD->testsrc, GSD->udpsink, NULL);
gchar* host = "127.0.0.1";
g_object_set(GSD->udpsink, "port", port, NULL);
g_object_set(GSD->udpsink, "host", host, NULL);
if (!gst_element_link(GSD->testsrc, GSD->udpsink))
console_out_bad("STREAMING", "Error linking test udp elements -- SEND");
else
console_out_yes("STREAMING", "Correctly linked test udp elements -- SEND");
// TEST PIPELINE IN
gst_bin_add_many(GST_BIN(GSD->pipetest_in), GSD->udpsrc, GSD->autovideosink, NULL);
gst_element_set_state(GSD->udpsrc, GST_STATE_NULL);
g_object_set(GSD->udpsrc, "port", port, NULL);
if (!gst_element_link(GSD->udpsrc, GSD->autovideosink))
console_out_bad("STREAMING", "Error linking test udp elements -- RECEIVE");
else
console_out_yes("STREAMING", "Correctly linked test udp elements -- RECEIVE");
// PLAY TEST PIPELINE OUT
GstStateChangeReturn ret1;
ret1 = gst_element_set_state(GSD->pipetest_out, GST_STATE_PLAYING);
if (ret1 == GST_STATE_CHANGE_FAILURE)
console_out_bad("TESTING", "Failed playing pipetest out");
else
console_out_yes("TESTING", "Correctly played pipetest out");
// PLAY TEST PIPELINE IN
GstStateChangeReturn ret2;
ret2 = gst_element_set_state(GSD->pipetest_in, GST_STATE_PLAYING);
if (ret2 == GST_STATE_CHANGE_FAILURE)
console_out_bad("TESTING", "Failed playing pipetest in");
else
console_out_yes("TESTING", "Correctly played pipetest in");
// PRINT PIPELINES
GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(GSD->pipetest_out), GST_DEBUG_GRAPH_SHOW_ALL, "pipetest_out");
GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(GSD->pipetest_in), GST_DEBUG_GRAPH_SHOW_ALL, "pipetest_in");
This is "my own console output":
EDIT: not relevant anymore! Everything is instanciated fine, the pipeline was built correctly, yet with
PIPELINE OUT: videotestsrc --> udpsink (host:127.0.0.1, port: 5078)
PIPELINE IN: udpsrc (port: 5078) --> autovideosink
The autovideosink does not display anything!
By checking netstat -a, no connection on such port is showed.
Additional INFO:
The graph generated with "gstreamer debugging" contains of course only the video/audio testsrc element connected to udpsink.
The first time I run that code, the "Windows Firewall Window" appeared, so I guess something is being sent/received.
This is inside a Visual Studio 2013/Qt5 Add-In Project, but that should not be an issue
Does anyone know what am I doing wrong?
This code seems fine but it doesn't relate to the console output you posted.
Try testing your pipeline piece by piece with the command line gst-launch:
gst-launch-1.0 -e -v videotestsrc ! udpsink host="127.0.01"
connected to a fakesink first and then swapping in the udp sink, once you have it working in the command line mirror the command in code.
try it with host="localhost" or host="192.168.0.1" i can't remember but i think udpsink might have trouble sending to the loopback
Related
I am able to play a video on the command line with gstreamer's gst-launch like this:
gst-launch gnlfilesource location=file:///tmp/myfile.mov start=0 duration=2000000000 ! autovideosink
This plays the first 2 seconds of the file in /tmp/myfile.mov, afterwards the video playback stops. Is there anyway to get this to loop repeatidly? i.e. turn the 2 second long gnlfilesource into an infinite length video that plays those 2 seconds again and again and again?
If using gst-launch then you may have to use while true; do [your command]; done as Fredrik has stated. However if interested in C code, I have written a code which may help you. Looping of video every 2 seconds from the beginning of the file at the end of the stream of first run.
//(c) 2011 enthusiasticgeek
// This code is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#include <gst/gst.h>
gboolean bus_callback(GstBus *bus, GstMessage *msg, gpointer data)
{
GstElement *play = GST_ELEMENT(data);
switch (GST_MESSAGE_TYPE(msg))
{
case GST_MESSAGE_EOS:
/* restart playback if at end */
if (!gst_element_seek(play,
1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
GST_SEEK_TYPE_SET, 2000000000, //2 seconds (in nanoseconds)
GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
g_print("Seek failed!\n");
}
break;
default:
break;
}
return TRUE;
}
gint
main (gint argc,
gchar *argv[])
{
GMainLoop *loop;
GstElement *play;
GstBus *bus;
/* init GStreamer */
gst_init (&argc, &argv);
loop = g_main_loop_new (NULL, FALSE);
/* make sure we have a URI */
if (argc != 2) {
g_print ("Usage: %s <URI>\n", argv[0]);
return -1;
}
/* set up */
play = gst_element_factory_make ("playbin", "play");
g_object_set (G_OBJECT (play), "uri", argv[1], NULL);
bus = gst_pipeline_get_bus (GST_PIPELINE (play));
gst_bus_add_watch (bus, bus_callback, play);
gst_object_unref (bus);
gst_element_set_state (play, GST_STATE_PLAYING);
/* now run */
g_main_loop_run (loop);
/* also clean up */
gst_element_set_state (play, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (play));
return 0;
}
Update:
See the following link
http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/chapter-dataaccess.html
[Section 19.1.2. Play a region of a media file]. This could be used in conjugation with my code.
This seems to be possible with multifilesrc plugin,
gst-launch-1.0 multifilesrc location=alien-age.mpg loop=true ! decodebin ! autovideosink
Seems to be added back in June 2011.
According to folks on the #gstreamer IRC channel, you can't do this with gstreamer itself, you'd need something outside the gstreamer pipeline to loop it.
multifilesrc is the easiest way, but it won't work on media files that have "Media length" known. you can loop on any video files only if file does not have any information about the time or length.
Open your file with any media player, if it shows media length or if you can seek the file forward or backward, that means it knows the media length and multifilesrc won't loop it.
How to convert video file into file without time track (stream file) with GStreamer:
you need to run two pipelines on command line, first run the recorder:
gst-launch-1.0 udpsrc port=10600 ! application/x-rtp-stream ! rtpstreamdepay name=pay1 ! rtph264depay ! h264parse ! video/x-h264,alignment=nal ! filesink location=my_timeless_file.mp4
it starts and waits for incoming stream.
on another terminal run the play pipeline:
gst-launch-1.0 filesrc location=my_file_with_time_track ! queue ! decodebin ! videoconvert ! x264enc ! h264parse config-interval=-1 ! rtph264pay pt=96 ! rtpstreampay name=pay0 ! udpsink host=127.0.0.1 port=10600
play pipeline starts and eventually terminates when it streamed whole file, now go back to the first command line and terminate recording pipeline with Ctrl+C.
(instead of udpsrc/udpsink you can use any other mechanisms to make the stream, like appsrc/appsink)
Now you have a new file which can be used in multifilesrc with loop:
gst-launch-1.0 multifilesrc location=my_timeless_file.mp4 loop=true ! queue ! decodebin ! videoconvert ! ximagesink
Why multifilesrc does not loop files with known length?
Because when length of media is known it sends EOS message downstream and causes whole pipeline going to state NULL, by removing that information when it reaches end of file (byte stream) it tries to find next file to play (remember it is "multi" file source, and by default can accept wildcard location like "image_%d.png"). When there is no wildcard to point to the next file, it loops back to only known file.
It's not looping file in stream on gstreamer, but I was able to do it with ffmpeg -stream_loop option.
https://ffmpeg.org/ffmpeg.html#Main-options
$ ffmpeg -re -stream_loop -1 -i /tmp/sample.mp4 -f rtsp rtsp://localhost:8554/stream
Assuming bash...
Wrap it in a while-loop?
while true; do [your command]; done
where true does nothing sucessfully, i.e.
true: true
Return a successful result.
Exit Status:
Always succeeds.
It allows you to create infinite loops, e.g.
$ while true; do echo "run..."; sleep 1; done
run...
run...
run...
run...
run...
...
I am new to Gstreamer. I wrote a simple RTSP server that generates a pipeline like:
appsrc name=vsrc is-live=true do-timestamp=true ! queue ! h264parse ! rtph264pay name=pay0 pt=96
The SDP response is generated after the DESCRIBE request, but only after a few frames on the signal have been received by the appsrc input:
vsrc = gst_bin_get_by_name_recurse_up(GST_BIN(element), "vsrc"); // appsrc
if (nullptr != vsrc)
{
gst_util_set_object_arg(G_OBJECT(vsrc), "format", "time");
g_signal_connect(vsrc, "need-data", (GCallback)need_video_data, streamResource);
}
The time from which the video is to be played is passed in the RTSP request PLAY, in the Range header as an absolute:
PLAY rtsp://172.19.9.65:554/Recording/ RTSP/1.0
CSeq: 4
Immediate: yes
Range: clock=20220127T082831.039Z- // Start from ...
To the object GstRTSPClient attached the handler to the signal in which I process this request and make the move to the right time in my appsrc
g_signal_connect(client, "pre-play-request", (GCallback)pre_play_request, NULL);
The problem is that at this point my appsrc's start time frames have already arrived in pipline and I watch them first, and then the playback continues from the time specified in the PLAY request.
Can you please tell me how I can cut off these initial frames that came in before the PLAY call.
I've tried:
gst_element_seek - doesn't help because of peculiarities of appsrc implementation
Flush didn't help either, tried resetting sink at element rtph264pay:
gst_pad_push_event(sinkPad, gst_event_new_flush_start());
GST_PAD_STREAM_LOCK(sinkPad);
// ... seek in appsrc
gst_pad_push_event(sinkPad, gst_event_new_flush_stop(TRUE));
GST_PAD_STREAM_UNLOCK(sinkPad);
gst_object_unref(sinkPad);
Thank You!
I am trying to make a tiny cpp program module that makes live stream from camera, I am using gstreamer1.0 and I have plugins 1.6 and gst-rtsp-server-1.6.0 . I am able to start stream but when I try to stop and start again it does not start again.
my pipeline is:
std_pipeline = "videotestsrc ! video/x-raw ! "
"videoconvert ! x264enc ! rtph264pay"
and I am initializing with functions below:
gst_rtsp_server_new();
gst_rtsp_server_get_mount_points(server);
gst_rtsp_media_factory_new();
gst_rtsp_media_factory_set_launch(factory, std_pipeline);
gst_rtsp_mount_points_add_factory(mounts, "/stream", factory);
gst_rtsp_server_attach(server, NULL);
to start stream I call in another thread:
g_main_loop_run(loop);
and I am try to destroy everything with:
GstRTSPSessionPool *pool
gst_rtsp_server_get_session_pool (server);
gst_rtsp_session_pool_filter (pool,
(GstRTSPSessionPoolFilterFunc) remove_func, server);
g_object_unref (pool);
g_source_remove(server_id);
mounts = gst_rtsp_server_get_mount_points(server);
gst_rtsp_mount_points_remove_factory(mounts, "/stream");
gst_object_unref(mounts);
g_main_loop_quit(loop);
and the stream stops but when I try to init and start stream again it does not start.
UPDATE::
I want to stream video data (H264) through RTSP in Gstreamer.
gst_rtsp_media_factory_set_launch (factory, "videotestsrc ! x264enc ! rtph264pay name=pay0 pt=96 ");
I want "videotestsrc ! x264enc ! rtph264pay name=pay0 pt=96" this pipeline would also be in C programming in place of direct command.
Actually I have custom pipeline, i want to pass this pipeline to GstRTSPMediaFactory.
With launch i am not able to pass my pipline.
source = gst_element_factory_make("videotestsrc", "test-source");
parse = gst_element_factory_make("x264enc", "parse");
sink = gst_element_factory_make("rtph264pay", "sink");
gst_bin_add_many(GST_BIN(pipeline), source, parse, sink, NULL);
gst_element_link_many(source, parse, sink, NULL);
Now, I want to stream this pipeline using RTSP. I can stream with gst_rtsp_media_factory_set_launch,
But i want to pass only pipeline variable, and has to stream the video.
Can it possible, if so How?
I Modified the rtsp-media-factory.c as follows,
Added GstElement *pipeline in struct _GstRTSPMediaFactoryPrivate.
And the Added two more functions get_pipeline & set pipeline
void
gst_rtsp_media_factory_set_launch_pipeline (GstRTSPMediaFactory * factory, GstElement *pipeline)
{
g_print("PRASANTH :: SET LAUNCH PIPELINE\n");
GstRTSPMediaFactoryPrivate *priv;
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
g_return_if_fail (pipeline != NULL);
priv = factory->priv;
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
// g_free (priv->launch);
priv->pipeline = pipeline;
Bin = priv->pipeline;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
}
In the Same way get also.
And at last in place of gst_parse_launch in function default_create_element,
added this line
element = priv->pipeline; // priv is of type GstRTSPMediaFactoryPrivate
return element;
but I am not able to receive the data.
When i put pay0 for rtpmp2pay it is working.
But it is working for once only. If Client stops and again starts its not working. To work it, again i am restarting the server.
What is the problem?
** (rtsp_server:4292): CRITICAL **: gst_rtsp_media_new: assertion 'GST_IS_ELEMENT (element)' failed
To have some answer here.
It solves the main problem according to comments discussion, but there is still problem with requesting another stream (when stopping and starting client).
The solution was to add proper name for payloader element as stated in docs:
The pipeline description should contain elements named payN, one for each
stream (ex. pay0, pay1, ...). Also, for increased compatibility each stream
should have a different payload type which can be configured on the payloader.
So this has to be changed to:
sink = gst_element_factory_make("rtph264pay", "pay0");
notice the change in name of element from sink -> pay0.
For the stopping client issue I would check if this works for parse version.
If yes then check if the parse pipeline string (in original source code of rtsp server) is saved anywhere and reused after restart.. you need to debug this.
I am designing a pipeline to Encode a video frame from a opencv application (got from a web cam) to video/x-h264 format, send it via network and decode it on another device of different type (probably a raspberry pi ) to a proper RGB stream for my project.
For this I am supposed to use a hardware accelerated Encoder and Decoder.
Since , the whole scenario is huge , the current development is performed on a Intel machine using the gstreamer VAAPI plugins(vaapiencode_h264 & vaapidecode ) . Ánd also, the fact that we need to NOT use any of the networking plugins like TCPServer or UDPServer
For this I have used the below pipeline for my purpose :
On the Encoder End:
appsrc name=applicationSource ! videoconvert ! video/x-raw, format=I420, width=640, height=480,framerate=30/1, pixel-aspect-ratio=1/1,interlace-mode=progressive ! vaapiencode_h264 bitrate=600 tune=high-compression ! h264parse config-interval=1 ! appsink name=applicationSink sync=false
The Appsrc part works perfectly well while the appsink part is having some issue with it.
The appsink part of this pipeline has been set with the below caps:
"video/x-h264, format=(string){avc,avc3,byte-stream },alignment=(string){au,nal};video/mpeg, mpegversion=(int)2, profile=(string)simple"
The code for the data extraction of my appsink is
bool HWEncoder::grabData()
{
// initial checks..
if (!cameraPipeline)
{
GST_ERROR("ERROR AS TO NO PIPE FOUND ... Stopping FRAME GRAB HERE !! ");
return false;
}
if (gst_app_sink_is_eos (GST_APP_SINK(applicationSink)))
{
GST_WARNING("APP SINK GAVE US AN EOS! BAILING OUT ");
return false;
}
if (sample)
{
cout << "sample available ... unrefing it ! "<< endl;
gst_sample_unref(sample);
}
sample = gst_app_sink_pull_sample (GST_APP_SINK(applicationSink));
if (!sample)
{
GST_WARNING("No valid sample");
return false; // no valid sample pulled !
}
sink_buffer = gst_sample_get_buffer(sample);
if (!sink_buffer)
{
GST_ERROR("No Valid Buffer ");return false;
}
return true;
}
After bringing up the pipeline and checking for the buffer filling up in my appsink, I am getting stuck at the below said lines ofmy code indefinitely:
sample = gst_app_sink_pull_sample (GST_APP_SINK(applicationSink));
I have the following questions :
1) Is my Caps for appsink correct ? If not How can I determine the caps for them ?
2) Is there something wrong in my pipeline above ?
How can I fix this issue with Appsink ??
Any kind of help would be useful!
Thanks !!
Just a guess (I had similar problems) the problem having appsink and appsrc in same pipeline may be that when you fill/empty one of them it will block the other(more on that below).
appsink and appsrc would block when they are full/empty - this is normal desired behaviour. There is option drop for appsink or for appsrc there is option block - but using these it may be just workaround and you will get glitches in your stream. Proper solution is to handle the synchronisation between appsrc and appsink in a better way.
You can react on appsrc signals enough-data and need-data - this is our way. Also we fiddled with properties of appsrc: is-live, do-timestamp and buffer size (this may or may not help you):
g_object_set(src->appsrc,
"stream-type", GST_APP_STREAM_TYPE_STREAM,
"format", GST_FORMAT_TIME,
"do-timestamp", TRUE,
"is-live", TRUE,
"block", TRUE,
NULL);
Why do they block each other?
Because (I guess) you process appsink and at the same time appsrc in main application thread. When one of the appsink/appsrc block the thread there is no one that would handle the processing for the other one. So when appsink is blocked because it does not have any data there is noone that can feed appsrc with new data - thus endless deadlock.
We also implemented noblock version of appsink *pull_sample method but it was just a workaround and resulted in more problems than solutions.
If you want to debug what is happening you can add GST_DEBUG entry for appsrc/appsink (I do not remember what they were), you can add callback on mentioned enough-data and need-data signals or you may add queues and enable GST_DEBUG=queue_dataflow:5 to see which queue is filled first etc.. this is always helpful when debugging the "data-deadlock".