Fix gst leaks
This commit is contained in:
@@ -94,14 +94,16 @@ GstEnginePipeline::GstEnginePipeline(GstEngine *engine)
|
|||||||
audiobin_(nullptr),
|
audiobin_(nullptr),
|
||||||
queue_(nullptr),
|
queue_(nullptr),
|
||||||
audioconvert_(nullptr),
|
audioconvert_(nullptr),
|
||||||
rgvolume_(nullptr),
|
|
||||||
rglimiter_(nullptr),
|
|
||||||
audioconvert2_(nullptr),
|
audioconvert2_(nullptr),
|
||||||
equalizer_(nullptr),
|
|
||||||
audio_panorama_(nullptr),
|
|
||||||
volume_(nullptr),
|
|
||||||
audioscale_(nullptr),
|
audioscale_(nullptr),
|
||||||
audiosink_(nullptr) {
|
audiosink_(nullptr),
|
||||||
|
volume_(nullptr),
|
||||||
|
audio_panorama_(nullptr),
|
||||||
|
equalizer_preamp_(nullptr),
|
||||||
|
equalizer_(nullptr),
|
||||||
|
rgvolume_(nullptr),
|
||||||
|
rglimiter_(nullptr)
|
||||||
|
{
|
||||||
|
|
||||||
if (!sElementDeleter) {
|
if (!sElementDeleter) {
|
||||||
sElementDeleter = new GstElementDeleter;
|
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) {
|
void GstEnginePipeline::set_output_device(const QString &output, const QVariant &device) {
|
||||||
|
|
||||||
output_ = output;
|
output_ = output;
|
||||||
@@ -151,12 +164,12 @@ bool GstEnginePipeline::InitDecodeBin(GstElement *decode_bin) {
|
|||||||
|
|
||||||
pipeline_ = gst_pipeline_new("pipeline");
|
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;
|
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;
|
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.
|
// 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
|
// tee1 ! probe_queue ! probe_converter ! <caps16> ! probe_sink
|
||||||
// tee2 ! audio_queue ! equalizer_preamp ! equalizer ! volume ! audioscale
|
// tee2 ! audio_queue ! equalizer_preamp ! equalizer ! volume ! audioscale ! convert ! audiosink
|
||||||
// ! convert ! audiosink
|
|
||||||
|
|
||||||
gst_segment_init(&last_decodebin_segment_, GST_FORMAT_TIME);
|
gst_segment_init(&last_decodebin_segment_, GST_FORMAT_TIME);
|
||||||
|
|
||||||
@@ -234,19 +246,16 @@ bool GstEnginePipeline::InitAudioBin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create all the other elements
|
// Create all the other elements
|
||||||
GstElement *tee, *probe_queue, *probe_converter, *probe_sink, *audio_queue, *convert;
|
|
||||||
|
|
||||||
queue_ = engine_->CreateElement("queue2", audiobin_);
|
queue_ = engine_->CreateElement("queue2", audiobin_);
|
||||||
audioconvert_ = engine_->CreateElement("audioconvert", audiobin_);
|
audioconvert_ = engine_->CreateElement("audioconvert", audiobin_);
|
||||||
tee = engine_->CreateElement("tee", audiobin_);
|
GstElement *tee = engine_->CreateElement("tee", audiobin_);
|
||||||
|
GstElement *probe_queue = engine_->CreateElement("queue", audiobin_);
|
||||||
probe_queue = engine_->CreateElement("queue", audiobin_);
|
GstElement *probe_converter = engine_->CreateElement("audioconvert", audiobin_);
|
||||||
probe_converter = engine_->CreateElement("audioconvert", audiobin_);
|
GstElement *probe_sink = engine_->CreateElement("fakesink", audiobin_);
|
||||||
probe_sink = engine_->CreateElement("fakesink", audiobin_);
|
GstElement *audio_queue = engine_->CreateElement("queue", audiobin_);
|
||||||
|
|
||||||
audio_queue = engine_->CreateElement("queue", audiobin_);
|
|
||||||
audioscale_ = engine_->CreateElement("audioresample", audiobin_);
|
audioscale_ = engine_->CreateElement("audioresample", audiobin_);
|
||||||
convert = engine_->CreateElement("audioconvert", audiobin_);
|
GstElement *convert = engine_->CreateElement("audioconvert", audiobin_);
|
||||||
|
|
||||||
if (engine_->volume_control()) {
|
if (engine_->volume_control()) {
|
||||||
volume_ = engine_->CreateElement("volume", audiobin_);
|
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) {
|
if (!queue_ || !audioconvert_ || !tee || !probe_queue || !probe_converter || !probe_sink || !audio_queue || !audioscale_ || !convert) {
|
||||||
gst_object_unref(GST_OBJECT(audiobin_));
|
gst_object_unref(GST_OBJECT(audiobin_));
|
||||||
|
audiobin_ = nullptr;
|
||||||
return false;
|
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.
|
// convert_sink is the element after the first audioconvert, which again will change.
|
||||||
GstElement *event_probe = audioconvert_;
|
GstElement *event_probe = audioconvert_;
|
||||||
GstElement *convert_sink = tee;
|
GstElement *convert_sink = tee;
|
||||||
@@ -350,8 +361,13 @@ bool GstEnginePipeline::InitAudioBin() {
|
|||||||
gst_element_link(probe_converter, probe_sink);
|
gst_element_link(probe_converter, probe_sink);
|
||||||
|
|
||||||
// Link the outputs of tee to the queues on each path.
|
// 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"));
|
pad = 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"));
|
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.
|
// Link replaygain elements if enabled.
|
||||||
if (rg_enabled_ && rgvolume_ && rglimiter_ && audioconvert2_) {
|
if (rg_enabled_ && rgvolume_ && rglimiter_ && audioconvert2_) {
|
||||||
@@ -378,9 +394,14 @@ bool GstEnginePipeline::InitAudioBin() {
|
|||||||
gst_caps_unref(caps);
|
gst_caps_unref(caps);
|
||||||
|
|
||||||
// Add probes and handlers.
|
// Add probes and handlers.
|
||||||
gst_pad_add_probe(gst_element_get_static_pad(probe_converter, "src"), GST_PAD_PROBE_TYPE_BUFFER, HandoffCallback, this, nullptr);
|
pad = gst_element_get_static_pad(probe_converter, "src");
|
||||||
gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallbackSync, this, nullptr);
|
gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER, HandoffCallback, this, nullptr);
|
||||||
bus_cb_id_ = gst_bus_add_watch(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallback, this);
|
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;
|
return true;
|
||||||
|
|
||||||
@@ -389,6 +410,7 @@ bool GstEnginePipeline::InitAudioBin() {
|
|||||||
bool GstEnginePipeline::InitFromString(const QString &pipeline) {
|
bool GstEnginePipeline::InitFromString(const QString &pipeline) {
|
||||||
|
|
||||||
GstElement *new_bin = CreateDecodeBinFromString(pipeline.toUtf8().constData());
|
GstElement *new_bin = CreateDecodeBinFromString(pipeline.toUtf8().constData());
|
||||||
|
if (!new_bin) return false;
|
||||||
return InitDecodeBin(new_bin);
|
return InitDecodeBin(new_bin);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -400,7 +422,7 @@ bool GstEnginePipeline::InitFromUrl(const QByteArray &media_url, const QUrl orig
|
|||||||
end_offset_nanosec_ = end_nanosec;
|
end_offset_nanosec_ = end_nanosec;
|
||||||
|
|
||||||
pipeline_ = engine_->CreateElement("playbin");
|
pipeline_ = engine_->CreateElement("playbin");
|
||||||
if (pipeline_ == nullptr) return false;
|
if (!pipeline_) return false;
|
||||||
|
|
||||||
g_object_set(G_OBJECT(pipeline_), "uri", media_url.constData(), nullptr);
|
g_object_set(G_OBJECT(pipeline_), "uri", media_url.constData(), nullptr);
|
||||||
CHECKED_GCONNECT(G_OBJECT(pipeline_), "about-to-finish", &AboutToFinishCallback, this);
|
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) {
|
gboolean GstEnginePipeline::BusCallback(GstBus*, GstMessage *msg, gpointer self) {
|
||||||
|
|
||||||
GstEnginePipeline *instance = reinterpret_cast<GstEnginePipeline*>(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.
|
// 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.
|
// 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";
|
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_pad_send_event(sinkpad, gst_event_new_eos());
|
||||||
gst_object_unref(sinkpad);
|
gst_object_unref(sinkpad);
|
||||||
return;
|
return;
|
||||||
@@ -898,6 +909,8 @@ void GstEnginePipeline::SourceSetupCallback(GstPlayBin *bin, GParamSpec *pspec,
|
|||||||
instance->SetState(GST_STATE_PLAYING);
|
instance->SetState(GST_STATE_PLAYING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_object_unref(element);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 GstEnginePipeline::position() const {
|
qint64 GstEnginePipeline::position() const {
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ signals:
|
|||||||
QString ParseStrTag(GstTagList *list, const char *tag) const;
|
QString ParseStrTag(GstTagList *list, const char *tag) const;
|
||||||
guint ParseUIntTag(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();
|
bool InitAudioBin();
|
||||||
GstElement *CreateDecodeBinFromString(const char *pipeline);
|
GstElement *CreateDecodeBinFromString(const char *pipeline);
|
||||||
|
|
||||||
@@ -272,15 +272,15 @@ signals:
|
|||||||
// Elements in the audiobin. See comments in Init()'s definition.
|
// Elements in the audiobin. See comments in Init()'s definition.
|
||||||
GstElement *queue_;
|
GstElement *queue_;
|
||||||
GstElement *audioconvert_;
|
GstElement *audioconvert_;
|
||||||
GstElement *rgvolume_;
|
|
||||||
GstElement *rglimiter_;
|
|
||||||
GstElement *audioconvert2_;
|
GstElement *audioconvert2_;
|
||||||
GstElement *equalizer_preamp_;
|
|
||||||
GstElement *equalizer_;
|
|
||||||
GstElement *audio_panorama_;
|
|
||||||
GstElement *volume_;
|
|
||||||
GstElement *audioscale_;
|
GstElement *audioscale_;
|
||||||
GstElement *audiosink_;
|
GstElement *audiosink_;
|
||||||
|
GstElement *volume_;
|
||||||
|
GstElement *audio_panorama_;
|
||||||
|
GstElement *equalizer_preamp_;
|
||||||
|
GstElement *equalizer_;
|
||||||
|
GstElement *rgvolume_;
|
||||||
|
GstElement *rglimiter_;
|
||||||
|
|
||||||
uint bus_cb_id_;
|
uint bus_cb_id_;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user