Hi,
I set up 2 applications: one server using the gst-rtsp-server library to send a stream over rtsp, and one client application using rtspsrc to receive the stream. I would like the client to be able to set parameters in the server using the rtsp SET_PARAMETER method. I see that rtspsrc has a "set-parameter" signal, but I don't understand how I can implement this in my C project. Does anyone have some example code that he/she can share, or provide me information so I can better understand how to implement this? Thank you in advance! Kind regards, Thomas -- Sent from: http://gstreamer-devel.966125.n4.nabble.com/ _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
To anyone wanting to implement get- and set- parameter requests, after a long
time going through the source code I have found the way to do it. Here is an explanation: First of all, get- and set-parameter has only been implemented since august 2018 (see link <https://gstreamer-bugs.narkive.com/1ZFqXqdw/bug-792131-new-rtspsrc-add-an-action-signal-to-send-set-parameter> ), so you will need one of the latest version of gstreamer (I got it working on 1.16.0) GET-PARAMETER I'll start with GET-PARAMETER, as it's more complex as the server will also have to send the right response. Client Side rtspsrc has the "get-parameter" action signal to send a get-parameter request. The function looks like this: get_parameter_callback (GstElement rtspsrc, gchararray parameter_name, gchararray content_type, GstPromise promise, gpointer udata) So everything we need is a pointer to the rtspsrc element, a string containing the name, a string containing the content type (can be NULL), and a pointer to the promise. The promise is an object that will hold information about the response: if you got a response, or if it's expired, timed out, ... and also the response itself. When you send a get-parameter request through the action signal, you will want to block on the promise until you received a reply, and afterwards you can read the reply in the promise. So the code for setting up the get-parameter looks like this: int get_parameter(char name[8]) { char *get_body; char get_name[16]; char get_value[16]; // construct promise which we can read out later GstPromise *promise = gst_promise_new(); // send action signal to send GET-PARAMETER request g_signal_emit_by_name(rtspsrc, "get_parameter", name, NULL, promise); // wait until response is received GstPromiseResult result = gst_promise_wait(promise); if (result == GST_PROMISE_RESULT_REPLIED) { const GstStructure *reply = gst_promise_get_reply(promise); // the response will be in the "body" part of GstStructure get_body = gst_structure_get_string(reply, "body"); sscanf(get_body, "%s %s\n", get_name, get_value); g_print("%s is %s \n", get_name, get_value); } else { g_print("wait promise failed, code: %d \n", result); } } Server Side On server side (with gst-rtsp-server) we will need the specify how the server needs to respond to requests. Intuitively you would want to check the "get-parameter-request" signal of GstRTSPClient object, but this callback is called /after/ the server has already handled the request and sent a response, and the standard response to a get-parameter request which the server doesn't understand (which actually is any request), it will send an error response "Parameter not understood", so this is quite useless. Therefore you will need to find a way to change how the server handles requests: when the server receives a get-parameter request, it will execute a function "params_get", to initialize a response, which is actually a function pointer in the GstRTSPClient structure. So we need to change the function pointer to point to our own function to create a response. You can do this by acquiring the GstRTSPClientClass object, and then setting the function pointer to our own function. For this you need access to the GstRTSPClient object, which you can acquire in the callback of the "client-connected" signal of the server. so in the client-connected-callback you can issue the following to get access to the GstRTSPClientClass: static void client_connected_callback (GstRTSPServer * self, GstRTSPClient * object, gpointer user_data) { GstRTSPClientClass *client_class = GST_RTSP_CLIENT_GET_CLASS (object); // change function pointer to point to our own function client_class->params_get = custom_params_get; } our own function will parse the request message from context, and depending on the request will construct a response: static GstRTSPResult custom_params_get (GstRTSPClient * client, GstRTSPContext * ctx) { guint8 *request; guint length = 0; char parameter[32]; guint8 response[16]; gst_rtsp_message_get_body(ctx->request, &request, &length); if (request != NULL) { // extract parameter name from request sscanf((char *)request, "%s\n", parameter); if (strcmp(parameter, "requested_parameter:") == 0) { // initialse a response gst_rtsp_message_init_response(ctx->response, GST_RTSP_STS_OK, NULL, ctx->request); // add requested parameter and value to the body of the response snprintf((char *)response, sizeof(response), "%s %d\n", name, value_requested_parameter); gst_rtsp_message_set_body(ctx->response, response, sizeof(response)); } } return GST_RTSP_OK; } afterwards it will send send the response and your client will receive the response in promise. SET-PARAMETER set parameter works almost the same: Client Side int MLXTOFset_parameter(char name[8], char value[8]) { GstPromise *promise = gst_promise_new(); g_signal_emit_by_name(data.channel0.source, "set-parameter", name, value, NULL, promise); // you can check promise like you did in get-parameter to see if server has accepted the request in the same way as above, but it's not necessary return 0; } Server Side To be complete, on server side you should also adapt the function pointer of params_set so you can send the right response (if the server has accepted the request), and you can do it the same way as in get-parameter, so I will not repeat here. If you don't, the the server will always respond with "Parameter not understood". To receive the request, you have either already acquired it in your custom function as explained in the previous paragraph, or you can simply use the signal callback "set-parameter-request" of the GstRTSPClient object. In the callback you have access to GstRTSPContext, from which you can access the request message, so the callback would look like this: static void set_parameter_request_callback (GstRTSPClient * self, GstRTSPContext * ctx, gpointer user_data) { guint8 *request; char name[32]; char value[32]; int value_int; guint length = 0; gst_rtsp_message_get_body(ctx->request, &request, &length); sscanf((char *)request, "%s %s\n", name, value); value_int = atoi(value); if (strcmp(name, "parameter_to_be_set:") == 0) { _parameter = value_int; } } -- Sent from: http://gstreamer-devel.966125.n4.nabble.com/ _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
Free forum by Nabble | Edit this page |