/** * gst_switch_server_new_record: * @return: TRUE if succeeded. * * Start a new recording. * */ gboolean gst_switch_server_new_record (GstSwitchServer * srv) { GstWorkerClass *worker_class; gboolean result = FALSE; g_return_val_if_fail (GST_IS_RECORDER (srv->recorder), FALSE); if (srv->recorder) { GST_SWITCH_SERVER_LOCK_RECORDER (srv); if (srv->recorder) { gst_worker_stop (GST_WORKER (srv->recorder)); g_object_set (G_OBJECT (srv->recorder), "mode", srv->composite->mode, "port", srv->composite->encode_sink_port, "width", srv->composite->width, "height", srv->composite->height, NULL); worker_class = GST_WORKER_CLASS (G_OBJECT_GET_CLASS (srv->recorder)); if (worker_class->reset (GST_WORKER (srv->recorder))) { result = gst_worker_start (GST_WORKER (srv->recorder)); } else { ERROR ("failed to reset composite recorder"); } } GST_SWITCH_SERVER_UNLOCK_RECORDER (srv); } return result; }
int main (int argc, char **argv) { gst_init (&argc, &argv); g_mutex_init (&trans_lock); mainloop = g_main_loop_new (NULL, TRUE); worker0 = GST_WORKER (g_object_new (GST_TYPE_WORKER, "name", "test-worker-0", NULL)); worker0->pipeline_func = test_worker_pipeline; g_signal_connect (worker0, "prepare-worker", G_CALLBACK (test_worker_prepare), NULL); g_signal_connect (worker0, "start-worker", G_CALLBACK (test_worker_start), NULL); g_signal_connect (worker0, "end-worker", G_CALLBACK (test_worker_end), NULL); g_thread_new ("test-pulse", (GThreadFunc) test_worker_pulse, worker0); gst_worker_start (worker0); g_main_loop_run (mainloop); g_mutex_clear (&trans_lock); INFO ("end"); return 0; }
/** * gst_composite_apply_parameters: * * Applying new composite parameters such as PIP position. This is actually * resetting the composite pipeline with the new parameters. */ static void gst_composite_apply_parameters (GstComposite * composite) { GstWorkerClass *worker_class; g_return_if_fail (GST_IS_COMPOSITE (composite)); worker_class = GST_WORKER_CLASS (G_OBJECT_GET_CLASS (composite)); if (!worker_class->reset (GST_WORKER (composite))) { ERROR ("failed to reset composite"); } /* if (!worker_class->reset (GST_WORKER (composite->output))) { ERROR ("failed to reset composite output"); } */ /* g_object_set (composite->recorder, "port", composite->encode_sink_port, "mode", composite->mode, "width", composite->width, "height", composite->height, NULL); if (!worker_class->reset (GST_WORKER (composite->recorder))) { ERROR ("failed to reset composite recorder"); } */ }
static void gst_switch_server_end_case (GstCase *cas, GstSwitchServer *srv) { gint caseport = 0; GList *item; GST_SWITCH_SERVER_LOCK_CASES (srv); switch (cas->type) { default: srv->cases = g_list_remove (srv->cases, cas); INFO ("Removed %s (%p, %d) (%d cases left)", GST_WORKER (cas)->name, cas, G_OBJECT (cas)->ref_count, g_list_length (srv->cases)); caseport = cas->sink_port; g_object_unref (cas); break; case GST_CASE_INPUT_a: case GST_CASE_INPUT_v: srv->cases = g_list_remove (srv->cases, cas); INFO ("Removed %s %p (%d cases left)", GST_WORKER (cas)->name, cas, g_list_length (srv->cases)); caseport = cas->sink_port; g_object_unref (cas); for (item = srv->cases; item;) { GstCase *c = GST_CASE (item->data); if (c->sink_port == caseport) { gst_worker_stop (GST_WORKER (c)); item = g_list_next (item); /* srv->cases = g_list_remove (srv->cases, c); g_object_unref (G_OBJECT (c)); */ } else { item = g_list_next (item); } } break; } GST_SWITCH_SERVER_UNLOCK_CASES (srv); if (caseport) gst_switch_server_revoke_port (srv, caseport); }
/** * @brief * @param ui The GstSwitchUI instance. * @param port The compose port number. * @memberof GstSwitchUI */ static void gst_switch_ui_set_compose_port (GstSwitchUI * ui, gint port) { GstElement *overlay = NULL; GST_SWITCH_UI_LOCK_COMPOSE (ui); if (ui->compose) { gst_worker_stop (GST_WORKER (ui->compose)); g_object_unref (ui->compose); } ui->compose = gst_switch_ui_new_video_disp (ui, ui->compose_view, port); overlay = gst_worker_get_element (GST_WORKER (ui->compose), "overlay"); if (overlay) { g_signal_connect (overlay, "draw", G_CALLBACK (gst_switch_ui_compose_draw), ui); } GST_SWITCH_UI_UNLOCK_COMPOSE (ui); }
/** * gst_composite_prepare: * @return TRUE if the composite pipeline is well prepared. * * Prepare the composite pipeline. */ static gboolean gst_composite_prepare (GstComposite * composite) { g_return_val_if_fail (GST_IS_COMPOSITE (composite), FALSE); if (composite->scaler == NULL) { composite->scaler = GST_WORKER (g_object_new (GST_TYPE_WORKER, "name", "scale", NULL)); composite->scaler->pipeline_func_data = composite; composite->scaler->pipeline_func = (GstWorkerGetPipelineString) gst_composite_get_scaler_string; } else { GstWorkerClass *worker_class; worker_class = GST_WORKER_CLASS (G_OBJECT_GET_CLASS (composite->scaler)); if (!worker_class->reset (GST_WORKER (composite->scaler))) { ERROR ("failed to reset scaler"); } } return TRUE; }
static gboolean gst_switch_ptz_prepare (GstSwitchPTZ * ptz) { GstWorker *worker = GST_WORKER (ptz); GstElement *sink = gst_worker_get_element_unlocked (worker, "sink"); gulong handle = GDK_WINDOW_XID (gtk_widget_get_window (ptz->video_view)); g_return_val_if_fail (GST_IS_ELEMENT (sink), FALSE); gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (sink), handle); gst_object_unref (sink); return TRUE; }
/** * @brief * @param ui The GstSwitchUI instance. * @param worker * @memberof GstSwitchUI */ static void gst_switch_ui_end_audio_visual (GstWorker * worker, GstSwitchUI * ui) { GstAudioVisual *visual = GST_AUDIO_VISUAL (worker); INFO ("audio ended: %s, %d", worker->name, visual->port); if (visual->renewing) { g_object_unref (GST_WORKER (visual)); } else { gst_switch_ui_remove_preview (ui, worker, "audio-visual"); } }
/** * gst_switch_server_prepare_composite: * @return TRUE if the composite worker is prepared. * * Preparing the composite worker. */ static gboolean gst_switch_server_prepare_composite (GstSwitchServer * srv, GstCompositeMode mode) { gint port, encode; if (srv->composite) { return TRUE; } port = gst_switch_server_alloc_port (srv); encode = gst_switch_server_alloc_port (srv); INFO ("Compose sink to %d, %d", port, encode); g_assert (srv->composite == NULL); srv->composite = GST_COMPOSITE (g_object_new (GST_TYPE_COMPOSITE, "name", "composite", "port", port, "encode", encode, "mode", mode, NULL)); g_signal_connect (srv->composite, "start-worker", G_CALLBACK (gst_switch_server_worker_start), srv); g_signal_connect (srv->composite, "worker-null", G_CALLBACK (gst_switch_server_worker_null), srv); /* g_signal_connect (srv->composite, "start-output", G_CALLBACK (gst_switch_server_start_output), srv); g_signal_connect (srv->composite, "start-recorder", G_CALLBACK (gst_switch_server_start_recorder), srv); */ g_signal_connect (srv->composite, "end-transition", G_CALLBACK (gst_switch_server_end_transition), srv); GST_SWITCH_SERVER_LOCK_PIP (srv); srv->pip_x = srv->composite->b_x; srv->pip_y = srv->composite->b_y; srv->pip_w = srv->composite->b_width; srv->pip_h = srv->composite->b_height; GST_SWITCH_SERVER_UNLOCK_PIP (srv); if (!gst_worker_start (GST_WORKER (srv->composite))) goto error_start_composite; return TRUE; error_start_composite: { g_object_unref (srv->composite); srv->composite = NULL; return FALSE; } }
/** * gst_composite_retry_adjustment: * @return Always FALSE to allow glib to cleanup the timeout source * * This is invoked when the pipeline is reporting errors and requiring PIP * adjustment. */ static gboolean gst_composite_retry_adjustment (GstComposite * composite) { g_return_val_if_fail (GST_IS_COMPOSITE (composite), FALSE); if (composite->adjusting) { GST_COMPOSITE_LOCK_ADJUSTMENT (composite); if (composite->adjusting) { GstWorkerClass *worker_class; WARN ("adjusting PIP error, retry.."); worker_class = GST_WORKER_CLASS (G_OBJECT_GET_CLASS (composite)); if (!worker_class->reset (GST_WORKER (composite))) { ERROR ("failed to reset composite"); } gst_worker_start (GST_WORKER (composite)); } GST_COMPOSITE_UNLOCK_ADJUSTMENT (composite); } return FALSE; }
/** * @brief Initialize the GstRecorder instance. * @param rec The GstRecorder instance. * @memberof GstRecorder */ static void gst_recorder_init (GstRecorder * rec) { rec->sink_port = 0; rec->mode = 0; rec->width = 0; rec->height = 0; // Recording pipeline needs clean shut-down // via EOS to close out each recording GST_WORKER (rec)->send_eos_on_stop = TRUE; //INFO ("init %p", rec); }
/** * @brief * @param ui The GstSwitchUI instance. * @param frame * @param visual * @memberof GstSwitchUI */ static GstAudioVisual * gst_switch_ui_renew_audio_visual (GstSwitchUI * ui, GtkWidget * frame, GstAudioVisual * visual) { gulong handle = visual->handle; gint port = visual->port; visual->renewing = TRUE; gst_worker_stop (GST_WORKER (visual)); visual = gst_switch_ui_new_audio_visual_unsafe (ui, NULL, handle, port); g_object_set_data (G_OBJECT (frame), "audio-visual", visual); return visual; }
/** * @brief * @param disp The GstVideoDisp instance. * @memberof GstVideoDisp */ static gboolean gst_video_disp_prepare (GstVideoDisp * disp) { GstWorker *worker = GST_WORKER (disp); GstElement *sink = gst_worker_get_element_unlocked (worker, "sink"); g_return_val_if_fail (GST_IS_ELEMENT (sink), FALSE); gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (sink), disp->handle); gst_object_unref (sink); //INFO ("prepared display video on %ld", disp->handle); return TRUE; }
/** * gst_composite_start_transition: * * Start the new transtition request, this will set the %transition flag into * TRUE. */ static void gst_composite_start_transition (GstComposite * composite) { g_return_if_fail (GST_IS_COMPOSITE (composite)); GST_COMPOSITE_LOCK_TRANSITION (composite); if (gst_composite_ready_for_transition (composite)) { composite->transition = gst_worker_stop (GST_WORKER (composite)); /* INFO ("transtion ok=%d, %d, %dx%d", composite->transition, composite->mode, composite->width, composite->height); */ } GST_COMPOSITE_UNLOCK_TRANSITION (composite); }
/** * @brief * @param ui The GstSwitchUI instance. * @param view * @param port * @memberof GstSwitchUI */ static GstVideoDisp * gst_switch_ui_new_video_disp (GstSwitchUI * ui, GtkWidget * view, gint port) { gchar *name = g_strdup_printf ("video-%d", port); GdkWindow *xview = gtk_widget_get_window (view); GstVideoDisp *disp = GST_VIDEO_DISP (g_object_new (GST_TYPE_VIDEO_DISP, "name", name, "port", port, "handle", (gulong) GDK_WINDOW_XID (xview), NULL)); g_free (name); g_object_set_data (G_OBJECT (view), "video-display", disp); if (!gst_worker_start (GST_WORKER (disp))) ERROR ("failed to start video display"); return disp; }
/** * gst_composite_retry_transition: * @return Always FALSE to allow glib to cleanup the timeout source * * This is invoked when the pipeline's getting errors to retry the transition * request. */ static gboolean gst_composite_retry_transition (GstComposite * composite) { g_return_val_if_fail (GST_IS_COMPOSITE (composite), FALSE); if (composite->transition) { GST_COMPOSITE_LOCK_TRANSITION (composite); if (composite->transition) { WARN ("new mode %d, %dx%d (error transition)", composite->mode, composite->width, composite->height); gst_composite_apply_parameters (composite); gst_worker_start (GST_WORKER (composite)); } GST_COMPOSITE_UNLOCK_TRANSITION (composite); } return FALSE; }
/** * @param rec The GstRecorder instance. * @memberof GstRecorder * @return TRUE indicating the recorder is prepared, FALSE otherwise. * * Invoked when the GstWorker is preparing the pipeline. */ static gboolean gst_recorder_prepare (GstRecorder * rec) { GstElement *tcp_sink = NULL; g_return_val_if_fail (GST_IS_RECORDER (rec), FALSE); tcp_sink = gst_worker_get_element_unlocked (GST_WORKER (rec), "tcp_sink"); g_return_val_if_fail (GST_IS_ELEMENT (tcp_sink), FALSE); g_signal_connect (tcp_sink, "client-added", G_CALLBACK (gst_recorder_client_socket_added), rec); g_signal_connect (tcp_sink, "client-socket-removed", G_CALLBACK (gst_recorder_client_socket_removed), rec); gst_object_unref (tcp_sink); return TRUE; }
/** * gst_switch_server_create_output: * @return TRUE if the composite output worker is created. * * Create the composite output worker. */ static gboolean gst_switch_server_create_output (GstSwitchServer * srv) { if (srv->output) { return TRUE; } srv->output = GST_WORKER (g_object_new (GST_TYPE_WORKER, "name", "output", NULL)); srv->output->pipeline_func_data = srv; srv->output->pipeline_func = (GstWorkerGetPipelineString) gst_switch_server_get_output_string; g_signal_connect (srv->output, "prepare-worker", G_CALLBACK (gst_switch_server_prepare_output), srv); g_signal_connect (srv->output, "start-worker", G_CALLBACK (gst_switch_server_start_output), srv); gst_worker_start (srv->output); return TRUE; }
/** * @brief * @param ui The GstSwitchUI instance. * @param view * @param handle * @param port * @memberof GstSwitchUI */ static GstAudioVisual * gst_switch_ui_new_audio_visual_unsafe (GstSwitchUI * ui, GtkWidget * view, gulong handle, gint port) { gchar *name = g_strdup_printf ("visual-%d", port); GstAudioVisual *visual; if (view && handle == 0) { GdkWindow *xview = gtk_widget_get_window (view); handle = GDK_WINDOW_XID (xview); } visual = GST_AUDIO_VISUAL (g_object_new (GST_TYPE_AUDIO_VISUAL, "name", name, "port", port, "handle", handle, "active", (ui->audio_port == port), NULL)); g_free (name); if (!gst_worker_start (GST_WORKER (visual))) ERROR ("failed to start audio visual"); return visual; }
/** * gst_switch_server_create_recorder: * @return TRUE if the recorder is created successfully. * * Creating the recorder. */ static gboolean gst_switch_server_create_recorder (GstSwitchServer * srv) { if (srv->recorder) { return TRUE; } GST_SWITCH_SERVER_LOCK_RECORDER (srv); srv->recorder = GST_RECORDER (g_object_new (GST_TYPE_RECORDER, "name", "recorder", "port", srv->composite->encode_sink_port, "mode", srv->composite->mode, "width", srv->composite->width, "height", srv->composite->height, NULL)); g_signal_connect (srv->recorder, "start-worker", G_CALLBACK (gst_switch_server_start_recorder), srv); gst_worker_start (GST_WORKER (srv->recorder)); GST_SWITCH_SERVER_UNLOCK_RECORDER (srv); return TRUE; }
/** * @brief * @param ui The GstSwitchUI instance. * @param worker * @param name * @memberof GstSwitchUI */ static void gst_switch_ui_remove_preview (GstSwitchUI * ui, GstWorker * worker, const gchar * name) { GList *v = NULL; GST_SWITCH_UI_LOCK_SELECT (ui); v = gtk_container_get_children (GTK_CONTAINER (ui->preview_box)); for (; v; v = g_list_next (v)) { GtkWidget *frame = GTK_WIDGET (v->data); gpointer data = g_object_get_data (G_OBJECT (frame), name); if (data && GST_IS_WORKER (data) && GST_WORKER (data) == worker) { if (ui->selected == frame) { GList *nxt = g_list_next (v); if (nxt == NULL) nxt = g_list_previous (v); ui->selected = nxt ? GTK_WIDGET (nxt->data) : NULL; } gtk_widget_destroy (frame); g_object_unref (worker); } } GST_SWITCH_UI_UNLOCK_SELECT (ui); }
static void gst_switch_ptz_run (GstSwitchPTZ * ptz) { if (ptz->controller == NULL) { #if 0 GtkWidget *d = gtk_message_dialog_new (NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "You don't specify the correct protocol (check the -p option)!"); gtk_dialog_run (GTK_DIALOG (d)); gtk_widget_destroy (d); #endif g_print ("You don't specify the correct protocol (check the -p option)!\n"); return; } if (ptz->window) { gtk_widget_show_all (ptz->window); gst_worker_start (GST_WORKER (ptz)); gtk_main (); } }
/** * gst_composite_adjust_pip: * @param composite The GstComposite instance * @param x the X position of the PIP * @param y the Y position of the PIP * @param w the width of the PIP * @param h the height of the PIP * @return PIP has been changed succefully * * Change the PIP position and size. */ gboolean gst_composite_adjust_pip (GstComposite * composite, gint x, gint y, gint w, gint h) { gboolean result = FALSE; GstIterator *iter = NULL; GValue value = { 0 }; GstElement *element = NULL; gboolean done = FALSE; g_return_val_if_fail (GST_IS_COMPOSITE (composite), FALSE); GST_COMPOSITE_LOCK (composite); if (composite->adjusting) { WARN ("last PIP adjustment request is progressing"); goto end; } composite->b_x = x; composite->b_y = y; if (composite->b_width != w || composite->b_height != h) { composite->b_width = w; composite->b_height = h; composite->adjusting = TRUE; gst_worker_stop (GST_WORKER (composite)); result = TRUE; goto end; } element = gst_worker_get_element (GST_WORKER (composite), "mix"); iter = gst_element_iterate_sink_pads (element); while (iter && !done) { switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: { GstPad *pad = g_value_get_object (&value); if (g_strcmp0 (gst_pad_get_name (pad), "sink_1") == 0) { g_object_set (pad, "xpos", composite->b_x, "ypos", composite->b_y, NULL); done = TRUE; result = TRUE; } g_value_reset (&value); } break; case GST_ITERATOR_RESYNC: gst_iterator_resync (iter); break; case GST_ITERATOR_DONE: done = TRUE; break; default: /* iterator returned _ERROR or premature end with _OK, * mark an error and exit */ done = TRUE; result = FALSE; break; } } if (G_IS_VALUE (&value)) g_value_unset (&value); if (iter) gst_iterator_free (iter); composite->adjusting = FALSE; /* if (!result) { WARN ("failed to adjust PIP: %d, %d, %d, %d", x, y, w, h); } */ end: GST_COMPOSITE_UNLOCK (composite); return result; }
gboolean gst_switch_server_switch (GstSwitchServer * srv, gint channel, gint port) { GList *item; gboolean result = FALSE; GstCase *compose_case, *candidate_case; GstCase *work1, *work2; GCallback callback = G_CALLBACK (gst_switch_server_end_case); gchar *name; compose_case = NULL; candidate_case = NULL; GST_SWITCH_SERVER_LOCK_CASES (srv); for (item = srv->cases; item; item = g_list_next (item)) { GstCase *cas = GST_CASE (item->data); switch (channel) { case 'A': if (cas->type == GST_CASE_COMPOSITE_A) goto get_target_stream; break; case 'B': if (cas->type == GST_CASE_COMPOSITE_B) goto get_target_stream; break; case 'a': if (cas->type == GST_CASE_COMPOSITE_a) goto get_target_stream; break; default: WARN ("unknown channel %c", (gchar) channel); break; get_target_stream: if (compose_case == NULL) { compose_case = cas; } } switch (cas->type) { case GST_CASE_COMPOSITE_A: case GST_CASE_COMPOSITE_B: case GST_CASE_COMPOSITE_a: case GST_CASE_PREVIEW: if (cas->sink_port == port) { candidate_case = cas; } default: break; } } if (!candidate_case) { ERROR ("no stream for port %d (candidate)", port); goto end; } if (!compose_case) { ERROR ("no stream for port %d (compose)", port); goto end; } if (candidate_case == compose_case) { ERROR ("stream on %d already at %c", port, (gchar) channel); goto end; } INFO ("switching: %s (%d), %s (%d)", GST_WORKER (compose_case)->name, compose_case->type, GST_WORKER (candidate_case)->name, candidate_case->type); if (candidate_case->serve_type != compose_case->serve_type) { ERROR ("stream type not matched"); goto end; } name = g_strdup (GST_WORKER (compose_case)->name); work1 = GST_CASE (g_object_new (GST_TYPE_CASE, "name", name, "type", compose_case->type, "serve", compose_case->serve_type, "port", candidate_case->sink_port, "input", candidate_case->input, "branch", candidate_case->branch, NULL)); g_free (name); name = g_strdup (GST_WORKER (candidate_case)->name); work2 = GST_CASE (g_object_new (GST_TYPE_CASE, "name", name, "type", candidate_case->type, "serve", candidate_case->serve_type, "port", compose_case->sink_port, "input", compose_case->input, "branch", compose_case->branch, NULL)); g_free (name); if (compose_case->serve_type == GST_SERVE_VIDEO_STREAM) { g_object_set (work1, "awidth", compose_case->a_width, "aheight", compose_case->a_height, "bwidth", compose_case->b_width, "bheight", compose_case->b_height, NULL); g_object_set (work2, "awidth", candidate_case->a_width, "aheight", candidate_case->a_height, "bwidth", candidate_case->b_width, "bheight", candidate_case->b_height, NULL); } else { g_signal_connect (G_OBJECT (work1), "start-worker", G_CALLBACK (gst_switch_server_start_audio), srv); } compose_case->switching = TRUE; candidate_case->switching = TRUE; gst_worker_stop (GST_WORKER (compose_case)); gst_worker_stop (GST_WORKER (candidate_case)); g_signal_connect (work1, "end-worker", callback, srv); g_signal_connect (work2, "end-worker", callback, srv); if (!gst_worker_start (GST_WORKER (work1))) goto error_start_work; if (!gst_worker_start (GST_WORKER (work2))) goto error_start_work; srv->cases = g_list_append (srv->cases, work1); srv->cases = g_list_append (srv->cases, work2); result = TRUE; INFO ("switched: %s <-> %s", GST_WORKER (work1)->name, GST_WORKER (work2)->name); end: GST_SWITCH_SERVER_UNLOCK_CASES (srv); return result; error_start_work: { ERROR ("failed to start works"); g_object_unref (work1); g_object_unref (work2); GST_SWITCH_SERVER_UNLOCK_CASES (srv); return result; } }
static void gst_switch_server_serve (GstSwitchServer *srv, GSocket *client, GstSwitchServeStreamType serve_type) { GSocketInputStreamX *stream = G_SOCKET_INPUT_STREAM (g_object_new ( G_TYPE_SOCKET_INPUT_STREAM, "socket", client, NULL)); GstCaseType type = GST_CASE_UNKNOWN; GstCaseType inputtype = GST_CASE_UNKNOWN; GstCaseType branchtype = GST_CASE_UNKNOWN; gint num_cases = g_list_length (srv->cases); GstCase *input = NULL, *branch = NULL, *workcase = NULL; gchar *name; gint port = 0; GCallback start_callback = G_CALLBACK (gst_switch_server_start_case); GCallback end_callback = G_CALLBACK (gst_switch_server_end_case); GST_SWITCH_SERVER_LOCK_SERVE (srv); GST_SWITCH_SERVER_LOCK_CASES (srv); switch (serve_type) { case GST_SERVE_AUDIO_STREAM: inputtype = GST_CASE_INPUT_a; break; case GST_SERVE_VIDEO_STREAM: inputtype = GST_CASE_INPUT_v; break; default: goto error_unknown_serve_type; } type = gst_switch_server_suggest_case_type (srv, serve_type); switch (type) { case GST_CASE_COMPOSITE_A: branchtype = GST_CASE_BRANCH_A; break; case GST_CASE_COMPOSITE_B: branchtype = GST_CASE_BRANCH_B; break; case GST_CASE_COMPOSITE_a: branchtype = GST_CASE_BRANCH_a; break; case GST_CASE_PREVIEW: branchtype = GST_CASE_BRANCH_p; break; default: goto error_unknown_case_type; } port = gst_switch_server_alloc_port (srv); //INFO ("case-type: %d, %d, %d", type, branchtype, port); name = g_strdup_printf ("input_%d", port); input = GST_CASE (g_object_new (GST_TYPE_CASE, "name", name, "type", inputtype, "port", port, "serve", serve_type, "stream", stream, NULL)); g_object_unref (stream); g_object_unref (client); g_free (name); name = g_strdup_printf ("branch_%d", port); branch = GST_CASE (g_object_new (GST_TYPE_CASE, "name", name, "type", branchtype, "port", port, "serve", serve_type, NULL)); g_free (name); name = g_strdup_printf ("case-%d", num_cases); workcase = GST_CASE (g_object_new (GST_TYPE_CASE, "name", name, "type", type, "port", port, "serve", serve_type, "input", input, "branch", branch, NULL)); g_free (name); srv->cases = g_list_append (srv->cases, input); srv->cases = g_list_append (srv->cases, branch); srv->cases = g_list_append (srv->cases, workcase); GST_SWITCH_SERVER_UNLOCK_CASES (srv); if (serve_type == GST_SERVE_VIDEO_STREAM) { g_object_set (input, "awidth", srv->composite->a_width, "aheight", srv->composite->a_height, "bwidth", srv->composite->b_width, "bheight", srv->composite->b_height, NULL); g_object_set (branch, "awidth", srv->composite->a_width, "aheight", srv->composite->a_height, "bwidth", srv->composite->b_width, "bheight", srv->composite->b_height, NULL); g_object_set (workcase, "awidth", srv->composite->a_width, "aheight", srv->composite->a_height, "bwidth", srv->composite->b_width, "bheight", srv->composite->b_height, NULL); } g_signal_connect (branch, "start-worker", start_callback, srv); g_signal_connect (input, "end-worker", end_callback, srv); g_signal_connect (branch, "end-worker", end_callback, srv); g_signal_connect (workcase, "end-worker", end_callback, srv); if (!gst_worker_start (GST_WORKER (input))) goto error_start_branch; if (!gst_worker_start (GST_WORKER (branch))) goto error_start_branch; if (!gst_worker_start (GST_WORKER (workcase))) goto error_start_workcase; GST_SWITCH_SERVER_UNLOCK_SERVE (srv); return; /* Errors Handling */ error_unknown_serve_type: { ERROR ("unknown serve type %d", serve_type); g_object_unref (stream); g_object_unref (client); GST_SWITCH_SERVER_UNLOCK_CASES (srv); GST_SWITCH_SERVER_UNLOCK_SERVE (srv); return; } error_unknown_case_type: { ERROR ("unknown case type (serve type %d)", serve_type); g_object_unref (stream); g_object_unref (client); GST_SWITCH_SERVER_UNLOCK_CASES (srv); GST_SWITCH_SERVER_UNLOCK_SERVE (srv); return; } error_start_branch: error_start_workcase: { ERROR ("failed serving new client"); GST_SWITCH_SERVER_LOCK_CASES (srv); srv->cases = g_list_remove (srv->cases, branch); srv->cases = g_list_remove (srv->cases, workcase); GST_SWITCH_SERVER_UNLOCK_CASES (srv); g_object_unref (stream); g_object_unref (branch); g_object_unref (workcase); gst_switch_server_revoke_port (srv, port); GST_SWITCH_SERVER_UNLOCK_SERVE (srv); return; } }