/** * 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; }
/** * gst_composite_end: * * This is invoked when the composite pipeline is ended. */ static void gst_composite_end (GstComposite * composite) { g_return_if_fail (GST_IS_COMPOSITE (composite)); gst_worker_stop (composite->scaler); }
/** * @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; }
/** * 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); }
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); }
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; } }
/** * 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; }