Audio recording script quality bad using Gsreamer - python

Thanks to this amazing community i finished my project about capturing audio from an audio input and saving it to a faile using gstreamer
Now i would like to refine the quality of the capture, since my script saves the audio as mono with 80kbps on 44100 hz. I would like to make it atleast stereo on 128 kbps
here is the code. P.S. feel free to use it anywhere you wish!
import gi
import datetime, time
import sys
import signal
gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst, Gtk
GObject.threads_init()
Gst.init(None)
pipeline = Gst.Pipeline()
autoaudiosrc = Gst.ElementFactory.make("autoaudiosrc", "autoaudiosrc")
audioconvert = Gst.ElementFactory.make("audioconvert", "audioconvert")
audioresample= Gst.ElementFactory.make("audioresample","audioresample")
vorbisenc = Gst.ElementFactory.make("vorbisenc", "vorbisenc")
oggmux = Gst.ElementFactory.make("oggmux", "oggmux")
filesink = Gst.ElementFactory.make("filesink", "filesink")
url = datetime.datetime.now()
audioresample.quality=10
filesink.set_property("location",url)
pipeline.add( autoaudiosrc)
pipeline.add( audioconvert)
pipeline.add( vorbisenc)
pipeline.add( oggmux)
pipeline.add( filesink)
pipeline.add( audioresample)
autoaudiosrc.link( audioconvert)
audioconvert.link( audioresample)
audioresample.link( vorbisenc)
vorbisenc.link( oggmux)
oggmux.link( filesink)
pipeline.set_state(Gst.State.PLAYING)
Gtk.main()

import gi
import datetime, time
import sys
import signal
signal.alarm(15)
gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst, Gtk
GObject.threads_init()
Gst.init(None)
pipeline = Gst.Pipeline()
autoaudiosrc = Gst.ElementFactory.make("autoaudiosrc", "autoaudiosrc")
audioconvert = Gst.ElementFactory.make("audioconvert", "audioconv")
audioresample= Gst.ElementFactory.make("audioresample","audioresample")
vorbisenc = Gst.ElementFactory.make("vorbisenc", "vorbisenc")
oggmux = Gst.ElementFactory.make("oggmux", "oggmux")
filesink = Gst.ElementFactory.make("filesink", "filesink")
url = datetime.datetime.now()
audioresample.set_property("quality", 10)
vorbisenc.set_property("quality", 1)
filesink.set_property("location",url)
pipeline.add( autoaudiosrc)
pipeline.add( audioconvert)
pipeline.add( vorbisenc)
pipeline.add( oggmux)
pipeline.add( filesink)
pipeline.add( audioresample)
autoaudiosrc.link( audioconvert)
audioconvert.link( audioresample)
audioresample.link(vorbisenc)
vorbisenc.link( oggmux)
oggmux.link( filesink)
pipeline.set_state(Gst.State.PLAYING)
Gtk.main()
There,it's smooth and ok now, i like it ( i probably don't have to have audioconvert, but it smooths the quality a tad bit, was trying a lot of other things but this is the best quality i can get)

Related

Memory leak occurs when using Gstreamer and multiprocessing.Manager().Namespace() in the same process

I'm using a Gstreamer to storyboard some video. I put each frame in multiprocessing.Manager().Namespace() for transfer between processes. In this case, a memory leak is observed. During 10 hours of application work, memory consumption increased by 400 MB. If you comment out the call of self.update_frame(buf.extract_dup(0, buf.get_size())), then the memory leak does not occur.
An example of a memory leak test:
import unittest
import gi
import traceback
import os, psutil
from multiprocessing import Process, Manager, Event
gi.require_version('Gst', '1.0')
from gi.repository import Gst
class RtpNamespaceTest(unittest.TestCase):
pipeline_str = '''
videotestsrc pattern=ball ! \
appsink name=handle-app-sink \
emit-signals=True \
max-buffers=1 \
drop=True \
'''
name_space = Manager().Namespace()
pipeline = None
event_interrupt: Event = Event()
def start(self):
# initializing gstreamer, subscribing to rtp-stream
Gst.init(None)
print(self.pipeline_str)
self.pipeline = Gst.parse_launch(self.pipeline_str)
self.pipeline.set_state(Gst.State.PLAYING)
self.appsink = self.pipeline.get_by_name('handle-app-sink')
self.appsink.connect("new-sample", self.on_new_buffer)
bus = self.pipeline.get_bus()
# listen to messages until storyboarding is stopped
while not self.event_interrupt.is_set():
bus.timed_pop_filtered(10000, Gst.MessageType.ANY)
# stops the pipeline, free up resources
self.pipeline.set_state(Gst.State.NULL)
def on_new_buffer(self, src):
sample = src.emit("pull-sample")
buf = sample.get_buffer()
# writing a frame in binary format in Namespace()
self.update_frame(buf.extract_dup(0, buf.get_size()))
print(f"RAM = {psutil.Process(os.getpid()).memory_info().rss / 1024 / 1024}")
return Gst.FlowReturn.OK
def update_frame(self, frame: bytes):
self.name_space.frame = frame
def test_repository(self):
while True:
try:
self.start()
except Exception as ex:
traceback.print_exc()
time.sleep(float(10))

Why the program only can run once.(PYTHON)

import gi
gi.require_version('Gst', '1.0')
from gi.repository import GObject #,Gtk
from gi.repository import Gst as gst
import datetime
def take_photo():
GObject.threads_init()
gst.init(None)
pipeline = gst.Pipeline()
video_source = gst.ElementFactory.make('v4l2src', 'video_source')
vconvert = gst.ElementFactory.make('videoconvert', 'vconvert')
clock = gst.ElementFactory.make('clockoverlay', 'clock')
timer= gst.ElementFactory.make('timeoverlay','timer')
vrate = gst.ElementFactory.make('videorate', 'vrate')
sconvert = gst.ElementFactory.make('videoconvert', 'sconvert')
png = gst.ElementFactory.make('pngenc', 'png')
multi_sink = gst.ElementFactory.make('multifilesink', 'multi_sink')
caps = gst.caps_from_string("video/x-raw,format=RGB,width=800,height=600,framerate=5/1")
timer.set_property('valignment','bottom')
timer.set_property('halignment','right')
clock.set_property('time-format','%Y/%m/%d %H:%M:%S')
clock.set_property('valignment','bottom')
caps1 = gst.caps_from_string("video/x-raw,framerate=1/1")
png.set_property('snapshot',True)
multi_sink.set_property('location','/home/pi/frame%05d.png')
filter = gst.ElementFactory.make("capsfilter", "filter")
filter.set_property("caps", caps)
filter1 = gst.ElementFactory.make("capsfilter", "filter1")
filter1.set_property("caps", caps1)
pipeline.add(video_source)
pipeline.add(vconvert)
pipeline.add(timer)
pipeline.add(clock)
pipeline.add(filter)
pipeline.add(vrate)
pipeline.add(filter1)
pipeline.add(sconvert)
pipeline.add(png)
pipeline.add(multi_sink)
video_source.link(filter)
filter.link(vconvert)
vconvert.link(timer)
timer.link(clock)
clock.link(vrate)
vrate.link(filter1)
filter1.link(sconvert)
sconvert.link(png)
png.link(multi_sink)
bus = pipeline.get_bus()
pipeline.set_state(gst.State.PLAYING)
print "Capture started"
bus = pipeline.get_bus()#class
msg = bus.timed_pop_filtered(gst.CLOCK_TIME_NONE,gst.MessageType.ERROR | gst.MessageType.EOS)
print msg
pipeline.set_state(gst.State.NULL)
Once the program run for the first time, it capture the image and when i run the second time, nothing happen. And i need to restart the whole python program in order to it to run again. Anybody can help me solve it?
What about implementing it as class, so do a proper initializationof gstreamer stuff.. and in take_photo you just play the pipe and stop it afterwards.. in should be reusable then (from gstreamer point of view.. pipe can go to NULL and PLAYING over and over):
class TakePhoto:
def __init__(self):
GObject.threads_init()
gst.init(None)
self.pipeline = gst.Pipeline()
.. do the element creation and their linking etc ..
def take_photo(self): #this is reusable
bus = self.pipeline.get_bus()
self.pipeline.set_state(gst.State.PLAYING)
print "Capture started"
bus = self.pipeline.get_bus()#class
msg = bus.timed_pop_filtered(gst.CLOCK_TIME_NONE,gst.MessageType.ERROR | gst.MessageType.EOS)
print msg
self.pipeline.set_state(gst.State.NULL)
Then python shell you can initialize one instance and call take_photo multiple times:
TakePhoto tp
tp.take_photo()
tp.take_photo()
This code is typed out of my head so I take no responsibility if it boils your HDD or anything.. and also I am not used to code in python.. so it may be full of bugs :D
but HTH

Python3 error with Gstreamer

I run:
raspivid -t 999999 -w 1080 -h 720 -fps 25 -hf -b 2000000 -o - | \gst-launch-1.0 -v fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 \! gdppay ! tcpserversink host=serverIp port=5000
on the Raspberry Pi and run:
gst-launch-1.0 -v tcpclientsrc host=serverIp port=5000 \! gdpdepay ! rtph264depay ! avdec_h264 ! videoconvert ! autovideosink sync=false
on my computer. and I received the video streamed from Raspberry.
now I want write a python code to do so in my computer.my code is :
#!/usr/bin/python3
from os import path
import gi
gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst, Gtk
# Needed for window.get_xid(), xvimagesink.set_window_handle(), respectively:
from gi.repository import GdkX11, GstVideo
GObject.threads_init()
Gst.init(None)
class Player(object):
def __init__(self):
self.pipeline = Gst.Pipeline()
self.tcpsrc = Gst.ElementFactory.make('tcpclientsrc','tcpsrc')
self.tcpsrc.set_property("host",'192.168.1.12')
self.tcpsrc.set_property("port",5000)
self.gdepay = Gst.ElementFactory.make('gdpdepay', 'gdepay')
self.rdepay = Gst.ElementFactory.make('rtph264depay', 'rdepay')
self.avdec = Gst.ElementFactory.make('avdec_h264', 'avdec')
self.vidconvert = Gst.ElementFactory.make('videoconvert', 'vidconvert')
self.asink = Gst.ElementFactory.make('appsink', 'asink')
self.asink.set_property('sync', False)
#self.asink.set_property('emit-signals', True)
#self.set_property('drop', True)
self.pipeline.add(self.tcpsrc)
self.pipeline.add(self.gdepay)
self.pipeline.add(self.rdepay)
self.pipeline.add(self.avdec)
self.pipeline.add(self.vidconvert)
self.pipeline.add(self.asink)
self.tcpsrc.link(self.gdepay)
self.gdepay.link(self.rdepay)
self.rdepay.link(self.avdec)
self.avdec.link(self.vidconvert)
self.vidconvert.link(self.asink)
def run(self):
self.pipeline.set_state(Gst.State.PLAYING)
p = Player()
p.run()
but I get the following error:
(DO.py:3618): GStreamer-WARNING **:
gstpad.c:4555:store_sticky_event: Sticky event
misordering, got 'segment' before 'caps'
(DO.py:3618): GStreamer-WARNING **:
gstpad.c:4555:store_sticky_event: Sticky event
misordering, got 'segment' before 'caps'
Best Regards,
Mostafa
I answered My question: I replaced this code:
#!/usr/bin/python3
from os import path
import gi
gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst, Gtk
# Needed for window.get_xid(), xvimagesink.set_window_handle(), respectively:
from gi.repository import GdkX11, GstVideo
GObject.threads_init()
Gst.init(None)
class Player(object):
def __init__(self):
self.pipeline = Gst.Pipeline()
self.tcpsrc = Gst.ElementFactory.make('tcpclientsrc','tcpsrc')
self.tcpsrc.set_property("host", '192.168.1.13')
self.tcpsrc.set_property("port", 5000)
self.gdepay = Gst.ElementFactory.make('gdpdepay', 'gdepay')
self.rdepay = Gst.ElementFactory.make('rtph264depay', 'rdepay')
self.avdec = Gst.ElementFactory.make('avdec_h264', 'avdec')
self.vidconvert = Gst.ElementFactory.make('videoconvert', 'vidconvert')
self.asink = Gst.ElementFactory.make('autovideosink', 'asink')
self.asink.set_property('sync', False)
#self.asink.set_property('emit-signals', True)
#self.set_property('drop', True)
self.pipeline.add(self.tcpsrc)
self.pipeline.add(self.gdepay)
self.pipeline.add(self.rdepay)
self.pipeline.add(self.avdec)
self.pipeline.add(self.vidconvert)
self.pipeline.add(self.asink)
self.tcpsrc.link(self.gdepay)
self.gdepay.link(self.rdepay)
self.rdepay.link(self.avdec)
self.avdec.link(self.vidconvert)
self.vidconvert.link(self.asink)
def run(self):
self.pipeline.set_state(Gst.State.PLAYING)
Gtk.main()
p = Player()
p.run()
first, I forgotten to add Gtk.main() to the run function.
second I changed self.asink = Gst.ElementFactory.make('appsink', 'asink') to self.asink = Gst.ElementFactory.make('autovideosink', 'asink')

GStreamer error "assertion 'GST_IS_ELEMENT (src)' failed" when linking elements

I'm working on a GStreamer-based program using Python and the GObject introspection bindings. I'm trying to build this pipeline:
videomixer name=mix ! autovideosink \
uridecodebin uri=v4l2:///dev/video0 ! mix.
The pipeline works perfectly using gst-launch-1.0, but my Python program gives the errors:
(minimal.py:12168): GStreamer-CRITICAL **: gst_element_link_pads_full: assertion 'GST_IS_ELEMENT (src)' failed
on_error(): (GError('Internal data flow error.',), 'gstbasesrc.c(2865): gst_base_src_loop (): /GstPipeline:pipeline0/GstURIDecodeBin:uridecodebin0/GstV4l2Src:source:\nstreaming task paused, reason not-linked (-1)')
My code:
#!/usr/bin/python3
import gi
gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst, Gtk, GdkX11, GstVideo
GObject.threads_init()
Gst.init(None)
class Source:
def __init__(self, uri, pipeline, mixer):
self.uri = uri
self.pipeline = pipeline
self.mixer = mixer
self.src = Gst.ElementFactory.make('uridecodebin', None)
self.pipeline.add(self.src)
self.src.set_property('uri', uri)
self.src.connect('pad-added', self.on_pad_added, self.src, self.mixer)
def on_pad_added(self, element, pad, src, dest):
name = pad.query_caps(None).to_string()
print('on_pad_added:', name)
if name.startswith('video/'):
src.link(dest)
class Main:
def __init__(self):
self.window = Gtk.Window()
self.window.connect('destroy', self.quit)
self.window.set_default_size(1280, 720)
self.drawingarea = Gtk.DrawingArea()
self.window.add(self.drawingarea)
self.pipeline = Gst.Pipeline()
self.bus = self.pipeline.get_bus()
self.bus.add_signal_watch()
self.bus.connect('message::error', self.on_error)
self.bus.enable_sync_message_emission()
self.bus.connect('sync-message::element', self.on_sync_message)
self.mixer = Gst.ElementFactory.make('videomixer', None)
self.sink = Gst.ElementFactory.make('autovideosink', None)
self.pipeline.add(self.mixer)
self.pipeline.add(self.sink)
self.mixer.link(self.sink)
video = Source('v4l2:///dev/video0', self.pipeline, self.mixer)
def run(self):
self.window.show_all()
# You need to get the XID after window.show_all(). You shouldn't get it
# in the on_sync_message() handler because threading issues will cause
# segfaults there.
self.xid = self.drawingarea.get_property('window').get_xid()
self.pipeline.set_state(Gst.State.PLAYING)
Gtk.main()
def quit(self, window):
self.pipeline.set_state(Gst.State.NULL)
Gtk.main_quit()
def on_sync_message(self, bus, msg):
if msg.get_structure().get_name() == 'prepare-window-handle': msg.src.set_window_handle(self.xid)
def on_error(self, bus, msg):
print('on_error():', msg.parse_error())
main = Main()
main.run()
I figured out the problem, I was linking the dynamically-created pad incorrectly:
src.link(dest)
Should have been:
pad.link(dest.get_compatible_pad(pad, None))
If the element is not added with the pipeline, then this error will occur. Ensure that the problematic element is added with the pipeline.

gstreamer appsrc works for xvimagesink but no in theoraenc ! oggmux

I am trying to stream cast a computer generated video using gstreamer and icecast, but I cannot get gstreamer appsrc to work. My app works as expected if I use xvimagesink as the sink(see commented code below). But once I pipe it to theoraenc it does not run.
I exchanged shout2send with filesink to check if the problem was icecast, the result is that no data is written to the file. Substituting appsrc with testvideosrc works as expected. Any suggestion?
#!/usr/bin/env python
import sys, os, pygtk, gtk, gobject
import pygst
pygst.require("0.10")
import gst
import numpy as np
class GTK_Main:
def __init__(self):
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.connect("destroy", gtk.main_quit, "WM destroy")
vbox = gtk.VBox()
window.add(vbox)
self.button = gtk.Button("Start")
self.button.connect("clicked", self.start_stop)
vbox.add(self.button)
window.show_all()
self.player = gst.Pipeline("player")
source = gst.element_factory_make("appsrc", "source")
caps = gst.Caps("video/x-raw-gray,bpp=16,endianness=1234,width=320,height=240,framerate=(fraction)10/1")
source.set_property('caps',caps)
source.set_property('blocksize',320*240*2)
source.connect('need-data', self.needdata)
colorspace = gst.element_factory_make('ffmpegcolorspace')
enc = gst.element_factory_make('theoraenc')
mux = gst.element_factory_make('oggmux')
shout = gst.element_factory_make('shout2send')
shout.set_property("ip","localhost")
shout.set_property("password","hackme")
shout.set_property("mount","/stream")
caps = gst.Caps("video/x-raw-yuv,width=320,height=240,framerate=(fraction)10/1,format=(fourcc)I420")
enc.caps = caps
videosink = gst.element_factory_make('xvimagesink')
videosink.caps = caps
self.player.add(source, colorspace, enc, mux, shout)
gst.element_link_many(source, colorspace, enc, mux, shout)
#self.player.add(source, colorspace, videosink)
#gst.element_link_many(source, colorspace, videosink)
def start_stop(self, w):
if self.button.get_label() == "Start":
self.button.set_label("Stop")
self.player.set_state(gst.STATE_PLAYING)
else:
self.player.set_state(gst.STATE_NULL)
self.button.set_label("Start")
def needdata(self, src, length):
bytes = np.int16(np.random.rand(length/2)*30000).data
src.emit('push-buffer', gst.Buffer(bytes))
GTK_Main()
gtk.gdk.threads_init()
gtk.main()
I think that your problem is most likely to do with timestamping of the buffers. I've done some quick testing, using that code and replacing the shout element with oggdemux, theoradec, ffmpegcolorspace and ximagesink. At first, I got no output, but after I dispensed with the muxing/demuxing altogether, I got a static image, along with some debug messages about timestamps. I got the correct output after setting the is-live and do-timestamp properties to true on appsrc.
I assume that it should be possible to directly set the timestamps on the buffers that you are pushing out of appsrc, but alas I've not discovered how to do that.

Categories