Discussion:
How to stop and restart writing to a filesink (while the pipeline is alive).
Alexander Botero
2012-09-10 17:48:05 UTC
Permalink
Hello,
I have a small audio recorder that uses Gstreamer.
I would like the recorder to pause when the signal-level drops under a
certain value, and re-start when the level rises again.

I cannot simply set the pipeline or filesink to GST_STATE_PAUSED or NULL
because my code needs to check the level-value all the time (so it can
determine when to stop or re-start writing to a sink file).
The pipeline must run all the time so the "message::element" message is
generated and level_message_cb(...) is called continually.

How can I stop (and re-start) writing to a filesink, while the pipeline is
ticking and alive?
I understand this can be difficult because container formats (like ogg)
need to write bytes to previous blocks.

Here is my test-code, a small gtk-program:
http://www.futuredesktop.org/tmp/test1.c

I have tried to stop/start the filesink with various methods.
Please see set_filesink1(...) and set_filesink2(...).

For example, I tried to set the filesink to READY-state, then setting its
location to NULL, and later back to "test1.ogg" But this is not allowed.

Compile:
gcc -Wall test1.c -o test1 $(pkg-config --cflags --libs gtk+-3.0
gthread-2.0 gstreamer-0.10)

Run:
./test1

The recorder is open source.

Kindly
Alexander
Paddy
2012-09-10 18:10:43 UTC
Permalink
Try an output-selector to select between your filesink (for good signal
level) or a fakesink (for bad signal level). This way your pipeline will
still flow data.

See my reply in
http://gstreamer-devel.966125.n4.nabble.com/Dropping-audio-untill-video-key-frame-td4656229.html
& you'll know what I'm getting at.



--
View this message in context: http://gstreamer-devel.966125.n4.nabble.com/How-to-stop-and-restart-writing-to-a-filesink-while-the-pipeline-is-alive-tp4656242p4656243.html
Sent from the GStreamer-devel mailing list archive at Nabble.com.
Tim-Philipp Müller
2012-09-10 19:02:30 UTC
Permalink
On Mon, 2012-09-10 at 19:48 +0200, Alexander Botero wrote:

Hi,
Post by Alexander Botero
I have a small audio recorder that uses Gstreamer.
I would like the recorder to pause when the signal-level drops under a
certain value, and re-start when the level rises again.
Do you want the resulting audio to be in one single file (without the
"silent" bits), or do you want to start a new file for each piece with a
"signal".

There's also the "cutter" element btw (so you don't have to actively
monitor the level value).

Cheers
-Tim
Alexander Botero
2012-09-13 16:17:08 UTC
Permalink
Many thanks for your replies.

The output-selector element:
Ref:
http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-output-selector.html
Yes, this look very promising.
I made a small test and it does switch between the filesinks (or between a
filesink and fakesink), but the the resulting file is really big.

Here is my (gtk3 based) test code:
http://www.futuredesktop.org/tmp/test3.c

Compile:
gcc -Wall test3.c -o test3 $(pkg-config --cflags --libs gtk+-3.0 gdk-2.0
gthread-2.0 gstreamer-0.10)

And run:
./test3

The button_1_click() creates the pipeline. In the code, choose
either pipeline_create1() or pipeline_create2() function.
Button_2_click() and button_3_click() functions set the "active-pad"
(active file) on the output-selector.

The resulting file is about 23GB for a few seconds of recording. The file
is not playable.
$ ls -l *.wav
-rw-rw-r-- 1 moma moma 23025309546 Sep 13 17:53 test1.wav

The filesize is correct in the beginning. It gets totally wrong when I
switch between the pads.
My understanding of the pads and sinks is not very good.

What can I do to keep the filesize correct?
----------------------------------------------------------------

The GstCutter element:
I just began to test the "cutter" element. I will comment it later on.
----------------------------------------------------------------
Post by Tim-Philipp Müller
Do you want the resulting audio to be in one single file (without
the "silent" bits), or do you want to start a new file for each piece with
a"signal".

The recording should output a single file. It should filter out the
"silent" parts.

This is the audio-recorder i want to improve.
http://bildr.no/view/805395
It's on the launchpad.net. "audio-recorder".

Kindly
Alexander
Post by Tim-Philipp Müller
Hi,
Post by Alexander Botero
I have a small audio recorder that uses Gstreamer.
I would like the recorder to pause when the signal-level drops under a
certain value, and re-start when the level rises again.
Do you want the resulting audio to be in one single file (without the
"silent" bits), or do you want to start a new file for each piece with a
"signal".
There's also the "cutter" element btw (so you don't have to actively
monitor the level value).
Cheers
-Tim
_______________________________________________
gstreamer-devel mailing list
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Paddy
2012-09-14 08:44:42 UTC
Permalink
Are you switching between the two wav files, or one wav file & the fakesink,
when you see the big file issue??

I don't see anything obviously wrong from a quick glance at your code. You
may want to try adding something like "audio/x-raw-int, rate= ..." after the
audioconvert element. What does the debug reveal when you switch outputs ??

A
http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-valve.html
valve element might suit you better than an output selector.




--
View this message in context: http://gstreamer-devel.966125.n4.nabble.com/How-to-stop-and-restart-writing-to-a-filesink-while-the-pipeline-is-alive-tp4656242p4656304.html
Sent from the GStreamer-devel mailing list archive at Nabble.com.
Alexander Botero
2012-09-17 09:18:19 UTC
Permalink
Paddy: The file is corrupt is both (in all) cases. The file pointer jumps
randomly.

Ok, I moved on and started to play with the GstCutter and GstVader
elements. I found GstVader on the net.

The GstCutter element:
I tested the cutter-filter but I had problems settings the treshold (volume
treshold) for the silent parts. So I gave it up.

The GstVader element:
GstVader is an improved version of the GstCutter element. It is a VAD
(Voice Activity Detection) filter.
It does a very good job by filtering out the silent parts.
Please read below how to get the Vader element (1). It's a product of
Carnegie Mellon University, USA.

Here I tested the Vader element with AAC, OGG, SPX, FLAC, WAV and MP3
encoders.
I took the the encoder-fragments from the GNOME's configuration registry.
Start gconf-editor and browse to: system -> gstreamer -> 0.10 -> audio ->
profiles.

Webcam (and its microphone) made it easy to test the volume-level and
treshold values, so I set the device="xxxx" in the pipelines (2).

Testing AAC (cd quality, file extension: m4a):
$ gst-launch-0.10 -e
--gst-plugin-path=$HOME/TT2/gst-template/gst-plugin/src/.libs pulsesrc
device="alsa_input.usb-Creative_Technology_Ltd._VF0610_Live__Cam_Socialize_HD_091214_b_00556-02-HD.analog-mono"
! vader threshold=0.3 auto-threshold=true ! queue ! audioconvert !
audioresample ! audio/x-raw-int,rate=44100,channels=2 ! faac profile=2 !
ffmux_mp4 ! filesink location=test1.xxx

Testing OGG audio (cd quality, lossy. file extension: ogg)
$ gst-launch-0.10 -e
--gst-plugin-path=$HOME/TT2/gst-template/gst-plugin/src/.libs pulsesrc
device="alsa_input.usb-Creative_Technology_Ltd._VF0610_Live__Cam_Socialize_HD_091214_b_00556-02-HD.analog-mono"
! vader threshold=0.3 auto-threshold=true ! queue ! audioconvert !
audioresample ! audio/x-raw-float,rate=44100,channels=2 ! vorbisenc
name=enc quality=0.5 ! oggmux ! filesink location=test1.xxx

Testing SPX (voice, lossy. file extension: spx)
gst-launch-0.10 -e
--gst-plugin-path=$HOME/TT2/gst-template/gst-plugin/src/.libs pulsesrc
device="alsa_input.usb-Creative_Technology_Ltd._VF0610_Live__Cam_Socialize_HD_091214_b_00556-02-HD.analog-mono"
! vader threshold=0.3 auto-threshold=true ! queue ! audioconvert !
audioresample ! audio/x-raw-int,rate=32000,channels=1 ! speexenc name=enc !
oggmux ! filesink location=test1.xxx

Results for AAC, OGG audio and SPX:
GstVader filters out the silent parts and the filesize is correct, BUT
playback replays the silent parts again (because of its internal clock?).
Playback (in Totem) shows approximately the same media length (in seconds)
as the recording pipeline.
So in reality, these pipelines cut nothing.
------------------------------------------

Testing FLAC (cd quality,lossless. file extension: flac)
$ gst-launch-0.10 -e
--gst-plugin-path=$HOME/TT2/gst-template/gst-plugin/src/.libs pulsesrc
device="alsa_input.usb-Creative_Technology_Ltd._VF0610_Live__Cam_Socialize_HD_091214_b_00556-02-HD.analog-mono"
! vader threshold=0.3 auto-threshold=true ! queue ! audioconvert !
audioresample ! audio/x-raw-int,rate=44100,channels=2 ! flacenc name=enc !
filesink location=test1.xxx

Testing WAV (voice, lossless. file extension: wav)
$ gst-launch-0.10 -e
--gst-plugin-path=$HOME/TT2/gst-template/gst-plugin/src/.libs pulsesrc
device="alsa_input.usb-Creative_Technology_Ltd._VF0610_Live__Cam_Socialize_HD_091214_b_00556-02-HD.analog-mono"
! vader threshold=0.3 auto-threshold=true ! queue ! audioconvert !
audioresample ! audio/x-raw-int,rate=22050,channels=1 ! wavenc name=enc !
filesink location=test1.xxx

Testing MP3 (cd quality. file extension: mp3)
$ gst-launch-0.10 -e
--gst-plugin-path=$HOME/TT2/gst-template/gst-plugin/src/.libs pulsesrc
device="alsa_input.usb-Creative_Technology_Ltd._VF0610_Live__Cam_Socialize_HD_091214_b_00556-02-HD.analog-mono"
! vader threshold=0.3 auto-threshold=true ! queue ! audioconvert !
audioresample ! audio/x-raw-int,rate=44100,channels=2 ! lamemp3enc name=enc
target=0 quality=6 ! xingmux ! id3v2mux ! filesink location=test1.xxx

Result for FLAC, WAV and MP3:
The result is very good.
The GstVader filters out the silent parts and the filesize is correct.
Playback is also without the silent bits. O resultado muito bom!

For MP3, I noticed that the time-slider in Totem is a bit staccato at first
playback. It's smooth at repeated playback.
------------------------------------------

Question:
The AAC, OGG audio and SPX failed to produce a correct result. The files
(somehow) keep the silent parts even the file has been cut correctly.
I have tried to manipulate the filesink's internal clock without success.
Do you have any thoughts about this?
------------------------------------------

I will test GstTee and GstValve later on. Ok?
------------------------------------------

1) Getting the GstVader element:
I copied it from the pocketsphinx-snapshot package.
See http://cmusphinx.sourceforge.net/wiki/download/
Copyright (c) 1999-2010 Carnegie Mellon University.

First, I created a basic GstPlugin from a template.
Ref:
http://gstreamer.freedesktop.org/data/doc/gstreamer/head/pwg/html/chapter-building-boiler.html#section-boiler-source
Then I copied pocketsphinx/src/gstvader.[ch] to the sample, and changed the
files.

Eg. I had to add plugin_init(GstPlugin * plugin) function and
GST_PLUGIN_DEFINE(...) macro to the gstvader.c.
I added also -lgstaudio-0.10 to the Makefile.am.
libgstvader_la_LIBADD = $(GST_LIBS) -lgstaudio-0.10

The modified source code is here:
http://www.futuredesktop.org/tmp/gst-plugin.tar.gz
Please respect the copyright notice (of Carnegie Mellon University) in the
files.

Compilation/linking put a dynamic library into gst-plugin/src/.libs/ folder.

Checking the library:
$ gst-inspect-0.10
$HOME/test/gst-template/gst-plugin/src/.libs/libgstvader.so

Plugin Details:
Name: vader
Description: Vader plugin
Filename: /home/alex/test/gst-template/gst-plugin/src/.libs/libgstvader.so
Version: 0.10.0
License: LGPL
Source module: vader-plugin-package
Binary package: GStreamer
---------------

2) Listing audio devices
pactl list | grep -A2 'Source #' | grep 'Name: ' | cut -d" " -f2

-- end ---
Post by Paddy
Are you switching between the two wav files, or one wav file & the fakesink,
when you see the big file issue??
I don't see anything obviously wrong from a quick glance at your code. You
may want to try adding something like "audio/x-raw-int, rate= ..." after the
audioconvert element. What does the debug reveal when you switch outputs ??
Stefan Sauer
2012-09-16 19:11:59 UTC
Permalink
Post by Alexander Botero
Hello,
I have a small audio recorder that uses Gstreamer.
I would like the recorder to pause when the signal-level drops under a
certain value, and re-start when the level rises again.
I cannot simply set the pipeline or filesink to GST_STATE_PAUSED or
NULL because my code needs to check the level-value all the time (so
it can determine when to stop or re-start writing to a sink file).
The pipeline must run all the time so the "message::element" message
is generated and level_message_cb(...) is called continually.
How can I stop (and re-start) writing to a filesink, while the
pipeline is ticking and alive?
I understand this can be difficult because container formats (like
ogg) need to write bytes to previous blocks.
You could do something like this:
autoaudiosrc ! level ! tee name=t ! queue ! autoaudiosink t. ! queue !
valve ! encodebin ! filesink

when the level drops below a threshold, you close the valve and remember
the position. When the level gets above the threshold again, you open he
valve (and eventually push a newsegment event).

Stefan
Post by Alexander Botero
http://www.futuredesktop.org/tmp/test1.c
I have tried to stop/start the filesink with various methods.
Please see set_filesink1(...) and set_filesink2(...).
For example, I tried to set the filesink to READY-state, then setting
its location to NULL, and later back to "test1.ogg" But this is not
allowed.
gcc -Wall test1.c -o test1 $(pkg-config --cflags --libs gtk+-3.0
gthread-2.0 gstreamer-0.10)
./test1
The recorder is open source.
Kindly
Alexander
_______________________________________________
gstreamer-devel mailing list
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Streit Eric
2012-09-17 06:55:12 UTC
Permalink
Hi,

I had the same problem when I wrote my "recorder" 5 years ago and I
managed to have something working: the program was designed to record a
list of words/phrases and save them in a separate file (with encoding:
flac).

It was working, but not perfect: you can find a archive on
http://www.yojik.eu/ (YazikRecorder).

I'm writing a new version of it , essentially a new recording pipeline
with the help of :
http://cgit.freedesktop.org/gstreamer/gstreamer/tree/docs/design/part-dynamic.txt
(which is not complete now on this website, but I have a copy of it).


It's written in python. (take a look at pipeline1 and pipeline2)

I don't understand why does'nt exit an element which take care of the
switching as the peipeline is running: it's a very common task
(switching effects, filesink ...)

Maybe a new element is allready there, and in this case, I would be
happy to know about it (with examples).

Hope this help,

Eric

ps: if you want, I can upload a copy of the text which disappeared on my
server.
Post by Stefan Sauer
Post by Alexander Botero
Hello,
I have a small audio recorder that uses Gstreamer.
I would like the recorder to pause when the signal-level drops under a
certain value, and re-start when the level rises again.
I cannot simply set the pipeline or filesink to GST_STATE_PAUSED or
NULL because my code needs to check the level-value all the time (so
it can determine when to stop or re-start writing to a sink file).
The pipeline must run all the time so the "message::element" message
is generated and level_message_cb(...) is called continually.
How can I stop (and re-start) writing to a filesink, while the
pipeline is ticking and alive?
I understand this can be difficult because container formats (like
ogg) need to write bytes to previous blocks.
autoaudiosrc ! level ! tee name=t ! queue ! autoaudiosink t. ! queue !
valve ! encodebin ! filesink
when the level drops below a threshold, you close the valve and remember
the position. When the level gets above the threshold again, you open he
valve (and eventually push a newsegment event).
Stefan
Post by Alexander Botero
http://www.futuredesktop.org/tmp/test1.c
I have tried to stop/start the filesink with various methods.
Please see set_filesink1(...) and set_filesink2(...).
For example, I tried to set the filesink to READY-state, then setting
its location to NULL, and later back to "test1.ogg" But this is not
allowed.
gcc -Wall test1.c -o test1 $(pkg-config --cflags --libs gtk+-3.0
gthread-2.0 gstreamer-0.10)
./test1
The recorder is open source.
Kindly
Alexander
_______________________________________________
gstreamer-devel mailing list
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
_______________________________________________
gstreamer-devel mailing list
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Alexander Botero
2012-09-18 13:55:26 UTC
Permalink
Hello,
Yes, your idea is pretty good. And it works very well with FLAC, WAV and
MP3 encoders.
The recorded files have correct length and the "silent" parts have gone
when replayed.

But AAC, OGG audio and SPX encoders (file formats) add the missing "silent"
bits when replayed, even the file has been cut correctly. I usually replay
my tests in Totem or RhythmBox.

This is exactly the same result I got with the VADer filter. (ref. my
previous posting).

The pipeline has this format:
pulsesrc device="xxx" ! level ! tee name=t ! queue ! fakesink t. ! queue !
valve ! encodebin ! filesink

Example1:
WAV encoder. This produces correct result.
gchar *pipeline_cmd = g_strdup("pulsesrc name=source"
" ! level name=level"
" ! tee name=t"
" ! queue"
" ! fakesink t."
" ! queue"
" ! valve name=valve"
" ! audioconvert"
" ! wavenc"
" ! filesink name=filesink");


Example2:
OGG audio. Filesize is correct, but this adds the silent bits when
replayed.
gchar *pipeline_cmd = g_strdup("pulsesrc name=source"
" ! level name=level"
" ! tee name=t"
" ! queue"
" ! fakesink t."
" ! queue"
" ! valve name=valve"
" ! audioconvert"
" ! vorbisenc"
" ! oggmux"
" ! filesink name=filesink");

In the code I set:
g_object_set(G_OBJECT(valve), "drop", TRUE / FALSE , NULL);

*Conclusion:*
We have to understand that the pipeline and its elements have an internal
clock.
In some audio formats (like: OGG, AAC, and SPX) this clock overrides the
missing frames, thus adding silent bits to the media when replayed.

There are some functions that might adjust the clock.

gst_element_get_base_time(...) and gst_element_set_base_time(...)
gst_element_get_start_time(...) and gst_element_set_start_time(...)

Or:
GstEvent *segment = gst_event_new_new_segment(FALSE, 1.0, GST_FORMAT_TIME,
g_start_time, g_end_time, g_start_time);
ret = gst_pad_send_event(sinkpad , segment);

But I do not know these methods well.

Anyway, it's been an interesting ride so far, and new comments are still
welcomed.
--------------------------

Tested formats from gconf-editor, system -> gstreamer -> 0.10 -> audio ->
profiles:
AAC: audio/x-raw-int,rate=44100,channels=2 ! faac profile=2 ! ffmux_mp4
FLAC: audio/x-raw-int,rate=44100,channels=2 ! flacenc name=enc
OGG: audio/x-raw-float,rate=44100,channels=2 ! vorbisenc name=enc
quality=0.5 ! oggmux
MP3: audio/x-raw-int,rate=44100,channels=2 ! lamemp3enc name=enc target=0
quality=6 ! xingmux ! id3v2mux
WAV: audio/x-raw-int,rate=22050,channels=1 ! wavenc name=enc
SPX: audio/x-raw-int,rate=32000,channels=1 ! speexenc name=enc ! oggmux

Greetings
Alexander
Post by Stefan Sauer
autoaudiosrc ! level ! tee name=t ! queue ! autoaudiosink t. ! queue !
valve ! encodebin ! filesink
when the level drops below a threshold, you close the valve and remember
the position. When the level gets above the threshold again, you open he
valve (and eventually push a newsegment event).
Stefan
Alexander Botero
2012-09-19 17:03:00 UTC
Permalink
Stefan, I took your "encodebin" very literally and made some tests with it.

I learned that it's possible to create a media (encoding) profile during
runtime.
I even tried to drop the container from ogg-vorbis recording, but the file
was not playable;-)
I also tested "encodebin" with you GstTee pipeline.

I haven't managed to adjust the internal clock of AAC, OGG Vorbis and SPX
formats.
They still "remember" the slient parts. But these tests have been very
interesting to do.

Current solution / eu resolvi por esta solução:
I have decided to use the VADer element i our (GPL'ed) audio-recorder
because it has a very good algorithm for audio detection and noise
filtering.
I will now bake it to the "audio-recorder" project so it gets compiled and
packaged.

The "silent" detection in the recorder will become much simpler. The
actual, old version creates two (2) long pipelines; one for the "silent"
detection and second (similar) pipeline for recording. This is awful waste
of resources.

But of course, the new recorder must live with the above problem with AAC,
OGG and SPX formats. That's life!
------------

static GstElement *create_pipeline() {
GstElement *pipeline = gst_pipeline_new("a simple recorder");

GstElement *src = gst_element_factory_make("pulsesrc", "source");
g_object_set(G_OBJECT(src), "device", "alsa_input.usb-Creative_....",
NULL);

GstElement *filesink = gst_element_factory_make("filesink", "filesink");
g_object_set(G_OBJECT(filesink), "location", "test.xxx", NULL);

GstElement *queue = gst_element_factory_make("queue", NULL);
GstElement *ebin = gst_element_factory_make("encodebin", NULL);

GstEncodingProfile *prof = create_ogg_vorbis_profile(1, NULL);
g_object_set (ebin, "profile", prof, NULL);
gst_encoding_profile_unref (prof);

gst_bin_add_many(GST_BIN(pipeline), src, queue, ebin, filesink, NULL);

if (!gst_element_link_many(src, queue, ebin, filesink, NULL)) {
g_printerr("Cannot link many.\n");
}

GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
gst_bus_add_signal_watch(bus);
g_signal_connect(bus, "message::element", G_CALLBACK(level_message_cb),
NULL);
gst_object_unref(bus);
}

static GstEncodingProfile *create_ogg_vorbis_profile (guint presence, gchar
* preset) {
// I copied this from gstreamer's test-module. It seems to be very easy
to create new profiles.
GstEncodingContainerProfile *cprof;
GstCaps *ogg, *vorbis;

ogg = gst_caps_new_simple ("application/ogg", NULL);
cprof = gst_encoding_container_profile_new ((gchar *) "oggprofile",
NULL, ogg, NULL);
gst_caps_unref (ogg);

vorbis = gst_caps_new_simple ("audio/x-vorbis", NULL);
gst_encoding_container_profile_add_profile (cprof, (GstEncodingProfile
*) gst_encoding_audio_profile_new (vorbis, preset, NULL, presence));
gst_caps_unref (vorbis);

// vorbisenc:
// audio/x-raw-float, rate=(int)[ 1, 200000 ], channels=(int)[ 1, 255
], endianness=(int)1234, width=(int)32
//
// caps = gst_caps_new_simple("audio/x-raw-float",
// "rate",G_TYPE_INT, 8000,
// "channels" ,G_TYPE_INT, (gint)1,
// "endianness",G_TYPE_INT,(gint)1234,
// "width" ,G_TYPE_INT, (gint)8, NULL);

return (GstEncodingProfile *)cprof;
}

Kindly
Osmo Antero
Post by Stefan Sauer
autoaudiosrc ! level ! tee name=t ! queue ! autoaudiosink t. ! queue !
valve ! encodebin ! filesink
when the level drops below a threshold, you close the valve and remember
the position. When the level gets above the threshold again, you open he
valve (and eventually push a newsegment event).
Stefan
Stefan Sauer
2012-09-19 18:29:35 UTC
Permalink
Post by Alexander Botero
Stefan, I took your "encodebin" very literally and made some tests with it.
I learned that it's possible to create a media (encoding) profile
during runtime.
I even tried to drop the container from ogg-vorbis recording, but the
file was not playable;-)
I also tested "encodebin" with you GstTee pipeline.
I haven't managed to adjust the internal clock of AAC, OGG Vorbis and
SPX formats.
They still "remember" the slient parts. But these tests have been very
interesting to do.
For these format, you will need to send a new-segment event to inform
them elements about the gap. You should find an example inside
camerabin2 in gst-plugins-bad.

Stefan
Post by Alexander Botero
I have decided to use the VADer element i our (GPL'ed) audio-recorder
because it has a very good algorithm for audio detection and noise
filtering.
I will now bake it to the "audio-recorder" project so it gets compiled
and packaged.
The "silent" detection in the recorder will become much simpler. The
actual, old version creates two (2) long pipelines; one for the
"silent" detection and second (similar) pipeline for recording. This
is awful waste of resources.
But of course, the new recorder must live with the above problem with
AAC, OGG and SPX formats. That's life!
------------
static GstElement *create_pipeline() {
GstElement *pipeline = gst_pipeline_new("a simple recorder");
GstElement *src = gst_element_factory_make("pulsesrc", "source");
g_object_set(G_OBJECT(src), "device",
"alsa_input.usb-Creative_....", NULL);
GstElement *filesink = gst_element_factory_make("filesink", "filesink");
g_object_set(G_OBJECT(filesink), "location", "test.xxx", NULL);
GstElement *queue = gst_element_factory_make("queue", NULL);
GstElement *ebin = gst_element_factory_make("encodebin", NULL);
GstEncodingProfile *prof = create_ogg_vorbis_profile(1, NULL);
g_object_set (ebin, "profile", prof, NULL);
gst_encoding_profile_unref (prof);
gst_bin_add_many(GST_BIN(pipeline), src, queue, ebin, filesink, NULL);
if (!gst_element_link_many(src, queue, ebin, filesink, NULL)) {
g_printerr("Cannot link many.\n");
}
GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
gst_bus_add_signal_watch(bus);
g_signal_connect(bus, "message::element",
G_CALLBACK(level_message_cb), NULL);
gst_object_unref(bus);
}
static GstEncodingProfile *create_ogg_vorbis_profile (guint presence,
gchar * preset) {
// I copied this from gstreamer's test-module. It seems to be very
easy to create new profiles.
GstEncodingContainerProfile *cprof;
GstCaps *ogg, *vorbis;
ogg = gst_caps_new_simple ("application/ogg", NULL);
cprof = gst_encoding_container_profile_new ((gchar *)
"oggprofile", NULL, ogg, NULL);
gst_caps_unref (ogg);
vorbis = gst_caps_new_simple ("audio/x-vorbis", NULL);
gst_encoding_container_profile_add_profile (cprof,
(GstEncodingProfile *) gst_encoding_audio_profile_new (vorbis, preset,
NULL, presence));
gst_caps_unref (vorbis);
// audio/x-raw-float, rate=(int)[ 1, 200000 ], channels=(int)[ 1,
255 ], endianness=(int)1234, width=(int)32
//
// caps = gst_caps_new_simple("audio/x-raw-float",
// "rate",G_TYPE_INT, 8000,
// "channels" ,G_TYPE_INT, (gint)1,
// "endianness",G_TYPE_INT,(gint)1234,
// "width" ,G_TYPE_INT, (gint)8, NULL);
return (GstEncodingProfile *)cprof;
}
Kindly
Osmo Antero
autoaudiosrc ! level ! tee name=t ! queue ! autoaudiosink t. !
queue ! valve ! encodebin ! filesink
when the level drops below a threshold, you close the valve and
remember the position. When the level gets above the threshold
again, you open he valve (and eventually push a newsegment event).
Stefan
_______________________________________________
gstreamer-devel mailing list
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Angel Martin
2013-06-04 15:17:42 UTC
Permalink
Dear all,

I did not achieve to create full legible muxed files for Gstreamer 0.10 on
top of multifilesink or output-selector.

After analysing lots of alternatives my solution takes as code base the
example depicted in:
http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/section-dynamic-pipelines.html

The probes function API has been changed a bit but the solution below works
to create every N seconds different MP4 files:

static GstElement *pipeline = NULL;

// Pipeline -> src -> dynamic pipeline
// Pipeline -> capsfilter(f264file) -> mp4mux(mux0)
-> filesink(fsink0)
// Pipeline -> elem_before||blockpad| ->
|elem_cur_sinkpad||elem_cur||elem_cur_srcpad -> |elem_cur_sinkpad||elem_cur
static gulong probe_id; // probe ID
static GstElement *elem_before; // SRC of dynamic pipeline
static GstElement *elem_after; // SINK of dynamic pipeline
static GstElement *elem_cur; // Main element of dynamic pipeline
static GstPad *blockpad; // SRC pad to be blocked
static GstPad *elem_cur_srcpad; // SRC pad where check EOS
static GstPad *elem_cur_sinkpad; // SINK of dynamic pipeline
static GstPad *elem_after_sinkpad; // SINK of SINK element

// Last Buffer Timestamp
static GstClockTime last_ts = 0;

typedef enum {
NO_NEW_FILE, // Keep current file destination
NEW_FILE, // Switch file destination
} NewFileStatus;
static NewFileStatus newfile = NO_NEW_FILE; // Switch File Flag

static int counter = 1; // Index filename

// EOS listener to switch to other file destination
static gboolean
event_probe_cb (GstPad * pad, GstEvent * event, gpointer user_data)
{
g_print ("INSIDE event_probe_cb:%d type:%s\n",probe_id,
GST_EVENT_TYPE (event)==GST_EVENT_EOS?"EOS":GST_EVENT_TYPE
(event)==GST_EVENT_NEWSEGMENT?"NEWSEGMENT":"OTHER");

if (GST_EVENT_TYPE (event) != GST_EVENT_EOS)
{
// Push the event in the pipe flow (false DROP)
return TRUE;
}
// remove the probe first
gst_pad_remove_event_probe (pad, probe_id);

gst_object_unref (elem_cur_srcpad);
gst_object_unref (elem_after_sinkpad);
gst_element_release_request_pad(elem_cur, elem_cur_sinkpad);

gst_element_set_state (elem_cur, GST_STATE_NULL);
gst_element_set_state (elem_after, GST_STATE_NULL);

// remove unlinks automatically
GST_DEBUG_OBJECT (pipeline, "removing %" GST_PTR_FORMAT, elem_cur);
gst_bin_remove (GST_BIN (pipeline), elem_cur);
GST_DEBUG_OBJECT (pipeline, "removing %" GST_PTR_FORMAT, elem_after);
gst_bin_remove (GST_BIN (pipeline), elem_after);

GstElement * mux0 = gst_element_factory_make("mp4mux", "mux0");
GstElement * fsink0 = gst_element_factory_make("filesink", "fsink0");
elem_cur = mux0;
elem_after = fsink0;

if(!mux0 || !fsink0)
{
printf("mising elements\n");
}

GST_DEBUG_OBJECT (pipeline, "adding %" GST_PTR_FORMAT, elem_cur);
gst_bin_add (GST_BIN (pipeline), elem_cur);
GST_DEBUG_OBJECT (pipeline, "adding %" GST_PTR_FORMAT, elem_after);
gst_bin_add (GST_BIN (pipeline), elem_after);

char buffer[128];
sprintf(buffer, "test_%d.mp4", counter++);
g_print ("File Switching %s\n", buffer);
g_object_set(G_OBJECT(elem_after), "location", buffer, NULL);

GST_DEBUG_OBJECT (pipeline, "linking..");
elem_cur_srcpad = gst_element_get_static_pad (elem_cur, "src");
elem_cur_sinkpad = gst_element_get_request_pad (elem_cur, "video_%d");
elem_after_sinkpad = gst_element_get_static_pad (elem_after, "sink");

if(gst_pad_link(blockpad, elem_cur_sinkpad) != GST_PAD_LINK_OK)
{
printf("linking output 0 failed\n");
return -1;
}
if(gst_pad_link(elem_cur_srcpad, elem_after_sinkpad) != GST_PAD_LINK_OK)
{
printf("linking output 1 failed\n");
return -1;
}

g_print ("Moving to PLAYING\n");
gst_element_set_state (elem_cur, GST_STATE_PLAYING);
gst_element_set_state (elem_after, GST_STATE_PLAYING);

GST_DEBUG_OBJECT (pipeline, "done");

newfile = NO_NEW_FILE;
// Push the event in the pipe flow (false DROP)
return TRUE;
}

// Check if Buffer contains a KEY FRAME
static gboolean
is_sync_frame (GstBuffer * buffer)
{
if (GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT))
{
return FALSE;
}
else if (!GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_IN_CAPS))
{
return TRUE;
}
}

// Block source and launch EOS to MUXER to achieve a full muxed file
static gboolean
pad_probe_cb (GstPad * pad, GstBuffer * buffer, gpointer user_data)
{
g_print ("\n\tINSIDE pad_probe_cb:%d %s %s\n",probe_id,
(newfile?"newfile":"thesame"),
(is_sync_frame (buffer)?"KEYframe":"frame"));
GST_DEBUG_OBJECT (pad, "pad is blocked now");

last_ts = GST_BUFFER_TIMESTAMP(buffer);
if(!GST_CLOCK_TIME_IS_VALID(last_ts))
last_ts=0;

if((newfile==NO_NEW_FILE) || !is_sync_frame (buffer))
return TRUE;

/* remove the probe first */
gst_pad_remove_buffer_probe (pad, probe_id);

/* install new probe for EOS */
probe_id = gst_pad_add_event_probe (elem_after_sinkpad,
G_CALLBACK(event_probe_cb), user_data);

/* push EOS into the element, the probe will be fired when the
* EOS leaves the effect and it has thus drained all of its data */
gst_pad_send_event (elem_cur_sinkpad, gst_event_new_eos ());

// Wait til the EOS have been processed the Buffer with the Key frame
will be the FIRST
while(newfile != NO_NEW_FILE)
Sleep(1);

// Push the buffer in the pipe flow (false DROP)
return TRUE;
}

// this timeout is periodically run as part of the mainloop
static gboolean timeout (gpointer user_data)
{
g_print ("TIMEOUT\n");
if(!playing)
return false;
newfile = NEW_FILE;
/* install new probe for Keyframe and New File */
probe_id = gst_pad_add_buffer_probe (blockpad, G_CALLBACK(pad_probe_cb),
pipeline);
return true;
}

Best,

Angel
Post by Alexander Botero
Stefan, I took your "encodebin" very literally and made some tests with it.
I learned that it's possible to create a media (encoding) profile during
runtime.
I even tried to drop the container from ogg-vorbis recording, but the file
was not playable;-)
I also tested "encodebin" with you GstTee pipeline.
I haven't managed to adjust the internal clock of AAC, OGG Vorbis and
SPX formats.
They still "remember" the slient parts. But these tests have been very
interesting to do.
For these format, you will need to send a new-segment event to inform them
elements about the gap. You should find an example inside camerabin2 in
gst-plugins-bad.
Stefan
I have decided to use the VADer element i our (GPL'ed) audio-recorder
because it has a very good algorithm for audio detection and noise
filtering.
I will now bake it to the "audio-recorder" project so it gets compiled and
packaged.
The "silent" detection in the recorder will become much simpler. The
actual, old version creates two (2) long pipelines; one for the "silent"
detection and second (similar) pipeline for recording. This is awful waste
of resources.
But of course, the new recorder must live with the above problem with
AAC, OGG and SPX formats. That's life!
------------
static GstElement *create_pipeline() {
GstElement *pipeline = gst_pipeline_new("a simple recorder");
GstElement *src = gst_element_factory_make("pulsesrc", "source");
g_object_set(G_OBJECT(src), "device", "alsa_input.usb-Creative_....",
NULL);
GstElement *filesink = gst_element_factory_make("filesink", "filesink");
g_object_set(G_OBJECT(filesink), "location", "test.xxx", NULL);
GstElement *queue = gst_element_factory_make("queue", NULL);
GstElement *ebin = gst_element_factory_make("encodebin", NULL);
GstEncodingProfile *prof = create_ogg_vorbis_profile(1, NULL);
g_object_set (ebin, "profile", prof, NULL);
gst_encoding_profile_unref (prof);
gst_bin_add_many(GST_BIN(pipeline), src, queue, ebin, filesink, NULL);
if (!gst_element_link_many(src, queue, ebin, filesink, NULL)) {
g_printerr("Cannot link many.\n");
}
GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
gst_bus_add_signal_watch(bus);
g_signal_connect(bus, "message::element",
G_CALLBACK(level_message_cb), NULL);
gst_object_unref(bus);
}
static GstEncodingProfile *create_ogg_vorbis_profile (guint presence,
gchar * preset) {
// I copied this from gstreamer's test-module. It seems to be very
easy to create new profiles.
GstEncodingContainerProfile *cprof;
GstCaps *ogg, *vorbis;
ogg = gst_caps_new_simple ("application/ogg", NULL);
cprof = gst_encoding_container_profile_new ((gchar *) "oggprofile",
NULL, ogg, NULL);
gst_caps_unref (ogg);
vorbis = gst_caps_new_simple ("audio/x-vorbis", NULL);
gst_encoding_container_profile_add_profile (cprof, (GstEncodingProfile
*) gst_encoding_audio_profile_new (vorbis, preset, NULL, presence));
gst_caps_unref (vorbis);
// audio/x-raw-float, rate=(int)[ 1, 200000 ], channels=(int)[ 1, 255
], endianness=(int)1234, width=(int)32
//
// caps = gst_caps_new_simple("audio/x-raw-float",
// "rate",G_TYPE_INT, 8000,
// "channels" ,G_TYPE_INT, (gint)1,
// "endianness",G_TYPE_INT,(gint)1234,
// "width" ,G_TYPE_INT, (gint)8, NULL);
return (GstEncodingProfile *)cprof;
}
Kindly
Osmo Antero
Post by Stefan Sauer
autoaudiosrc ! level ! tee name=t ! queue ! autoaudiosink t. ! queue !
valve ! encodebin ! filesink
when the level drops below a threshold, you close the valve and remember
the position. When the level gets above the threshold again, you open he
valve (and eventually push a newsegment event).
Stefan
_______________________________________________
_______________________________________________
gstreamer-devel mailing list
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Angel Martin
2013-06-05 08:55:59 UTC
Permalink
Hi,

To fully understand the elements/pads structure the right schedule is:

// Pipeline -> src -> dynamic pipeline
// Pipeline -> capsfilter(f264file) -> mp4mux(mux0)
-> filesink(fsink0)
// Pipeline -> elem_BEFORE||blockpad| ->
|elem_CUR_sinkpad||elem_CUR||elem_CUR_srcpad ->
|elem_AFTER_sinkpad||elem_AFTER

Best,

Angel
Post by Angel Martin
Dear all,
I did not achieve to create full legible muxed files for Gstreamer 0.10 on
top of multifilesink or output-selector.
After analysing lots of alternatives my solution takes as code base the
http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/section-dynamic-pipelines.html
The probes function API has been changed a bit but the solution below
static GstElement *pipeline = NULL;
// Pipeline -> src -> dynamic pipeline
// Pipeline -> capsfilter(f264file) -> mp4mux(mux0)
-> filesink(fsink0)
// Pipeline -> elem_before||blockpad| ->
|elem_cur_sinkpad||elem_cur||elem_cur_srcpad -> |elem_cur_sinkpad||elem_cur
static gulong probe_id; // probe ID
static GstElement *elem_before; // SRC of dynamic pipeline
static GstElement *elem_after; // SINK of dynamic pipeline
static GstElement *elem_cur; // Main element of dynamic pipeline
static GstPad *blockpad; // SRC pad to be blocked
static GstPad *elem_cur_srcpad; // SRC pad where check EOS
static GstPad *elem_cur_sinkpad; // SINK of dynamic pipeline
static GstPad *elem_after_sinkpad; // SINK of SINK element
// Last Buffer Timestamp
static GstClockTime last_ts = 0;
typedef enum {
NO_NEW_FILE, // Keep current file destination
NEW_FILE, // Switch file destination
} NewFileStatus;
static NewFileStatus newfile = NO_NEW_FILE; // Switch File Flag
static int counter = 1; // Index filename
// EOS listener to switch to other file destination
static gboolean
event_probe_cb (GstPad * pad, GstEvent * event, gpointer user_data)
{
g_print ("INSIDE event_probe_cb:%d type:%s\n",probe_id,
GST_EVENT_TYPE (event)==GST_EVENT_EOS?"EOS":GST_EVENT_TYPE
(event)==GST_EVENT_NEWSEGMENT?"NEWSEGMENT":"OTHER");
if (GST_EVENT_TYPE (event) != GST_EVENT_EOS)
{
// Push the event in the pipe flow (false DROP)
return TRUE;
}
// remove the probe first
gst_pad_remove_event_probe (pad, probe_id);
gst_object_unref (elem_cur_srcpad);
gst_object_unref (elem_after_sinkpad);
gst_element_release_request_pad(elem_cur, elem_cur_sinkpad);
gst_element_set_state (elem_cur, GST_STATE_NULL);
gst_element_set_state (elem_after, GST_STATE_NULL);
// remove unlinks automatically
GST_DEBUG_OBJECT (pipeline, "removing %" GST_PTR_FORMAT, elem_cur);
gst_bin_remove (GST_BIN (pipeline), elem_cur);
GST_DEBUG_OBJECT (pipeline, "removing %" GST_PTR_FORMAT, elem_after);
gst_bin_remove (GST_BIN (pipeline), elem_after);
GstElement * mux0 = gst_element_factory_make("mp4mux", "mux0");
GstElement * fsink0 = gst_element_factory_make("filesink", "fsink0");
elem_cur = mux0;
elem_after = fsink0;
if(!mux0 || !fsink0)
{
printf("mising elements\n");
}
GST_DEBUG_OBJECT (pipeline, "adding %" GST_PTR_FORMAT, elem_cur);
gst_bin_add (GST_BIN (pipeline), elem_cur);
GST_DEBUG_OBJECT (pipeline, "adding %" GST_PTR_FORMAT, elem_after);
gst_bin_add (GST_BIN (pipeline), elem_after);
char buffer[128];
sprintf(buffer, "test_%d.mp4", counter++);
g_print ("File Switching %s\n", buffer);
g_object_set(G_OBJECT(elem_after), "location", buffer, NULL);
GST_DEBUG_OBJECT (pipeline, "linking..");
elem_cur_srcpad = gst_element_get_static_pad (elem_cur, "src");
elem_cur_sinkpad = gst_element_get_request_pad (elem_cur, "video_%d");
elem_after_sinkpad = gst_element_get_static_pad (elem_after, "sink");
if(gst_pad_link(blockpad, elem_cur_sinkpad) != GST_PAD_LINK_OK)
{
printf("linking output 0 failed\n");
return -1;
}
if(gst_pad_link(elem_cur_srcpad, elem_after_sinkpad) != GST_PAD_LINK_OK)
{
printf("linking output 1 failed\n");
return -1;
}
g_print ("Moving to PLAYING\n");
gst_element_set_state (elem_cur, GST_STATE_PLAYING);
gst_element_set_state (elem_after, GST_STATE_PLAYING);
GST_DEBUG_OBJECT (pipeline, "done");
newfile = NO_NEW_FILE;
// Push the event in the pipe flow (false DROP)
return TRUE;
}
// Check if Buffer contains a KEY FRAME
static gboolean
is_sync_frame (GstBuffer * buffer)
{
if (GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT))
{
return FALSE;
}
else if (!GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_IN_CAPS))
{
return TRUE;
}
}
// Block source and launch EOS to MUXER to achieve a full muxed file
static gboolean
pad_probe_cb (GstPad * pad, GstBuffer * buffer, gpointer user_data)
{
g_print ("\n\tINSIDE pad_probe_cb:%d %s %s\n",probe_id,
(newfile?"newfile":"thesame"),
(is_sync_frame (buffer)?"KEYframe":"frame"));
GST_DEBUG_OBJECT (pad, "pad is blocked now");
last_ts = GST_BUFFER_TIMESTAMP(buffer);
if(!GST_CLOCK_TIME_IS_VALID(last_ts))
last_ts=0;
if((newfile==NO_NEW_FILE) || !is_sync_frame (buffer))
return TRUE;
/* remove the probe first */
gst_pad_remove_buffer_probe (pad, probe_id);
/* install new probe for EOS */
probe_id = gst_pad_add_event_probe (elem_after_sinkpad,
G_CALLBACK(event_probe_cb), user_data);
/* push EOS into the element, the probe will be fired when the
* EOS leaves the effect and it has thus drained all of its data */
gst_pad_send_event (elem_cur_sinkpad, gst_event_new_eos ());
// Wait til the EOS have been processed the Buffer with the Key frame
will be the FIRST
while(newfile != NO_NEW_FILE)
Sleep(1);
// Push the buffer in the pipe flow (false DROP)
return TRUE;
}
// this timeout is periodically run as part of the mainloop
static gboolean timeout (gpointer user_data)
{
g_print ("TIMEOUT\n");
if(!playing)
return false;
newfile = NEW_FILE;
/* install new probe for Keyframe and New File */
probe_id = gst_pad_add_buffer_probe (blockpad, G_CALLBACK(pad_probe_cb),
pipeline);
return true;
}
Best,
Angel
Post by Alexander Botero
Stefan, I took your "encodebin" very literally and made some tests with it.
I learned that it's possible to create a media (encoding) profile
during runtime.
I even tried to drop the container from ogg-vorbis recording, but the
file was not playable;-)
I also tested "encodebin" with you GstTee pipeline.
I haven't managed to adjust the internal clock of AAC, OGG Vorbis and
SPX formats.
They still "remember" the slient parts. But these tests have been very
interesting to do.
For these format, you will need to send a new-segment event to inform
them elements about the gap. You should find an example inside camerabin2
in gst-plugins-bad.
Stefan
I have decided to use the VADer element i our (GPL'ed) audio-recorder
because it has a very good algorithm for audio detection and noise
filtering.
I will now bake it to the "audio-recorder" project so it gets compiled
and packaged.
The "silent" detection in the recorder will become much simpler. The
actual, old version creates two (2) long pipelines; one for the "silent"
detection and second (similar) pipeline for recording. This is awful waste
of resources.
But of course, the new recorder must live with the above problem with
AAC, OGG and SPX formats. That's life!
------------
static GstElement *create_pipeline() {
GstElement *pipeline = gst_pipeline_new("a simple recorder");
GstElement *src = gst_element_factory_make("pulsesrc", "source");
g_object_set(G_OBJECT(src), "device", "alsa_input.usb-Creative_....",
NULL);
GstElement *filesink = gst_element_factory_make("filesink", "filesink");
g_object_set(G_OBJECT(filesink), "location", "test.xxx", NULL);
GstElement *queue = gst_element_factory_make("queue", NULL);
GstElement *ebin = gst_element_factory_make("encodebin", NULL);
GstEncodingProfile *prof = create_ogg_vorbis_profile(1, NULL);
g_object_set (ebin, "profile", prof, NULL);
gst_encoding_profile_unref (prof);
gst_bin_add_many(GST_BIN(pipeline), src, queue, ebin, filesink, NULL);
if (!gst_element_link_many(src, queue, ebin, filesink, NULL)) {
g_printerr("Cannot link many.\n");
}
GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
gst_bus_add_signal_watch(bus);
g_signal_connect(bus, "message::element",
G_CALLBACK(level_message_cb), NULL);
gst_object_unref(bus);
}
static GstEncodingProfile *create_ogg_vorbis_profile (guint presence,
gchar * preset) {
// I copied this from gstreamer's test-module. It seems to be very
easy to create new profiles.
GstEncodingContainerProfile *cprof;
GstCaps *ogg, *vorbis;
ogg = gst_caps_new_simple ("application/ogg", NULL);
cprof = gst_encoding_container_profile_new ((gchar *) "oggprofile",
NULL, ogg, NULL);
gst_caps_unref (ogg);
vorbis = gst_caps_new_simple ("audio/x-vorbis", NULL);
gst_encoding_container_profile_add_profile (cprof,
(GstEncodingProfile *) gst_encoding_audio_profile_new (vorbis, preset,
NULL, presence));
gst_caps_unref (vorbis);
// audio/x-raw-float, rate=(int)[ 1, 200000 ], channels=(int)[ 1, 255
], endianness=(int)1234, width=(int)32
//
// caps = gst_caps_new_simple("audio/x-raw-float",
// "rate",G_TYPE_INT, 8000,
// "channels" ,G_TYPE_INT, (gint)1,
// "endianness",G_TYPE_INT,(gint)1234,
// "width" ,G_TYPE_INT, (gint)8, NULL);
return (GstEncodingProfile *)cprof;
}
Kindly
Osmo Antero
Post by Stefan Sauer
autoaudiosrc ! level ! tee name=t ! queue ! autoaudiosink t. ! queue !
valve ! encodebin ! filesink
when the level drops below a threshold, you close the valve and remember
the position. When the level gets above the threshold again, you open he
valve (and eventually push a newsegment event).
Stefan
_______________________________________________
_______________________________________________
gstreamer-devel mailing list
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Loading...