/** * 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_start: * * This is invokved when the composite pipeline started. */ static void gst_composite_start (GstComposite * composite) { g_return_if_fail (GST_IS_COMPOSITE (composite)); gst_worker_start (composite->scaler); }
/** * 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; } }
/** * @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; }
/** * @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; }
/** * 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; }
/** * 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; }
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 (); } }
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; } }