static void test_prepare_reusable (GstRTSPThreadPool * pool, const gchar * launch_line) { GstRTSPMediaFactory *factory; GstRTSPMedia *media; GstRTSPUrl *url; GstRTSPThread *thread; factory = gst_rtsp_media_factory_new (); fail_if (gst_rtsp_media_factory_is_shared (factory)); fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test", &url) == GST_RTSP_OK); gst_rtsp_media_factory_set_launch (factory, launch_line); media = gst_rtsp_media_factory_construct (factory, url); fail_unless (GST_IS_RTSP_MEDIA (media)); fail_unless (gst_rtsp_media_n_streams (media) == 1); g_object_set (G_OBJECT (media), "reusable", TRUE, NULL); thread = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_MEDIA, NULL); fail_unless (gst_rtsp_media_prepare (media, thread)); fail_unless (gst_rtsp_media_unprepare (media)); fail_unless (gst_rtsp_media_n_streams (media) == 1); thread = gst_rtsp_thread_pool_get_thread (pool, GST_RTSP_THREAD_TYPE_MEDIA, NULL); fail_unless (gst_rtsp_media_prepare (media, thread)); fail_unless (gst_rtsp_media_unprepare (media)); g_object_unref (media); gst_rtsp_url_free (url); g_object_unref (factory); }
int main(int argc, char **argv) { GMainLoop *loop; GstRTSPServer *server; GstRTSPMediaMapping *mapping; GstRTSPCamMediaFactory *factory; GstRTSPUrl *local_url; GOptionContext *ctx; GOptionGroup *gst_group; gboolean res; GError *error = NULL; g_type_init (); g_thread_init (NULL); ctx = g_option_context_new ("rtsp://host:port/path"); g_option_context_add_main_entries (ctx, option_entries, NULL); gst_group = gst_init_get_option_group (); g_option_context_add_group (ctx, gst_group); res = g_option_context_parse (ctx, &argc, &argv, &error); g_option_context_free (ctx); gst_init (&argc, &argv); if (!res) { g_printerr ("command line error: %s\n", error->message); g_error_free (error); return 1; } if (gst_rtsp_url_parse (argc != 2 ? "rtsp://127.0.0.1:8554/test" : argv[1], &local_url) != GST_RTSP_OK) { g_printerr ("invalid rtsp url\n"); return 1; } loop = g_main_loop_new (NULL, FALSE); server = gst_rtsp_server_new (); factory = gst_rtsp_cam_media_factory_new (); g_object_set (factory, "video-device", video_device, "video", !no_video, "video-width", video_width, "video-height", video_height, "video-codec", video_codec, "video-framerate", fps_n, fps_d, "audio", !no_audio, "audio-device", audio_device, "audio-codec", audio_codec, NULL); gst_rtsp_media_factory_set_shared (GST_RTSP_MEDIA_FACTORY (factory), TRUE); mapping = gst_rtsp_server_get_media_mapping (server); gst_rtsp_media_mapping_add_factory (mapping, local_url->abspath, GST_RTSP_MEDIA_FACTORY (factory)); g_object_unref (mapping); gst_rtsp_url_free (local_url); gst_rtsp_server_attach (server, NULL); g_timeout_add_seconds (5, (GSourceFunc) timeout, server); /* start serving */ g_main_loop_run (loop); return 0; }
/** * gst_rtsp_url_parse: * @urlstr: the url string to parse * @url: (out): location to hold the result. * * Parse the RTSP @urlstr into a newly allocated #GstRTSPUrl. Free after usage * with gst_rtsp_url_free(). * * Returns: a #GstRTSPResult. */ GstRTSPResult gst_rtsp_url_parse (const gchar * urlstr, GstRTSPUrl ** url) { GstRTSPUrl *res; gchar *p, *delim, *at, *col; gchar *host_end = NULL; guint i; g_return_val_if_fail (urlstr != NULL, GST_RTSP_EINVAL); g_return_val_if_fail (url != NULL, GST_RTSP_EINVAL); res = g_new0 (GstRTSPUrl, 1); p = (gchar *) urlstr; col = strstr (p, "://"); if (col == NULL) goto invalid; for (i = 0; i < G_N_ELEMENTS (rtsp_schemes_map); i++) { if (g_ascii_strncasecmp (rtsp_schemes_map[i].scheme, p, col - p) == 0) { res->transports = rtsp_schemes_map[i].transports; p = col + 3; break; } } if (res->transports == GST_RTSP_LOWER_TRANS_UNKNOWN) goto invalid; delim = strpbrk (p, "/?"); at = strchr (p, '@'); if (at && delim && at > delim) at = NULL; if (at) { col = strchr (p, ':'); /* must have a ':' and it must be before the '@' */ if (col == NULL || col > at) goto invalid; res->user = g_uri_unescape_segment (p, col, NULL); col++; res->passwd = g_uri_unescape_segment (col, at, NULL); /* move to host */ p = at + 1; } if (*p == '[') { res->family = GST_RTSP_FAM_INET6; /* we have an IPv6 address in the URL, find the ending ] which must be * before any delimiter */ host_end = strchr (++p, ']'); if (!host_end || (delim && host_end >= delim)) goto invalid; /* a port specifier must follow the address immediately */ col = host_end[1] == ':' ? host_end + 1 : NULL; } else { res->family = GST_RTSP_FAM_INET; col = strchr (p, ':'); /* we have a ':' and a delimiter but the ':' is after the delimiter, it's * not really part of the hostname */ if (col && delim && col >= delim) col = NULL; host_end = col ? col : delim; } if (!host_end) res->host = g_strdup (p); else { res->host = g_strndup (p, host_end - p); if (col) { res->port = strtoul (col + 1, NULL, 10); } else { /* no port specified, set to 0. gst_rtsp_url_get_port() will return the * default port */ res->port = 0; } } p = delim; if (p && *p == '/') { delim = strchr (p, '?'); if (!delim) res->abspath = g_strdup (p); else res->abspath = g_strndup (p, delim - p); p = delim; } else { /* IQinVision IQeye 1080p fails if a path '/' is provided * and RTSP does not mandate that a non-zero-length path * must be used */ res->abspath = g_strdup (""); } if (p && *p == '?') res->query = g_strdup (p + 1); *url = res; return GST_RTSP_OK; /* ERRORS */ invalid: { gst_rtsp_url_free (res); return GST_RTSP_EINVAL; } }
/** * gst_rtsp_url_parse: * @urlstr: the url string to parse * @url: location to hold the result. * * Parse the RTSP @urlstr into a newly allocated #GstRTSPUrl. Free after usage * with gst_rtsp_url_free(). * * Returns: a #GstRTSPResult. */ GstRTSPResult gst_rtsp_url_parse (const gchar * urlstr, GstRTSPUrl ** url) { GstRTSPUrl *res; gchar *p, *delim, *at, *col; g_return_val_if_fail (urlstr != NULL, GST_RTSP_EINVAL); g_return_val_if_fail (url != NULL, GST_RTSP_EINVAL); res = g_new0 (GstRTSPUrl, 1); p = (gchar *) urlstr; if (g_str_has_prefix (p, RTSP_PROTO)) { res->transports = GST_RTSP_LOWER_TRANS_TCP | GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST; p += RTSP_PROTO_LEN; } else if (g_str_has_prefix (p, RTSPU_PROTO)) { res->transports = GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST; p += RTSPU_PROTO_LEN; } else if (g_str_has_prefix (p, RTSPT_PROTO)) { res->transports = GST_RTSP_LOWER_TRANS_TCP; p += RTSPT_PROTO_LEN; } else goto invalid; delim = strpbrk (p, "/?"); at = strchr (p, '@'); if (at && delim && at > delim) at = NULL; if (at) { col = strchr (p, ':'); /* must have a ':' and it must be before the '@' */ if (col == NULL || col > at) goto invalid; res->user = g_strndup (p, col - p); col++; res->passwd = g_strndup (col, at - col); /* move to host */ p = at + 1; } col = strchr (p, ':'); /* we have a ':' and a delimiter but the ':' is after the delimiter, it's * not really part of the hostname */ if (col && delim && col >= delim) col = NULL; if (col) { res->host = g_strndup (p, col - p); p = col + 1; res->port = strtoul (p, (char **) &p, 10); if (delim) p = delim; } else { /* no port specified, set to 0. _get_port() will return the default port. */ res->port = 0; if (!delim) { res->host = g_strdup (p); p = NULL; } else { res->host = g_strndup (p, delim - p); p = delim; } } if (p && *p == '/') { delim = strchr (p, '?'); if (!delim) { res->abspath = g_strdup (p); p = NULL; } else { res->abspath = g_strndup (p, delim - p); p = delim; } } else { res->abspath = g_strdup ("/"); } if (p && *p == '?') res->query = g_strdup (p + 1); *url = res; return GST_RTSP_OK; /* ERRORS */ invalid: { gst_rtsp_url_free (res); return GST_RTSP_EINVAL; } }
static GstRTSPStatusCode nmp_rtsp_handle_request(NmpMediaDevice *device, GstRTSPMessage *request) { GstRTSPMethod method; GstRTSPVersion version; const gchar *url_str; GstRTSPUrl *url; NmpRtspState state = { NULL }; GstRTSPMessage response = { 0 }; GstRTSPStatusCode rtsp_code = GST_RTSP_STS_OK; state.request = request; state.response = &response; gst_rtsp_message_parse_request(request, &method, &url_str, &version); if (version != GST_RTSP_VERSION_1_0) { /* we can only handle 1.0 requests */ nmp_rtsp_device_send_generic_response(device, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, &state); return GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED; } state.method = method; if (gst_rtsp_url_parse(url_str, &url) != GST_RTSP_OK) { nmp_rtsp_device_send_generic_response(device, GST_RTSP_STS_BAD_REQUEST, &state); return GST_RTSP_STS_BAD_REQUEST; } state.url = url; switch (method) { case GST_RTSP_OPTIONS: rtsp_code = nmp_rtsp_handle_options_request(device, &state); break; case GST_RTSP_TEARDOWN: // nmp_rtsp_handle_teardown_request(device, &state); break; case GST_RTSP_DESCRIBE: case GST_RTSP_SETUP: case GST_RTSP_PLAY: case GST_RTSP_PAUSE: case GST_RTSP_SET_PARAMETER: case GST_RTSP_GET_PARAMETER: case GST_RTSP_ANNOUNCE: case GST_RTSP_RECORD: case GST_RTSP_REDIRECT: nmp_rtsp_device_send_generic_response(device, GST_RTSP_STS_NOT_IMPLEMENTED, &state); break; case GST_RTSP_INVALID: default: nmp_rtsp_device_send_generic_response(device, GST_RTSP_STS_BAD_REQUEST, &state); break; } gst_rtsp_url_free(url); return rtsp_code; }