GStreamer multifilesrc never throws EOS - gstreamer

It appears that the GStreamer 1.0 multifilesrc element will not automatically throw an EOS when it runs out of files. If a stop-index=N is specified then it will EOS after N frames.
gst-launch-1.0 -ev multifilesrc location="tmp/frame%04d.jpg" stop-index=20 ! image/jpeg,framerate=10/1 ! jpegdec ! videoconvert ! videorate ! xvimagesink
Is there a way to have multifilesrc automatically generate EOS when the file list is exhausted or otherwise pack the frames into a stream with an EOS? Otherwise my pipeline just hangs at the end.

Related

How to detect one source of funnel plugin has ended in gstreamer pipeline?

I am using gstreamer to build a pipeline with two source. One is a file source (filesrc), the other is appsrc. When the filesrc got EOS, the pipeline do not quit. appsrc still get need-data signal and will never stop itself. It seems funnel plugin will wait for all sources to end before sending EOS to pipeline. Is there a way to get notified when filesrc got end of file?
gst-launch command looks like this:
gst-launch-1.0 funnel name=f \
appsrc name=appsrc-h264-sei do-timestamp=true block=true is-live=true ! video/x-h264, stream-format=byte-stream, alignment=au ! queue ! f. \
filesrc input.h264 ! queue ! f. \
f. ! queue ! h264parse ! video/x-h264, stream-format=byte-stream, alignment=au ! mp4mux ! filesink location=file.mp4
You can install a GstPadProbe at the the funnel input pad and check for the EOS event on the callback.

What does 'num-buffers' do in gstreamer?

I could only find few pages giving a one-liner explanation of num-buffers. Like this one.
Number of buffers to output before sending EOS (End of Stream). Default = -1 (unlimited)
I have a dummy pipeline using gst-launch-1.0 multifilesrc with default loop=False. The pipeline loops because of num-buffers=-1 as the default.
I don't want it to loop, which happens to be when I set num-buffers=1 or literally any other finite number.
What does it mean to be num-buffers=1 (or any value in that sense)?
Edit: Sample pipelines with a 10-second video
# 1. With loop=false and num-buffers=1
$> GST_DEBUG=3 gst-launch-1.0 multifilesrc location=preview.h264 loop=false num-buffers=1 ! h264parse ! avdec_h264 ! fakesink
...
Got EOS from element "pipeline0".
Execution ended after 0:00:00.425738029
...
# 2. With loop=false and num-buffers=10
$> GST_DEBUG=3 gst-launch-1.0 multifilesrc location=preview.h264 loop=false num-buffers=10 ! h264parse ! avdec_h264 ! fakesink
...
Got EOS from element "pipeline0".
Execution ended after 0:00:04.256451070
...
# 3. With neither loop flag (default=false) nor num-buffers (default=-1, unlimited)
$> GST_DEBUG=3 gst-launch-1.0 multifilesrc location=preview.h264 ! h264parse ! avdec_h264 ! fakesink
...This never ends because num-buffers=-1. Why?...
I didn't get any warnings in any case.
"num-buffers" defines how many frames will be published by a given element like videotestsrc. After sending "num-buffers", EOS event is published.
I find it useful in tests when you can define number of frames and framerate and then set expectations about how many frames shall be received during given time (e.g. using probe).
multifilesrc doesn't seem to support "num-buffers": it will read all files and exits (or start again when loop=True). You should see a warning when setting "num-buffers" on multifilesrc.
multifilesrc inherits from GstBaseSrc element and has num-buffers property. It should be used to replay a sequence of frames as video:
gst-launch-1.0 multifilesrc location="%08d.png" loop=true num-buffers=1000 ! decodebin ! videoconvert ! ximagesink
To replay images named 00000000.png to 99999999.png one after another.
For your purpose, just use filesrc element, not multifilesrc.

record camera stream from gstreamer

I have a gstreamer pipeline which works perfectly and takes a camera stream, encodes it as H.264 video, saves it to a file AND displays it on the screen as follows:
gst-launch-1.0 -v autovideosrc ! tee name = t ! queue ! omxh264enc !
'video/x-h264, stream-format=(string)byte-stream' ! h264parse ! qtmux !
filesink location=test.mp4 t. ! queue ! videoscale ! video/x-raw,
width=480,height=270 ! xvimagesink -e sync=false
Now, I am trying to do something even simple and just record the stream to a file (without displaying on screen) and this does not seem to work! It writes a file but cannot play it. What I have tried so far is:
gst-launch-1.0 -v autovideosrc ! queue ! omxh264enc ! 'video/x-h264,
stream-format=(string)byte-stream' ! h264parse ! qtmux ! filesink
location=test.mp4 sync=false
I can also remove the queue element but with the same result:
gst-launch-1.0 -v autovideosrc ! omxh264enc ! 'video/x-h264,
stream-format=(string)byte-stream' ! h264parse ! qtmux ! filesink
location=test.mp4 sync=false
It does not give any errors but just does not write a valid stream to my filesink, it seems.
How do you stop the stream? Will the camera correctly inject an EOS signal? If not and you just press ctrl-c to stop the operation the .mp4 file will missing important headers which are required for proper playback.
Add -e to your command line. In that case when you press ctrl-c the pipeline will not just stop but is being properly shut down by sending an EOS signal through the pipeline.

How to remove a branch of tee in an active GStreamer pipeline?

everyone
The version of GStreamer I use is 1.x. I've spent a lot of time in searching a way to delete a tee branch.
In an active pipeline, a recording bin is created as below and inserted into this pipeline by branching the tee element.
"queue ! video/x-h264, width=800, height=600, framerate=10/1, stream-format=(string)byte-stream ! h264parse ! mp4mux ! filesink location=/xxxx"
It works perfectly except that I want to dynamically delete the recording bin and get a playable mp4 file. According to some discussion and tutorial, to get a correct mp4 file , we need to handle something about EOS. After trying some methods, I always got broken mp4 files.
Does anyone have sample code written in C to show me ? I'd appreciate your help.
Your best bet for cases like this may be to create two processes. The first process would run the video, and half of the tee it has would deliver h264 data to the second process through whatever means.
Here are two pipelines demonstrating the concept using UDP sockets.
gst-launch-1.0 videotestsrc ! x264enc ! tee name=t ! h264parse ! avdec_h264 ! videoconvert ! ximagesink t. ! queue ! h264parse ! rtph264pay ! udpsink host=localhost port=8888
gst-launch-1.0 udpsrc port=8888 num-buffers=300 ! application/x-rtp,media=video,encoding-name=H264 ! rtph264depay ! h264parse ! mp4mux ! filesink location=/tmp/264.mp4
The trick to getting that clean mp4 is to make sure an EOS event is delivered reliably.
Instead of dynamically adding it you just have it in the pipeline by default, and add a probe callback at the source pad of the queue in the probe callback you have to do the trick either to pass the buffer or not (GST_PAD_PROBE_DROP drops the buffer and GST_PAD_PROBE_OK passes on the buffer to next element) so when you get an event to start/stop recoding you just need to return appropriate values. And filesink you can use multifilesink instead so as to write to different files everytime you start/stop.
Note the queue which drops the buffers needs before the mux element otherwise the file would be corrupt.
Hope that helps!
Finally, I came up with a solution.
Let's say that there is an active pipeline including a recording bin.
"udpsrc port=4444 caps=\"application/x-rtp, media=(string)video,
clock-rate=(int)90000, encoding-name=(string)H264 ! rtph264depay !
tee name=tp tp. ! queue ! video/x-h264, width=800, height=600,
framerate=10/1 ! decodebin ! videoconvert ! video/x-raw, format=RGBA !
autovideosink"
recording bin:
"queue ! video/x-h264, width=800, height=600, framerate=10/1,
stream-format=(string)byte-stream ! h264parse ! mp4mux ! filesink
location=/xxxx"
After a period of time, we want to stop recording and save as a mp4 file, and video media is still streaming.
First, I use a blocking probe to block the src pad of tee. In this blocking probe callback, I use an event probe to catch EOS in the sink pad of filesink and do a busy waiting.
*if EOS is catched in the event probe callback
self->isGotEOS = YES;
*busy waiting in the blocking probe callback
while (self->isGotEOS == NO) {
usleep(100000);
}
Before entering the busy waiting while loop, an EOS event is created and sent to the sink pad of recording bin.
After the busy waiting is done:
usleep(200000);
[self destory_record_elements];
I think usleep(200000) is a trick. Without it, a non-playable mp4 file is usually the result. It would seem that 200ms is long enough handling the EOS.
I had similar problem previously, my pipeline
videotestsrc do-timestamp="TRUE" ! videoflip method=0 ! tee name=t
t. ! queue ! videoconvert ! glupload ! glshader ! autovideosink async="FALSE"
t. ! queue ! identity drop-probability=1 ! videoconvert name=conv2 ! openh264enc ! h264parse ! avimux ! multifilesink async="FALSE" post-messages=true next-file=4
Then I just change drop-probability property on identity element
drop-probability = 1 + gst_pad_send_event(conv2_sinkpad, gst_event_new_eos()); - stop recording
drop-probability = 0 - resume recording

play encoded stream in gstreamer

I used the following GStreamer pipeline to store my encoded stream in a binary file:
gst-launch v4l2src ! videorate ! video/x-raw-yuv, framerate=\(fraction\)10/1 \
! videoscale ! video/x-raw-yuv, format=\(fourcc\)I420, width=640, height=480\
! ffmpegcolorspace ! x264enc ! fdsink > vid.bin
Now i want to play previously recorded files in GStreamer using the following pipeline:
cat vid.bin | gst-launch fdsrc ! ffdec_h264 ! autovideosink
But then it gives the following error:
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
ERROR: from element /GstPipeline:pipeline0/ffdec_h264:ffdec_h2640: Internal GStreamer error: negotiation problem. Please file a bug at http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer.
Additional debug info:
gstffmpegdec.c(2804): gst_ffmpegdec_chain (): /GstPipeline:pipeline0/ffdec_h264:ffdec_h2640:
ffdec_h264: input format was not set before data start
ERROR: pipeline doesn't want to preroll.
Setting pipeline to NULL ...
Freeing pipeline ...
I know that the best way to capture video is using Muxers but is there any way to play my previous files?
Thanks
Not sure your pipeline is right.
If you want to write to a file why not simply use filesink and filesrc.
fdsink > vid.bin will not work fine because if you see the prints by gstreamer gst-launch will also go into the file. [Just open vid.bin in an text editor and you will see what I mean].
Also for x264 stream to be stored without a muxer you need to use byte-stream=1 in your x264enc to store it in annexb format so that it is decodable.
To play back raw x264 stream you need to have a color space convertor before the video sink
gst-launch filesrc location=inputfile ! legacyh264parse ! ffdec_h264 ! queue ! ffmpegcolorspace ! autovideosink
plays just fine here at my end
Or, to playback a raw h264 file with gstreamer 1.0:
gst-launch-1.0 filesrc location=/tmp/video.h264 ! h264parse ! avdec_h264 ! autovideosink