Fix gst leaks

This commit is contained in:
Jonas Kvinge 2019-03-27 00:27:49 +01:00
parent 9d7e44be2d
commit 21970f3065
2 changed files with 59 additions and 46 deletions

View File

@ -94,14 +94,16 @@ GstEnginePipeline::GstEnginePipeline(GstEngine *engine)
audiobin_(nullptr),
queue_(nullptr),
audioconvert_(nullptr),
rgvolume_(nullptr),
rglimiter_(nullptr),
audioconvert2_(nullptr),
equalizer_(nullptr),
audio_panorama_(nullptr),
volume_(nullptr),
audioscale_(nullptr),
audiosink_(nullptr) {
audiosink_(nullptr),
volume_(nullptr),
audio_panorama_(nullptr),
equalizer_preamp_(nullptr),
equalizer_(nullptr),
rgvolume_(nullptr),
rglimiter_(nullptr)
{
if (!sElementDeleter) {
sElementDeleter = new GstElementDeleter;
@ -111,6 +113,17 @@ GstEnginePipeline::GstEnginePipeline(GstEngine *engine)
}
GstEnginePipeline::~GstEnginePipeline() {
if (pipeline_) {
gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), nullptr, nullptr, nullptr);
g_source_remove(bus_cb_id_);
gst_element_set_state(pipeline_, GST_STATE_NULL);
gst_object_unref(GST_OBJECT(pipeline_));
}
}
void GstEnginePipeline::set_output_device(const QString &output, const QVariant &device) {
output_ = output;
@ -151,12 +164,12 @@ bool GstEnginePipeline::InitDecodeBin(GstElement *decode_bin) {
pipeline_ = gst_pipeline_new("pipeline");
gst_bin_add(GST_BIN(pipeline_), decode_bin);
if (!gst_bin_add(GST_BIN(pipeline_), decode_bin)) return false;
if (!InitAudioBin()) return false;
gst_bin_add(GST_BIN(pipeline_), audiobin_);
if (!gst_bin_add(GST_BIN(pipeline_), audiobin_)) return false;
gst_element_link(decode_bin, audiobin_);
if (!gst_element_link(decode_bin, audiobin_)) return false;
return true;
@ -196,8 +209,7 @@ bool GstEnginePipeline::InitAudioBin() {
// After the tee the pipeline splits. One split is converted to 16-bit int samples for the scope, the other is kept as float32 and sent to the speaker.
// tee1 ! probe_queue ! probe_converter ! <caps16> ! probe_sink
// tee2 ! audio_queue ! equalizer_preamp ! equalizer ! volume ! audioscale
// ! convert ! audiosink
// tee2 ! audio_queue ! equalizer_preamp ! equalizer ! volume ! audioscale ! convert ! audiosink
gst_segment_init(&last_decodebin_segment_, GST_FORMAT_TIME);
@ -234,19 +246,16 @@ bool GstEnginePipeline::InitAudioBin() {
}
// Create all the other elements
GstElement *tee, *probe_queue, *probe_converter, *probe_sink, *audio_queue, *convert;
queue_ = engine_->CreateElement("queue2", audiobin_);
audioconvert_ = engine_->CreateElement("audioconvert", audiobin_);
tee = engine_->CreateElement("tee", audiobin_);
probe_queue = engine_->CreateElement("queue", audiobin_);
probe_converter = engine_->CreateElement("audioconvert", audiobin_);
probe_sink = engine_->CreateElement("fakesink", audiobin_);
audio_queue = engine_->CreateElement("queue", audiobin_);
GstElement *tee = engine_->CreateElement("tee", audiobin_);
GstElement *probe_queue = engine_->CreateElement("queue", audiobin_);
GstElement *probe_converter = engine_->CreateElement("audioconvert", audiobin_);
GstElement *probe_sink = engine_->CreateElement("fakesink", audiobin_);
GstElement *audio_queue = engine_->CreateElement("queue", audiobin_);
audioscale_ = engine_->CreateElement("audioresample", audiobin_);
convert = engine_->CreateElement("audioconvert", audiobin_);
GstElement *convert = engine_->CreateElement("audioconvert", audiobin_);
if (engine_->volume_control()) {
volume_ = engine_->CreateElement("volume", audiobin_);
@ -261,10 +270,12 @@ bool GstEnginePipeline::InitAudioBin() {
if (!queue_ || !audioconvert_ || !tee || !probe_queue || !probe_converter || !probe_sink || !audio_queue || !audioscale_ || !convert) {
gst_object_unref(GST_OBJECT(audiobin_));
audiobin_ = nullptr;
return false;
}
// Create the replaygain elements if it's enabled. event_probe is the audioconvert element we attach the probe to, which will change depending on whether replaygain is enabled.
// Create the replaygain elements if it's enabled.
// event_probe is the audioconvert element we attach the probe to, which will change depending on whether replaygain is enabled.
// convert_sink is the element after the first audioconvert, which again will change.
GstElement *event_probe = audioconvert_;
GstElement *convert_sink = tee;
@ -350,8 +361,13 @@ bool GstEnginePipeline::InitAudioBin() {
gst_element_link(probe_converter, probe_sink);
// Link the outputs of tee to the queues on each path.
gst_pad_link(gst_element_get_request_pad(tee, "src_%u"), gst_element_get_static_pad(probe_queue, "sink"));
gst_pad_link(gst_element_get_request_pad(tee, "src_%u"), gst_element_get_static_pad(audio_queue, "sink"));
pad = gst_element_get_static_pad(probe_queue, "sink");
gst_pad_link(gst_element_get_request_pad(tee, "src_%u"), pad);
gst_object_unref(pad);
pad = gst_element_get_static_pad(audio_queue, "sink");
gst_pad_link(gst_element_get_request_pad(tee, "src_%u"), pad);
gst_object_unref(pad);
// Link replaygain elements if enabled.
if (rg_enabled_ && rgvolume_ && rglimiter_ && audioconvert2_) {
@ -378,9 +394,14 @@ bool GstEnginePipeline::InitAudioBin() {
gst_caps_unref(caps);
// Add probes and handlers.
gst_pad_add_probe(gst_element_get_static_pad(probe_converter, "src"), GST_PAD_PROBE_TYPE_BUFFER, HandoffCallback, this, nullptr);
gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallbackSync, this, nullptr);
bus_cb_id_ = gst_bus_add_watch(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallback, this);
pad = gst_element_get_static_pad(probe_converter, "src");
gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER, HandoffCallback, this, nullptr);
gst_object_unref(pad);
GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline_));
gst_bus_set_sync_handler(bus, BusCallbackSync, this, nullptr);
bus_cb_id_ = gst_bus_add_watch(bus, BusCallback, this);
gst_object_unref(bus);
return true;
@ -389,6 +410,7 @@ bool GstEnginePipeline::InitAudioBin() {
bool GstEnginePipeline::InitFromString(const QString &pipeline) {
GstElement *new_bin = CreateDecodeBinFromString(pipeline.toUtf8().constData());
if (!new_bin) return false;
return InitDecodeBin(new_bin);
}
@ -400,7 +422,7 @@ bool GstEnginePipeline::InitFromUrl(const QByteArray &media_url, const QUrl orig
end_offset_nanosec_ = end_nanosec;
pipeline_ = engine_->CreateElement("playbin");
if (pipeline_ == nullptr) return false;
if (!pipeline_) return false;
g_object_set(G_OBJECT(pipeline_), "uri", media_url.constData(), nullptr);
CHECKED_GCONNECT(G_OBJECT(pipeline_), "about-to-finish", &AboutToFinishCallback, this);
@ -418,17 +440,6 @@ bool GstEnginePipeline::InitFromUrl(const QByteArray &media_url, const QUrl orig
}
GstEnginePipeline::~GstEnginePipeline() {
if (pipeline_) {
gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), nullptr, nullptr, nullptr);
g_source_remove(bus_cb_id_);
gst_element_set_state(pipeline_, GST_STATE_NULL);
gst_object_unref(GST_OBJECT(pipeline_));
}
}
gboolean GstEnginePipeline::BusCallback(GstBus*, GstMessage *msg, gpointer self) {
GstEnginePipeline *instance = reinterpret_cast<GstEnginePipeline*>(self);
@ -581,7 +592,7 @@ void GstEnginePipeline::ErrorMessageReceived(GstMessage *msg) {
// A track is still playing and the next uri is not playable. We ignore the error here so it can play until the end.
// But there is no message send to the bus when the current track finishes, we have to add an EOS ourself.
qLog(Debug) << "Ignoring error when loading next track";
GstPad* sinkpad = gst_element_get_static_pad(audiobin_, "sink");
GstPad *sinkpad = gst_element_get_static_pad(audiobin_, "sink");
gst_pad_send_event(sinkpad, gst_event_new_eos());
gst_object_unref(sinkpad);
return;
@ -898,6 +909,8 @@ void GstEnginePipeline::SourceSetupCallback(GstPlayBin *bin, GParamSpec *pspec,
instance->SetState(GST_STATE_PLAYING);
}
g_object_unref(element);
}
qint64 GstEnginePipeline::position() const {

View File

@ -158,7 +158,7 @@ signals:
QString ParseStrTag(GstTagList *list, const char *tag) const;
guint ParseUIntTag(GstTagList *list, const char *tag) const;
bool InitDecodeBin(GstElement* new_bin);
bool InitDecodeBin(GstElement *new_bin);
bool InitAudioBin();
GstElement *CreateDecodeBinFromString(const char *pipeline);
@ -272,15 +272,15 @@ signals:
// Elements in the audiobin. See comments in Init()'s definition.
GstElement *queue_;
GstElement *audioconvert_;
GstElement *rgvolume_;
GstElement *rglimiter_;
GstElement *audioconvert2_;
GstElement *equalizer_preamp_;
GstElement *equalizer_;
GstElement *audio_panorama_;
GstElement *volume_;
GstElement *audioscale_;
GstElement *audiosink_;
GstElement *volume_;
GstElement *audio_panorama_;
GstElement *equalizer_preamp_;
GstElement *equalizer_;
GstElement *rgvolume_;
GstElement *rglimiter_;
uint bus_cb_id_;