经常用到将appsrc中填充数据后,以rtsp流的形式推出。和rtmp不同的是,rtmp需要用ngnix做为server,而rtsp就是通过代码自己搭建一个server,代码如下
static int need_data_rtsp (GstElement * appsrc, guint unused, data * ptr)
{
if(*(ptr->Stop))
{
cout<<"stop pushing"<
}
GstBuffer *buffer;
guint size;
GstFlowReturn ret =GST_FLOW_OK;
size = (ptr->Input->size().width) * (ptr->Input->size().height) * 3;
buffer = gst_buffer_new_allocate (NULL, size, NULL);
GstMapInfo map;
gst_buffer_map(buffer,&map,GST_MAP_READ);
ptr->Mux->lock();
memcpy(map.data,ptr->Input->data,size);
ptr->Mux->unlock();
guint64 s = ( getTickCount() - ptr->t) * GST_SECOND / getTickFrequency();
ptr->t = getTickCount();
GST_BUFFER_PTS (buffer) = ptr->Timestamp;
GST_BUFFER_DURATION (buffer) = s;
ptr->Timestamp += GST_BUFFER_DURATION (buffer) ;
g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret);
gst_buffer_unmap(buffer,&map);
std::cout<<"pushing"<
gst_buffer_unref (buffer);
if ( *(ptr->Stop) ) {
/* something wrong, stop pushing */
g_main_loop_quit (ptr->Loop);
}
return 1;
}
static void media_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media, push_stream *ptr)
{
GstElement *element, *appsrc;
// GMainLoop *loop = g_main_loop_new (NULL, FALSE);
data *ctx = new data(ptr->input,ptr->mux,&(ptr->stop),ptr->loop);
/* get the element used for providing the streams of the media */
element = gst_rtsp_media_get_element (media);
/* get our appsrc, we named it 'mysrc' with the name property */
appsrc = gst_bin_get_by_name_recurse_up (GST_BIN (element), "mysrc");
/* this instructs appsrc that we will be dealing with timed buffer */
gst_util_set_object_arg (G_OBJECT (appsrc), "format", "time");
/* configure the caps of the video */
g_object_set (G_OBJECT (appsrc), "caps",
gst_caps_new_simple ("video/x-raw",
"format", G_TYPE_STRING, "BGR",
"width", G_TYPE_INT, ptr->width,
"height", G_TYPE_INT, ptr->height,
"framerate", GST_TYPE_FRACTION, 2, 1, NULL), NULL);
/* make sure ther datais freed when the media is gone */
//g_object_set_data_full (G_OBJECT (media), "my-extra-data", ctx,
// (GDestroyNotify) g_free);
/* install the callback that will be called when a buffer is needed */
g_signal_connect (appsrc, "need-data", (GCallback) need_data_rtsp, ctx);
// g_main_loop_run (loop);
gst_object_unref (appsrc);
gst_object_unref (element);
cout<<"new a client"<
}
void push_stream:: push_rtsp()
{
gst_init (NULL, NULL);
loop = g_main_loop_new (NULL, FALSE);
/* create a server instance */
server = gst_rtsp_server_new ();
gst_rtsp_server_set_service (server,"8556");
// gst_rtsp_server_set_address (server,"192.168.1.164");
/* get the mount points for this server, every server has a default object
* that be used to map uri mount points to media factories */
mounts = gst_rtsp_server_get_mount_points (server);
/* make a media factory for a test stream. The default media factory can use
* gst-launch syntax to create pipelines.
* any launch line works as long as it contains elements named pay%d. Each
* element with pay%d names will be a stream */
factory = gst_rtsp_media_factory_new ();
gst_rtsp_media_factory_set_launch (factory,
"( appsrc name=mysrc ! videoconvert ! x264enc ! rtph264pay name=pay0 pt=96 )");
/* notify when our media is ready, This is called whenever someone asks for
* the media and a new pipeline with our appsrc is created */
g_signal_connect (factory, "media-configure", (GCallback) media_configure,this);
/* attach the test factory to the /test url */
gst_rtsp_mount_points_add_factory (mounts, “/test"”, factory);
/* don't need the ref to the mounts anymore */
g_object_unref (mounts);
/* attach the server to the default maincontext */
gst_rtsp_server_attach (server, NULL);
/* start serving */
g_print ("stream ready at rtsp://127.0.0.1:8554/test\n");
g_main_loop_run (loop);
}
程序的流程是调用push_rtsp()函数后,进入主循环中,当有一个client请求连接时,就会触发 g_signal_connect (factory, "media-configure", (GCallback) media_configure,this)这句,调用media-configure()函数,当数据写入appsrc时触发 g_signal_connect (appsrc, "need-data", (GCallback) need_data_rtsp, ctx);回调 need-data()这个函数。因为项目的要求,我用到了data 和 push_stream 这两个类,push_rtsp()就是push_stream 中的一个方法。
类的具体定义:
class data
{
public:
data(Mat* _Input,mutex* _Mux, int* _Stop ,GMainLoop* _Loop);
~data();
Mat * Input;
mutex * Mux;
int * Stop;
GMainLoop *Loop;
GstClockTime Timestamp;
int64 t;
};
class push_stream
{
private:
GstElement *pipeline;
GstElement *appsrc;
GstElement *conv;
GstElement *videosink;
GstElement *h264enc;
GstElement *flvmux;
String location;
GstRTSPServer *server;
GstRTSPMountPoints *mounts;
GstRTSPMediaFactory *factory;
public:
int stop;
int width;
int height;
GMainLoop *loop;
Mat *input;
mutex *mux;
void stop_stream();
push_stream();
push_stream(String _location ,Mat* _input, mutex *_mux);
void continue_stream();
void push_rtmp ();
void push_rtsp ();
void init (String _location, Mat* _input, mutex *_mux);
~push_stream();
};
https://github.com/GStreamer/gst-rtsp-server/tree/master/examples这个链接中有一些rtsp的有用的代码,测试过部分,可用。