#include "gstplayer.h"
#include <QDebug>
gboolean GstPlayer::bus_callback (GstBus *bus,
GstMessage *message,
gpointer data)
{
//g_print ("Got %s message\n", GST_MESSAGE_TYPE_NAME (message));
GMainLoop *loop = (GMainLoop *) data;
switch (GST_MESSAGE_TYPE (message))
{
case GST_MESSAGE_ERROR:
{
GError *err;
gchar *debug;
gst_message_parse_error (message, &err, &debug);
//g_print ("Error: %s\n", err->message);
emit s_obj->signal_errorinfo(QString(err->message));
emit s_obj->signal_stateinfo(QString("Error:")+QString(err->message));
g_error_free (err);
g_free (debug);
g_main_loop_quit (loop);
break;
}
case GST_MESSAGE_EOS:
/* end-of-stream */
//g_print ("Stream Ends\n");
emit s_obj->signal_errorinfo(QString("码流结束"));
emit s_obj->signal_stateinfo(QString("Stream Ends."));
g_main_loop_quit (loop);
break;
default:
/* unhandled message */
break;
}
/* we want to be notified again the next time there is a message
* on the bus, so returning TRUE (FALSE means we want to stop watching
* for messages on the bus and our callback should not be called again)
*/
return TRUE;
}
void GstPlayer::on_pad_added(GstElement *src, GstPad *new_pad, CustomData *data)
{
GstElement *depay = (GstElement *) data->gst_depay;
GstPad *sink_pad = gst_element_get_static_pad (depay, "sink");
GstPadLinkReturn ret;
GstCaps *new_pad_caps = NULL;
GstStructure *new_pad_struct = NULL;
const gchar *new_pad_type = NULL;
qDebug ("'%s' Received new pad '%s' from '%s':\n",DEBUGINFO, GST_PAD_NAME (new_pad), GST_ELEMENT_NAME (src));
/* If our converter is already linked, we have nothing to do here */
if (gst_pad_is_linked (sink_pad))
{
qDebug ()<<DEBUGERROR<<"We are already linked. Ignoring.";
emit s_obj->signal_stateinfo(QString("already linked. Ignoring."));
goto exit;
}
/* Check the new pad's type */
new_pad_caps = gst_pad_get_current_caps (new_pad);
new_pad_struct = gst_caps_get_structure (new_pad_caps, 0);
new_pad_type = gst_structure_get_name (new_pad_struct);
if (!g_str_has_prefix (new_pad_type, "application/x-rtp"))
{
emit s_obj->signal_stateinfo(QString("It has type %1 which is not find. Ignoring.").arg(QString(new_pad_type)));
qDebug ("'%s' It has type '%s' which is not find. Ignoring.\n",DEBUGERROR, new_pad_type);
goto exit;
}
/* Attempt the link */
ret = gst_pad_link (new_pad, sink_pad);
if (GST_PAD_LINK_FAILED (ret))
{
emit s_obj->signal_stateinfo(QString("Type is %1 but link failed.").arg(QString(new_pad_type)));
qDebug ("'%s' Type is '%s' but link failed.\n",DEBUGERROR, new_pad_type);
}
else
{
emit s_obj->signal_stateinfo(QString("Link succeeded (type %1).").arg(QString(new_pad_type)));
qDebug ("'%s' Link succeeded (type '%s').\n",DEBUGINFO, new_pad_type);
}
exit:
/* Unreference the new pad's caps, if we got them */
if (new_pad_caps != NULL)
gst_caps_unref (new_pad_caps);
/* Unreference the sink pad */
gst_object_unref (sink_pad);
}
GstPlayer* GstPlayer::s_obj = nullptr;
GstPlayer::GstPlayer(QString url,QObject *parent)
: QObject(parent),m_url(url)
{
s_obj = this;
//GstElement *pipeline = gst_parse_launch ("gst-launch-1.0 rtspsrc location=rtsp://192.168.31.10:554/h264/ch1/main/av_stream user-id=\"admin\" user-pw=\"123456\" ! rtph264depay ! queue ! h264parse ! mppvideodec ! waylandsink sync=false", NULL);
// 创建管道
data.gst_src = gst_element_factory_make("rtspsrc", "source");
if("H264" == App::encoding)
data.gst_depay = gst_element_factory_make("rtph264depay","depay");
else
data.gst_depay = gst_element_factory_make("rtph265depay","depay");
data.gst_queue = gst_element_factory_make("queue", "queue");
if("H264" == App::encoding)
data.gst_parser = gst_element_factory_make("h264parse", "parse");
else
data.gst_parser = gst_element_factory_make("h265parse", "parse");
data.gst_decoder = gst_element_factory_make("mppvideodec", "deodec");
data.gst_sink = gst_element_factory_make ("waylandsink","sink");
data.gst_pipeline = gst_pipeline_new ("new-pipeline");
if (!data.gst_pipeline || !data.gst_src || !data.gst_depay || !data.gst_queue
|| !data.gst_parser || !data.gst_decoder || !data.gst_sink)
{
emit signal_errorinfo("可视化初始化失败失败.");
emit signal_stateinfo("可视化初始化失败失败.");
return;
}
//设置每个元素的参数, 需要查看gst-inspect-1.0 rtspsrc
g_object_set (G_OBJECT(data.gst_src), "location",m_url.toStdString().c_str(),NULL);
g_object_set(G_OBJECT(data.gst_sink), "window-x", MIPI_WIDTH, NULL);
g_object_set(G_OBJECT(data.gst_sink), "window-y", 0, NULL);
int hdmiWidth = 1280;
int hdmiHeight = 800;
QStringList ra = App::resolutionratio.split('*');
if(2 == ra.count())
{
hdmiWidth = ra.at(0).toInt();
hdmiHeight = ra.at(1).toInt();
}
g_object_set(G_OBJECT(data.gst_sink), "window-width", hdmiWidth, NULL);
g_object_set(G_OBJECT(data.gst_sink), "window-height", hdmiHeight, NULL);
g_object_set(G_OBJECT(data.gst_sink), "fill-mode", 0, NULL);
g_object_set(G_OBJECT(data.gst_sink), "sync", false, NULL);
// 将多个插件连接起来
gst_bin_add_many(GST_BIN(data.gst_pipeline),data.gst_src,data.gst_depay,data.gst_queue,data.gst_parser,data.gst_decoder, data.gst_sink, NULL);
//连接
if(gst_element_link_many(data.gst_depay,data.gst_queue,data.gst_parser,data.gst_decoder, data.gst_sink, NULL) == 0 )
{
emit signal_errorinfo("可视化连接失败.");
emit signal_stateinfo("可视化连接失败.");
return;
}
//查看元素,以为rtspsrc的Availability为Sometimes,所以要动态绑定pad
//https://blog.csdn.net/hello_dear_you/article/details/122374435
g_signal_connect (data.gst_src, "pad-added", G_CALLBACK (on_pad_added), &data);
//绑定UI界面
//gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (data.gst_sink), this->winId());
//将管道的消息总线上的新消息的监视添加到默认的GLib主上下文,这是下面我们的GLib主循环附加到的主上下文
data.loop = g_main_loop_new (NULL, FALSE);
data.bus = gst_pipeline_get_bus (GST_PIPELINE (data.gst_pipeline));
gst_bus_add_watch (data.bus, bus_callback, data.loop);
gst_object_unref (data.bus);
}
GstPlayer::~GstPlayer()
{
g_main_loop_unref (data.loop);
gst_object_unref (data.bus);
gst_element_set_state (data.gst_pipeline, GST_STATE_NULL);
gst_object_unref (data.gst_pipeline);
}
void GstPlayer::play()
{
GstStateChangeReturn ret = gst_element_set_state (data.gst_pipeline, GST_STATE_PLAYING);
if (ret == GST_STATE_CHANGE_FAILURE)
{
emit signal_errorinfo("可视化播放失败.");
emit signal_stateinfo("可视化播放失败.");
gst_object_unref (data.gst_pipeline);
return;
}
g_main_loop_run (data.loop);
}
void GstPlayer::replay()
{
stop();
QUIHelper::sleep(50);
g_object_set (G_OBJECT(data.gst_src), "location",m_url.toStdString().c_str(),NULL);
play();
}
void GstPlayer::stop()
{
GstStateChangeReturn ret = gst_element_set_state (data.gst_pipeline, GST_STATE_NULL);
if (ret == GST_STATE_CHANGE_FAILURE)
{
emit signal_errorinfo("可视化停止失败.");
emit signal_stateinfo("可视化停止失败.");
gst_object_unref (data.gst_pipeline);
return;
}
}