diff options
-rw-r--r-- | gst/camerabin/camerabinimage.c | 326 | ||||
-rw-r--r-- | gst/camerabin/camerabinimage.h | 8 | ||||
-rw-r--r-- | gst/camerabin/gstcamerabin.c | 4 |
3 files changed, 258 insertions, 80 deletions
diff --git a/gst/camerabin/camerabinimage.c b/gst/camerabin/camerabinimage.c index 1efe1f9bd..8b94d7d22 100644 --- a/gst/camerabin/camerabinimage.c +++ b/gst/camerabin/camerabinimage.c @@ -83,6 +83,12 @@ static void gst_camerabin_image_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_camerabin_image_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); +static gboolean metadata_write_probe (GstPad * pad, GstBuffer * buffer, + gpointer u_data); +static gboolean prepare_element (GList ** result, + const gchar * default_element_name, GstElement * app_elem, + GstElement ** res_elem); + GST_BOILERPLATE (GstCameraBinImage, gst_camerabin_image, GstBin, GST_TYPE_BIN); @@ -141,6 +147,7 @@ gst_camerabin_image_init (GstCameraBinImage * img, img->filename = g_string_new (""); img->post = NULL; + img->csp = NULL; img->enc = NULL; img->app_enc = NULL; img->meta_mux = NULL; @@ -150,7 +157,6 @@ gst_camerabin_image_init (GstCameraBinImage * img, img->sinkpad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK); gst_element_add_pad (GST_ELEMENT (img), img->sinkpad); - img->elements_created = FALSE; img->flags = DEFAULT_FLAGS; } @@ -162,12 +168,45 @@ gst_camerabin_image_dispose (GstCameraBinImage * img) g_string_free (img->filename, TRUE); img->filename = NULL; + if (img->elements) { + g_list_free (img->elements); + img->elements = NULL; + } + + if (img->sink) { + GST_LOG_OBJECT (img, "disposing %s with refcount %d", + GST_ELEMENT_NAME (img->sink), GST_OBJECT_REFCOUNT_VALUE (img->sink)); + gst_object_unref (img->sink); + img->sink = NULL; + } + + if (img->meta_mux) { + GST_LOG_OBJECT (img, "disposing %s with refcount %d", + GST_ELEMENT_NAME (img->meta_mux), + GST_OBJECT_REFCOUNT_VALUE (img->meta_mux)); + gst_object_unref (img->meta_mux); + img->meta_mux = NULL; + } + + if (img->enc) { + GST_LOG_OBJECT (img, "disposing %s with refcount %d", + GST_ELEMENT_NAME (img->enc), GST_OBJECT_REFCOUNT_VALUE (img->enc)); + gst_object_unref (img->enc); + img->enc = NULL; + } + + if (img->app_enc) { + GST_LOG_OBJECT (img, "disposing %s with refcount %d", + GST_ELEMENT_NAME (img->app_enc), + GST_OBJECT_REFCOUNT_VALUE (img->app_enc)); gst_object_unref (img->app_enc); img->app_enc = NULL; } if (img->post) { + GST_LOG_OBJECT (img, "disposing %s with refcount %d", + GST_ELEMENT_NAME (img->post), GST_OBJECT_REFCOUNT_VALUE (img->post)); gst_object_unref (img->post); img->post = NULL; } @@ -308,6 +347,85 @@ gst_camerabin_image_get_property (GObject * object, guint prop_id, } /* + * gst_camerabin_image_prepare_elements: + * @imagebin: a pointer to #GstCameraBinImage object + * + * This function creates an ordered list of elements configured for imagebin + * pipeline and creates the elements if necessary. It also stores pointers + * to created elements for re-using them. + * + * Image bin: + * img->sinkpad ! [ post process !] [ csp !] encoder ! metadata ! filesink + * + * Returns: %FALSE if there was error creating element, %TRUE otherwise + */ +gboolean +gst_camerabin_image_prepare_elements (GstCameraBinImage * imagebin) +{ + gboolean ret = FALSE; + GstPad *sinkpad = NULL; + + g_return_val_if_fail (imagebin != NULL, FALSE); + + GST_DEBUG_OBJECT (imagebin, "preparing image capture elements"); + + if (imagebin->elements != NULL) { + g_list_free (imagebin->elements); + imagebin->elements = NULL; + } + + /* Create file sink element */ + if (!prepare_element (&imagebin->elements, DEFAULT_SINK, NULL, + &imagebin->sink)) { + goto done; + } else { + g_object_set (G_OBJECT (imagebin->sink), "location", + imagebin->filename->str, "async", FALSE, "buffer-mode", 2, + /* non buffered io */ NULL); + } + + /* Create metadata muxer element */ + if (!prepare_element (&imagebin->elements, DEFAULT_META_MUX, NULL, + &imagebin->meta_mux)) { + goto done; + } else if (!imagebin->metadata_probe_id) { + /* Add probe for default XMP metadata writing */ + sinkpad = gst_element_get_static_pad (imagebin->meta_mux, "sink"); + imagebin->metadata_probe_id = + gst_pad_add_buffer_probe (sinkpad, G_CALLBACK (metadata_write_probe), + imagebin); + gst_object_unref (sinkpad); + } + + /* Create image encoder element */ + if (!prepare_element (&imagebin->elements, DEFAULT_ENC, imagebin->app_enc, + &imagebin->enc)) { + goto done; + } + + /* Create optional colorspace conversion element */ + if (imagebin->flags & GST_CAMERABIN_FLAG_IMAGE_COLOR_CONVERSION) { + if (!prepare_element (&imagebin->elements, "ffmpegcolorspace", NULL, + &imagebin->csp)) { + goto done; + } + } + + /* Add optional image post processing element */ + if (!prepare_element (&imagebin->elements, NULL, imagebin->post, + &imagebin->post)) { + goto done; + } + + ret = TRUE; + +done: + GST_DEBUG_OBJECT (imagebin, "preparing finished %s", ret ? "OK" : "NOK"); + return ret; +} + + +/* * static helper functions implementation */ @@ -377,113 +495,169 @@ done: return TRUE; } +/* + * prepare_element: + * @result: result list address + * @default_element_name: name of default element to be created + * @app_elem: pointer to application set element + * @res_elem: pointer to current element to be replaced if needed + * + * This function chooses given image capture element or creates a new one and + * and prepends it to @result list. + * + * Returns: %FALSE if there was error creating new element, %TRUE otherwise + */ +static gboolean +prepare_element (GList ** result, const gchar * default_element_name, + GstElement * app_elem, GstElement ** res_elem) +{ + GstElement *elem = NULL; + gboolean ret = TRUE; + + if (app_elem) { + /* Prefer application set element */ + elem = app_elem; + } else if (*res_elem) { + /* Use existing element if any */ + elem = *res_elem; + } else if (default_element_name) { + /* Create new element */ + if (!(elem = gst_element_factory_make (default_element_name, NULL))) { + GST_WARNING ("creating %s failed", default_element_name); + ret = FALSE; + } + } + + if (*res_elem != elem) { + /* Keep reference and store pointer to chosen element, which can be re-used + until imagebin is disposed or new image capture element is chosen. */ + gst_object_replace ((GstObject **) res_elem, (GstObject *) elem); + } + if (elem) { + *result = g_list_prepend (*result, elem); + } + + return ret; +} /* - * gst_camerabin_image_create_elements: + * gst_camerabin_image_link_first_element: * @img: a pointer to #GstCameraBinImage object + * @elem: first element to be linked on imagebin * - * This function creates needed #GstElements and resources to capture images. - * Use gst_camerabin_image_destroy_elements to release these resources. - * - * Image bin: - * img->sinkpad ! [ post process !] csp ! encoder ! metadata ! filesink + * Adds given element to imagebin and links it to imagebin's ghost sink pad. * - * Returns: %TRUE if succeeded or FALSE if failed + * Returns: %TRUE if adding and linking succeeded, %FALSE otherwise */ static gboolean -gst_camerabin_image_create_elements (GstCameraBinImage * img) +gst_camerabin_image_link_first_element (GstCameraBinImage * imagebin, + GstElement * elem) { - GstPad *sinkpad = NULL, *img_sinkpad = NULL; + GstPad *first_sinkpad = NULL; gboolean ret = FALSE; - GstBin *imgbin = NULL; - GstElement *csp = NULL; - g_return_val_if_fail (img != NULL, FALSE); + g_return_val_if_fail (imagebin != NULL, FALSE); + /* Link given element to imagebin ghost sink pad */ + if (gst_bin_add (GST_BIN (imagebin), elem)) { + first_sinkpad = gst_element_get_static_pad (elem, "sink"); + if (first_sinkpad) { + if (gst_ghost_pad_set_target (GST_GHOST_PAD (imagebin->sinkpad), + first_sinkpad)) { + ret = TRUE; + } else { + GST_WARNING ("linking first element failed"); + } + gst_object_unref (first_sinkpad); + } else { + GST_WARNING ("no sink pad in first element"); + } + } else { + GST_WARNING ("adding element failed"); + } + return ret; +} - GST_DEBUG ("creating image capture elements"); +/* + * gst_camerabin_image_link_elements: + * @imagebin: a pointer to #GstCameraBinImage object + * + * Link elements configured to imagebin elements list. + * + * Returns %TRUE if linking succeeded, %FALSE otherwise. + */ +static gboolean +gst_camerabin_image_link_elements (GstCameraBinImage * imagebin) +{ + GList *prev = NULL; + GList *next = NULL; + gboolean ret = FALSE; - imgbin = GST_BIN (img); + GST_DEBUG_OBJECT (imagebin, "linking image elements"); - if (img->elements_created) { - GST_WARNING ("elements already created"); - ret = TRUE; + if (!imagebin->elements) { + GST_WARNING ("no elements to link"); goto done; - } else { - img->elements_created = TRUE; } - /* Create image pre/post-processing element if any */ - if (img->post) { - if (!gst_camerabin_add_element (imgbin, img->post)) { + /* Link the elements in list */ + prev = imagebin->elements; + next = g_list_next (imagebin->elements); + for (; next != NULL; next = g_list_next (next)) { + /* Link first element in list to imagebin ghost sink pad */ + if (prev == imagebin->elements + && !gst_camerabin_image_link_first_element (imagebin, + GST_ELEMENT (prev->data))) { goto done; } - img_sinkpad = gst_element_get_static_pad (img->post, "sink"); - } - - if (img->flags & GST_CAMERABIN_FLAG_IMAGE_COLOR_CONVERSION) { - /* Add colorspace converter */ - if (!(csp = - gst_camerabin_create_and_add_element (imgbin, - "ffmpegcolorspace"))) { + if (!gst_bin_add (GST_BIN (imagebin), GST_ELEMENT (next->data))) { + GST_WARNING_OBJECT (imagebin, "adding element failed"); goto done; } - if (!img_sinkpad) - img_sinkpad = gst_element_get_static_pad (csp, "sink"); - } - - if (img->app_enc) { - img->enc = img->app_enc; - if (!gst_camerabin_add_element (imgbin, img->enc)) { + GST_LOG_OBJECT (imagebin, "linking %s - %s", + GST_ELEMENT_NAME (GST_ELEMENT (prev->data)), + GST_ELEMENT_NAME (GST_ELEMENT (next->data))); + if (!gst_element_link (GST_ELEMENT (prev->data), GST_ELEMENT (next->data))) { + GST_WARNING_OBJECT (imagebin, "linking element failed"); goto done; } - } else if (!(img->enc = - gst_camerabin_create_and_add_element (imgbin, DEFAULT_ENC))) { - goto done; - } - /* Create metadata element */ - if (!(img->meta_mux = - gst_camerabin_create_and_add_element (imgbin, DEFAULT_META_MUX))) { - goto done; - } - /* Add probe for XMP metadata writing */ - sinkpad = gst_element_get_static_pad (img->meta_mux, "sink"); - gst_pad_add_buffer_probe (sinkpad, G_CALLBACK (metadata_write_probe), img); - gst_object_unref (sinkpad); - /* Set "Intel" exif byte-order if possible */ - if (g_object_class_find_property (G_OBJECT_GET_CLASS (img->meta_mux), - "exif-byte-order")) { - g_object_set (G_OBJECT (img->meta_mux), "exif-byte-order", 1, NULL); - } - - /* Add sink element for storing the image */ - if (!(img->sink = - gst_camerabin_create_and_add_element (imgbin, DEFAULT_SINK))) { - goto done; - } - g_object_set (G_OBJECT (img->sink), "location", img->filename->str, "async", FALSE, "buffer-mode", 2, /* non buffered io */ - NULL); - - /* Set up sink ghost pad for image bin */ - if (!img_sinkpad) { - img_sinkpad = gst_element_get_static_pad (img->enc, "sink"); + prev = next; } - gst_ghost_pad_set_target (GST_GHOST_PAD (img->sinkpad), img_sinkpad); ret = TRUE; done: - if (img_sinkpad) { - gst_object_unref (img_sinkpad); - } if (!ret) { - gst_camerabin_image_destroy_elements (img); + gst_camerabin_remove_elements_from_bin (GST_BIN (imagebin)); } + GST_DEBUG_OBJECT (imagebin, "linking finished %s", ret ? "OK" : "NOK"); + return ret; } +/* + * gst_camerabin_image_create_elements: + * @img: a pointer to #GstCameraBinImage object + * + * This function creates needed elements, adds them to + * imagebin and links them. + * + * Returns %TRUE if success, %FALSE otherwise. + */ +static gboolean +gst_camerabin_image_create_elements (GstCameraBinImage * img) +{ + gboolean ret = FALSE; + g_return_val_if_fail (img != NULL, FALSE); + + if (gst_camerabin_image_prepare_elements (img)) { + ret = gst_camerabin_image_link_elements (img); + } + + return ret; +} /* * gst_camerabin_image_destroy_elements: @@ -501,12 +675,6 @@ gst_camerabin_image_destroy_elements (GstCameraBinImage * img) gst_ghost_pad_set_target (GST_GHOST_PAD (img->sinkpad), NULL); gst_camerabin_remove_elements_from_bin (GST_BIN (img)); - - img->enc = NULL; - img->meta_mux = NULL; - img->sink = NULL; - - img->elements_created = FALSE; } void diff --git a/gst/camerabin/camerabinimage.h b/gst/camerabin/camerabinimage.h index 25a258cae..b116d0905 100644 --- a/gst/camerabin/camerabinimage.h +++ b/gst/camerabin/camerabinimage.h @@ -48,14 +48,18 @@ struct _GstCameraBinImage /* Ghost pads of image bin */ GstPad *sinkpad; + /* Ordered list of elements configured to imagebin */ + GList *elements; + /* Imagebin elements */ GstElement *post; + GstElement *csp; GstElement *enc; GstElement *app_enc; GstElement *meta_mux; GstElement *sink; - gboolean elements_created; GstCameraBinFlags flags; + gulong metadata_probe_id; }; struct _GstCameraBinImageClass @@ -80,5 +84,7 @@ GstElement *gst_camerabin_image_get_encoder (GstCameraBinImage * img); GstElement *gst_camerabin_image_get_postproc (GstCameraBinImage * img); +gboolean gst_camerabin_image_prepare_elements (GstCameraBinImage * imagebin); + G_END_DECLS #endif /* #ifndef __CAMERABIN_IMAGE_H__ */ diff --git a/gst/camerabin/gstcamerabin.c b/gst/camerabin/gstcamerabin.c index 550a160a1..737540255 100644 --- a/gst/camerabin/gstcamerabin.c +++ b/gst/camerabin/gstcamerabin.c @@ -1039,6 +1039,10 @@ gst_camerabin_change_mode (GstCameraBin * camera, gint mode) camera->active_bin = camera->vidbin; } gst_camerabin_reset_to_view_finder (camera); + } else if (camera->mode == MODE_IMAGE) { + /* Prepare needed elements for image processing */ + gst_camerabin_image_prepare_elements (GST_CAMERABIN_IMAGE + (camera->imgbin)); } } } |