static GstElement * build_convert_frame_pipeline (GstElement ** src_element, GstElement ** sink_element, const GstCaps * from_caps, const GstCaps * to_caps, GError ** err) { GstElement *src = NULL, *csp = NULL, *vscale = NULL; GstElement *sink = NULL, *encoder = NULL, *pipeline; GError *error = NULL; /* videoscale is here to correct for the pixel-aspect-ratio for us */ GST_DEBUG ("creating elements"); if (!create_element ("appsrc", &src, &error) || !create_element ("ffmpegcolorspace", &csp, &error) || !create_element ("videoscale", &vscale, &error) || !create_element ("appsink", &sink, &error)) goto no_elements; pipeline = gst_pipeline_new ("videoconvert-pipeline"); if (pipeline == NULL) goto no_pipeline; /* Add black borders if necessary to keep the DAR */ g_object_set (vscale, "add-borders", TRUE, NULL); GST_DEBUG ("adding elements"); gst_bin_add_many (GST_BIN (pipeline), src, csp, vscale, sink, NULL); /* set caps */ g_object_set (src, "caps", from_caps, NULL); g_object_set (sink, "caps", to_caps, NULL); /* FIXME: linking is still way too expensive, profile this properly */ GST_DEBUG ("linking src->csp"); if (!gst_element_link_pads (src, "src", csp, "sink")) goto link_failed; GST_DEBUG ("linking csp->vscale"); if (!gst_element_link_pads (csp, "src", vscale, "sink")) goto link_failed; if (caps_are_raw (to_caps)) { GST_DEBUG ("linking vscale->sink"); if (!gst_element_link_pads (vscale, "src", sink, "sink")) goto link_failed; } else { encoder = get_encoder (to_caps, &error); if (!encoder) goto no_encoder; gst_bin_add (GST_BIN (pipeline), encoder); GST_DEBUG ("linking vscale->encoder"); if (!gst_element_link (vscale, encoder)) goto link_failed; GST_DEBUG ("linking encoder->sink"); if (!gst_element_link_pads (encoder, "src", sink, "sink")) goto link_failed; } g_object_set (src, "emit-signals", TRUE, NULL); g_object_set (sink, "emit-signals", TRUE, NULL); *src_element = src; *sink_element = sink; return pipeline; /* ERRORS */ no_encoder: { gst_object_unref (pipeline); GST_ERROR ("could not find an encoder for provided caps"); if (err) *err = error; else g_error_free (error); return NULL; } no_elements: { if (src) gst_object_unref (src); if (csp) gst_object_unref (csp); if (vscale) gst_object_unref (vscale); if (sink) gst_object_unref (sink); GST_ERROR ("Could not convert video frame: %s", error->message); if (err) *err = error; else g_error_free (error); return NULL; } no_pipeline: { gst_object_unref (src); gst_object_unref (csp); gst_object_unref (vscale); gst_object_unref (sink); GST_ERROR ("Could not convert video frame: no pipeline (unknown error)"); if (err) *err = g_error_new (GST_CORE_ERROR, GST_CORE_ERROR_FAILED, "Could not convert video frame: no pipeline (unknown error)"); return NULL; } link_failed: { gst_object_unref (pipeline); GST_ERROR ("Could not convert video frame: failed to link elements"); if (err) *err = g_error_new (GST_CORE_ERROR, GST_CORE_ERROR_NEGOTIATION, "Could not convert video frame: failed to link elements"); return NULL; } }
static GstElement * build_convert_frame_pipeline (GstElement ** src_element, GstElement ** sink_element, const GstCaps * from_caps, GstVideoCropMeta * cmeta, const GstCaps * to_caps, GError ** err) { GstElement *vcrop = NULL, *csp = NULL, *csp2 = NULL, *vscale = NULL; GstElement *src = NULL, *sink = NULL, *encoder = NULL, *pipeline; GstVideoInfo info; GError *error = NULL; if (cmeta) { if (!create_element ("videocrop", &vcrop, &error)) { g_error_free (error); g_warning ("build_convert_frame_pipeline: Buffer has crop metadata but videocrop element is not found. Cropping will be disabled"); } else { if (!create_element ("videoconvert", &csp2, &error)) goto no_elements; } } /* videoscale is here to correct for the pixel-aspect-ratio for us */ GST_DEBUG ("creating elements"); if (!create_element ("appsrc", &src, &error) || !create_element ("videoconvert", &csp, &error) || !create_element ("videoscale", &vscale, &error) || !create_element ("appsink", &sink, &error)) goto no_elements; pipeline = gst_pipeline_new ("videoconvert-pipeline"); if (pipeline == NULL) goto no_pipeline; /* Add black borders if necessary to keep the DAR */ g_object_set (vscale, "add-borders", TRUE, NULL); GST_DEBUG ("adding elements"); gst_bin_add_many (GST_BIN (pipeline), src, csp, vscale, sink, NULL); if (vcrop) gst_bin_add_many (GST_BIN (pipeline), vcrop, csp2, NULL); /* set caps */ g_object_set (src, "caps", from_caps, NULL); if (vcrop) { gst_video_info_from_caps (&info, from_caps); g_object_set (vcrop, "left", cmeta->x, NULL); g_object_set (vcrop, "top", cmeta->y, NULL); g_object_set (vcrop, "right", GST_VIDEO_INFO_WIDTH (&info) - cmeta->width, NULL); g_object_set (vcrop, "bottom", GST_VIDEO_INFO_HEIGHT (&info) - cmeta->height, NULL); GST_DEBUG ("crop meta [x,y,width,height]: %d %d %d %d", cmeta->x, cmeta->y, cmeta->width, cmeta->height); } g_object_set (sink, "caps", to_caps, NULL); /* FIXME: linking is still way too expensive, profile this properly */ if (vcrop) { GST_DEBUG ("linking src->csp2"); if (!gst_element_link_pads (src, "src", csp2, "sink")) goto link_failed; GST_DEBUG ("linking csp2->vcrop"); if (!gst_element_link_pads (csp2, "src", vcrop, "sink")) goto link_failed; GST_DEBUG ("linking vcrop->csp"); if (!gst_element_link_pads (vcrop, "src", csp, "sink")) goto link_failed; } else { GST_DEBUG ("linking src->csp"); if (!gst_element_link_pads (src, "src", csp, "sink")) goto link_failed; } GST_DEBUG ("linking csp->vscale"); if (!gst_element_link_pads_full (csp, "src", vscale, "sink", GST_PAD_LINK_CHECK_NOTHING)) goto link_failed; if (caps_are_raw (to_caps)) { GST_DEBUG ("linking vscale->sink"); if (!gst_element_link_pads_full (vscale, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) goto link_failed; } else { encoder = get_encoder (to_caps, &error); if (!encoder) goto no_encoder; gst_bin_add (GST_BIN (pipeline), encoder); GST_DEBUG ("linking vscale->encoder"); if (!gst_element_link (vscale, encoder)) goto link_failed; GST_DEBUG ("linking encoder->sink"); if (!gst_element_link_pads (encoder, "src", sink, "sink")) goto link_failed; } g_object_set (src, "emit-signals", TRUE, NULL); g_object_set (sink, "emit-signals", TRUE, NULL); *src_element = src; *sink_element = sink; return pipeline; /* ERRORS */ no_encoder: { gst_object_unref (pipeline); GST_ERROR ("could not find an encoder for provided caps"); if (err) *err = error; else g_error_free (error); return NULL; } no_elements: { if (src) gst_object_unref (src); if (vcrop) gst_object_unref (vcrop); if (csp) gst_object_unref (csp); if (csp2) gst_object_unref (csp2); if (vscale) gst_object_unref (vscale); if (sink) gst_object_unref (sink); GST_ERROR ("Could not convert video frame: %s", error->message); if (err) *err = error; else g_error_free (error); return NULL; } no_pipeline: { gst_object_unref (src); if (vcrop) gst_object_unref (vcrop); gst_object_unref (csp); if (csp2) gst_object_unref (csp2); gst_object_unref (vscale); gst_object_unref (sink); GST_ERROR ("Could not convert video frame: no pipeline (unknown error)"); if (err) *err = g_error_new (GST_CORE_ERROR, GST_CORE_ERROR_FAILED, "Could not convert video frame: no pipeline (unknown error)"); return NULL; } link_failed: { gst_object_unref (pipeline); GST_ERROR ("Could not convert video frame: failed to link elements"); if (err) *err = g_error_new (GST_CORE_ERROR, GST_CORE_ERROR_NEGOTIATION, "Could not convert video frame: failed to link elements"); return NULL; } }