aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAshok Sidipotu <ashok.sidipotu@collabora.com>2023-10-12 11:56:21 +0530
committerAshok Sidipotu <ashok.sidipotu@collabora.com>2023-10-25 16:31:38 +0530
commit4f2e6690a893ed41be6eb3c74d6cab82a5e12f39 (patch)
tree547106264f33714444db209d0c1b35d3e571f292
parentaf8a4ba93e3afe42bfc57b5ce4c207782ed3b2d4 (diff)
camera-gstreamer: Add fallback sink
Add a still image fallback sink when the intended camera's are not available. Still image indicates that the camera devices are not available. This should help towards the better user experience of the app. Bug-AGL: SPEC-4881 Change-Id: Id0e4689861fead763366eac4de506f298a0de5e2 Signed-off-by: Ashok Sidipotu <ashok.sidipotu@collabora.com>
-rw-r--r--app/CMakeLists.txt2
-rw-r--r--app/main.cpp117
-rw-r--r--app/still-image.jpgbin0 -> 1057603 bytes
3 files changed, 84 insertions, 35 deletions
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index fc71e8f..d7935f3 100644
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -117,3 +117,5 @@ target_link_libraries(${PROJECT_NAME}
install(TARGETS ${PROJECT_NAME} DESTINATION bin)
include(GNUInstallDirs)
install(FILES ${PROJECT_NAME}.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
+install(FILES still-image.jpg DESTINATION ${CMAKE_INSTALL_DATADIR}/applications/data)
+add_definitions(-DAPP_DATA_PATH=${CMAKE_INSTALL_FULL_DATADIR}/applications/data)
diff --git a/app/main.cpp b/app/main.cpp
index 2068143..2d286ba 100644
--- a/app/main.cpp
+++ b/app/main.cpp
@@ -97,6 +97,8 @@ struct receiver_data {
};
static int running = 1;
+static bool gst_pipeline_failed = FALSE;
+static bool fallback_gst_pipeline_tried = FALSE;
static void
redraw(void *data, struct wl_callback *callback, uint32_t time);
@@ -491,6 +493,19 @@ bus_sync_handler(GstBus *bus, GstMessage *message, gpointer user_data)
goto drop;
}
+ else if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR) {
+ GError* err = NULL;
+ gchar* dbg_info = NULL;
+
+ gst_message_parse_error(message, &err, &dbg_info);
+ g_printerr("ERROR from element %s: %s code %d\n",
+ GST_OBJECT_NAME(message->src), err->message, err->code);
+ g_printerr("Debugging info: %s\n", (dbg_info) ? dbg_info : "none");
+ gst_pipeline_failed = TRUE;
+ g_error_free(err);
+ g_free(dbg_info);
+ goto drop;
+ }
return GST_BUS_PASS;
@@ -700,13 +715,13 @@ destroy_display(struct display *display)
free(display);
}
-int main(int argc, char *argv[])
+// stringify the un-quoted string to quoted C string
+#define xstr(a) str(a)
+#define str(a) #a
+
+GstElement* create_pipeline(int* argc, char** argv[])
{
- int ret = 0;
- struct sigaction sa;
- struct receiver_data receiver_data = {};
- struct display *display;
- struct window *window;
+ GError *error = NULL;
const char *camera_device = NULL;
const char *width_str = NULL;
const char *height_str = NULL;
@@ -718,19 +733,6 @@ int main(int argc, char *argv[])
bool v4l2 = false;
char pipeline_str[1024];
- GError *error = NULL;
- const char *app_id = "camera-gstreamer";
-
- sa.sa_sigaction = signal_int;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESETHAND | SA_SIGINFO;
- sigaction(SIGINT, &sa, NULL);
-
- int gargc = 2;
- char **gargv = static_cast<char **>(calloc(2, sizeof(char *)));
-
- gargv[0] = strdup(argv[0]);
- gargv[1] = strdup("--gst-debug-level=2");
camera_device = getenv("DEFAULT_V4L2_DEVICE");
if (!camera_device)
@@ -758,24 +760,57 @@ int main(int argc, char *argv[])
if (v4l2)
snprintf(pipeline_str, sizeof(pipeline_str), "v4l2src device=%s ! video/x-raw,width=%d,height=%d ! waylandsink",
camera_device, width, height);
- else
- snprintf(pipeline_str, sizeof(pipeline_str), "pipewiresrc ! video/x-raw,width=%d,height=%d ! waylandsink",
- width, height);
-
- gst_init(&gargc, &gargv);
-
- setbuf(stdout, NULL);
+ else if (gst_pipeline_failed == TRUE) {
+ snprintf(pipeline_str, sizeof(pipeline_str), "filesrc location=%s/still-image.jpg ! decodebin ! videoconvert ! imagefreeze ! waylandsink fullscreen=true",
+ xstr(APP_DATA_PATH), width, height);
+ fallback_gst_pipeline_tried = TRUE;
+ }
+ else {
+ snprintf(pipeline_str, sizeof(pipeline_str), "pipewiresrc ! video/x-raw,width=%d,height=%d ! waylandsink", width,
+ height);
+ }
fprintf(stdout, "Using pipeline: %s\n", pipeline_str);
GstElement *pipeline = gst_parse_launch(pipeline_str, &error);
+
if (error || !pipeline) {
fprintf(stderr, "gstreamer pipeline construction failed!\n");
- free(gargv);
- return EXIT_FAILURE;
+ free(argv);
+ return NULL;
}
- receiver_data.pipeline = pipeline;
+ return pipeline;
+}
+
+int main(int argc, char* argv[])
+{
+ int ret = 0;
+ struct sigaction sa;
+ struct receiver_data receiver_data = {};
+ struct display* display;
+ struct window* window;
+ const char* app_id = "camera-gstreamer";
+
+ sa.sa_sigaction = signal_int;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESETHAND | SA_SIGINFO;
+ sigaction(SIGINT, &sa, NULL);
+
+ int gargc = 2;
+ char** gargv = static_cast<char**>(calloc(2, sizeof(char*)));
+
+ gargv[0] = strdup(argv[0]);
+ gargv[1] = strdup("--gst-debug-level=2");
+
+ setbuf(stdout, NULL);
+
+ gst_init(&gargc, &gargv);
+
+ receiver_data.pipeline = create_pipeline(&gargc, &gargv);
+
+ if (!receiver_data.pipeline)
+ return EXIT_FAILURE;
display = create_display(argc, argv);
if (!display)
@@ -809,22 +844,34 @@ int main(int argc, char *argv[])
redraw(window, NULL, 0);
}
- GstBus *bus = gst_element_get_bus(pipeline);
+ GstBus *bus = gst_element_get_bus(receiver_data.pipeline);
gst_bus_add_signal_watch(bus);
g_signal_connect(bus, "message::error", G_CALLBACK(error_cb), &receiver_data);
gst_bus_set_sync_handler(bus, bus_sync_handler, &receiver_data, NULL);
gst_object_unref(bus);
- gst_element_set_state(pipeline, GST_STATE_PLAYING);
+ gst_element_set_state(receiver_data.pipeline, GST_STATE_PLAYING);
fprintf(stdout, "gstreamer pipeline running\n");
// run the application
- while (running && ret != -1)
+ while (running && ret != -1) {
ret = wl_display_dispatch(display->wl_display);
-
- gst_element_set_state(pipeline, GST_STATE_NULL);
- gst_object_unref(pipeline);
+ if (gst_pipeline_failed && fallback_gst_pipeline_tried == FALSE) {
+ gst_element_set_state(receiver_data.pipeline, GST_STATE_NULL);
+ gst_object_unref(receiver_data.pipeline);
+ /* retry with fallback pipeline */
+ receiver_data.pipeline = create_pipeline(&gargc, &gargv);
+ GstBus *bus = gst_element_get_bus(receiver_data.pipeline);
+ gst_bus_add_signal_watch(bus);
+ g_signal_connect(bus, "message::error", G_CALLBACK(error_cb), &receiver_data);
+ gst_bus_set_sync_handler(bus, bus_sync_handler, &receiver_data, NULL);
+ gst_object_unref(bus);
+ gst_element_set_state(receiver_data.pipeline, GST_STATE_PLAYING);
+ }
+ }
+ gst_element_set_state(receiver_data.pipeline, GST_STATE_NULL);
+ gst_object_unref(receiver_data.pipeline);
destroy_window(window);
destroy_display(display);
diff --git a/app/still-image.jpg b/app/still-image.jpg
new file mode 100644
index 0000000..994778c
--- /dev/null
+++ b/app/still-image.jpg
Binary files differ