GStreamer - How to save matroska file

I changed the pipeline from

                                       /-> queue -> autovidesink
v4l2src -> videoconvert -> queue -> tee
                                       \-> queue -> matroskamux -> queue -> valve -> filesink

to

                                       /-> queue -> autovidesink
v4l2src -> videoconvert -> queue -> tee
                                       \-> queue -> valve -> matroskamux -> queue -> filesink

But the outcome doesn’t change: all problems described here still exist.

All of them? Even the matroska data corruption where it says re-syncing to next cluster?

Ahh not that one, sorry. But all other (freeze when you click “Stop” when the recording is paused and static frames where the recording was paused) are present.

Application freezes when you click stop while paused: my guess is that the valve drops the EOS event, so it never makes it through to the filesink, so you’re stuck waiting in gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_EOS);. To fix this, you could set valve drop=false before sending the EOS event, but then you risk a few rogue frames making it through again. It might be easier to also send an EOS event manually to an element or pad after the valve, e.g. the matroskamux sink pad(s). That way all sinks get an EOS event, and then you should also get an EOS message. You can check the GST_DEBUG log to see what’s happening with the EOS events and if they make it to the sinks or not.

That’s what I did. It works. Now I only have to figure out how to use gst_pad_set_offset(). Can you explain to me what to do to get the correct duration to supply as the second argument?

This is not entirely trivial I’m afraid.

The easiest way might be to have a GTimer which you start whenever you pause the recording and which you pause whenever you unpause the recording. That way the timer will measure the time you spent being paused.

The value you have to pass to gst_pad_set_offset() is in nanoseconds, so you can try passing g_timer_elapsed() * GST_SECOND * -1. For bonus points also handle the microseconds once it works.

You need to find the right pad to set this offset. probably the valve src pad or such. Setting the offset sends SEGMENT events, which should not be dropped by the valve.

This will only work if matroskamux picks up the new segment events properly. I would assume it does but I haven’t checked it.

Thanks again, I’ll try that later because unfortunately I have encountered some more problems.

The actual (complete i.e. with all the capabilities turned on) pipeline doesn’t look like as I have shown until now, nor as I have shown in the example program that I wrote. It actually looks like this:

                                       /-> queue -> autovideosink
v4l2src -> videoconvert -> queue -> tee
                                       \-> queue -> valve -> matroskamux -> queue -> filesink
                 alsasrc -> audioconvert -> queue -> valve -/

So it also records audio. I have modified the example program accordingly, click here.

The pipeline is paused by setting drop property of both valve elements to TRUE (and unpausing to FALSE, of course). When a user clicks “Stop” EOS is sent to the entire pipeline and to the matroskamux element.

This new example program has the following problems (none of these are present if you don’t include audio elements):

  1. If you just start the program and click “Stop” the produced file is corrupted.
  2. If you try to stop the program when the recording is paused the program will freeze, hanging on the line that sends EOS to the entire pipeline.
  3. If you click “Pause” and “Unpause” any number of times, as long as the last one was “Unpause” so the recording is not paused, and then click “Stop”, the produced file will contain errors wherever the program was paused.

In all cases the file is playable, though.

Sorry, I know this is not part of the original question but I didn’t expect this, nothing that I tried managed to fix these problem.

For pausing you probably don’t want a valve but the togglerecord element. That ensures that you don’t accidentally drop keyframes or anything else important and basically behaves like a “pause” button on a recorder. It will also not fall apart if you send EOS to the pipeline in paused state, but correctly finish everything at that point then.

See https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/tree/master/gst-plugin-togglerecord . Also comes with an UI example application with a record button.

I can’t use that plugin because it is not available in the repos. Since my project will be available in the repos this the plugin needs to be too.

Well, the code is available so feel free to reimplement it :slight_smile: I don’t understand your point though: your application has to be packaged, so has every other dependency of it. So why not package the plugin?

I don’t know Rust. I tried to read it but I couldn’t understand it very well. And I don’t even know will this fix my problem.

I would like to package the entire gstreamer-plugins-rs project but I can’t find where you archive versions of the library. For example, every my project has folder “archive” where I save each version of the program as tar.gz archive.
You probably have something similar but I can’t find it anywhere.

@sdroege
I could use specific commit instead of that, but I don’t know which one is good. Is the latest one fine?

Ok I used togglerecord. For now it works very well.

Unfortunately I need two source pads for recording video + audio. One is “Always” pad so that’s not a problem. The other one is “Sometimes” pad so I need to get it some other way.

I connected the entire pipeline except for the “Sometimes” pad and the pad that is going to be linked to it.
So my pipeline looks like this.


“togglerecord” and “vorbisenc” are unlinked before the pipeline is set into GST_STATE_PLAYING because that source pad of togglerecord is a “Sometimes” pad and hence does not exist yet.
Before pipeline is set into playing state this statement is executed.

g_signal_connect(togglerecord, "pad-added", G_CALLBACK(tg_new_pad_cb), gst_element_get_static_pad(vorbisenc, "sink"));

tg_new_pad_cb should be called when new pad is added and link it to the sink pad of vorbisenc. GDB shows that that function is never executed.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.