gboolean rb_gst_media_type_matches_profile (GstEncodingProfile *profile, const char *media_type) { const GstCaps *pcaps; const GList *cl; GstCaps *caps; gboolean matches = FALSE; caps = rb_gst_media_type_to_caps (media_type); if (caps == NULL) { return FALSE; } pcaps = gst_encoding_profile_get_format (profile); if (gst_caps_can_intersect (caps, pcaps)) { matches = TRUE; } if (matches == FALSE && GST_IS_ENCODING_CONTAINER_PROFILE (profile)) { for (cl = gst_encoding_container_profile_get_profiles (GST_ENCODING_CONTAINER_PROFILE (profile)); cl != NULL; cl = cl->next) { GstEncodingProfile *cp = cl->data; pcaps = gst_encoding_profile_get_format (cp); if (gst_caps_can_intersect (caps, pcaps)) { matches = TRUE; break; } } } return matches; }
static gint _compare_encoding_profiles (const GstEncodingProfile * a, const GstEncodingProfile * b) { if ((G_TYPE_FROM_INSTANCE (a) != G_TYPE_FROM_INSTANCE (b)) || !_gst_caps_is_equal_safe (a->format, b->format) || (g_strcmp0 (a->preset, b->preset) != 0) || (g_strcmp0 (a->name, b->name) != 0) || (g_strcmp0 (a->description, b->description) != 0)) return -1; if (GST_IS_ENCODING_CONTAINER_PROFILE (a)) return _compare_container_encoding_profiles (GST_ENCODING_CONTAINER_PROFILE (a), GST_ENCODING_CONTAINER_PROFILE (b)); if (GST_IS_ENCODING_VIDEO_PROFILE (a)) { GstEncodingVideoProfile *va = (GstEncodingVideoProfile *) a; GstEncodingVideoProfile *vb = (GstEncodingVideoProfile *) b; if ((va->pass != vb->pass) || (va->variableframerate != vb->variableframerate)) return -1; } return 0; }
/** * gst_encoding_container_profile_get_profiles: * @profile: a #GstEncodingContainerProfile * * Returns: (element-type GstPbutils.EncodingProfile) (transfer none): * the list of contained #GstEncodingProfile. */ const GList * gst_encoding_container_profile_get_profiles (GstEncodingContainerProfile * profile) { g_return_val_if_fail (GST_IS_ENCODING_CONTAINER_PROFILE (profile), NULL); return profile->encodingprofiles; }
static gboolean gst_encoding_container_profile_has_video (GstEncodingContainerProfile * profile) { const GList *l; g_return_val_if_fail (GST_IS_ENCODING_CONTAINER_PROFILE (profile), FALSE); for (l = profile->encodingprofiles; l != NULL; l = l->next) { if (GST_IS_ENCODING_VIDEO_PROFILE (l->data)) return TRUE; if (GST_IS_ENCODING_CONTAINER_PROFILE (l->data) && gst_encoding_container_profile_has_video (l->data)) return TRUE; } return FALSE; }
/* Serialize the top-level profiles * Note: They don't have to be containerprofiles */ static gboolean serialize_encoding_profile (GKeyFile * out, GstEncodingProfile * prof) { gchar *profgroupname; const GList *tmp; guint i; const gchar *profname, *profdesc, *profpreset, *proftype; GstCaps *profformat; profname = gst_encoding_profile_get_name (prof); profdesc = gst_encoding_profile_get_description (prof); profformat = gst_encoding_profile_get_format (prof); profpreset = gst_encoding_profile_get_preset (prof); proftype = gst_encoding_profile_get_type_nick (prof); profgroupname = g_strdup_printf ("profile-%s", profname); g_key_file_set_string (out, profgroupname, "name", profname); g_key_file_set_value (out, profgroupname, "type", proftype); if (profdesc) { gchar *locale; locale = get_locale (); if (locale != NULL) { g_key_file_set_locale_string (out, profgroupname, "description", locale, profdesc); g_free (locale); } else { g_key_file_set_string (out, profgroupname, "description", profdesc); } } if (profformat) { gchar *tmpc = gst_caps_to_string (profformat); g_key_file_set_string (out, profgroupname, "format", tmpc); g_free (tmpc); } if (profpreset) g_key_file_set_string (out, profgroupname, "preset", profpreset); /* stream profiles */ if (GST_IS_ENCODING_CONTAINER_PROFILE (prof)) { for (tmp = gst_encoding_container_profile_get_profiles (GST_ENCODING_CONTAINER_PROFILE (prof)), i = 0; tmp; tmp = tmp->next, i++) { GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data; if (!serialize_stream_profiles (out, sprof, profname, i)) return FALSE; } } if (profformat) gst_caps_unref (profformat); g_free (profgroupname); return TRUE; }
/** * gst_encoding_container_profile_contains_profile: * @container: a #GstEncodingContainerProfile * @profile: a #GstEncodingProfile * * Checks if @container contains a #GstEncodingProfile identical to * @profile. * * Returns: %TRUE if @container contains a #GstEncodingProfile identical * to @profile, else %FALSE. */ gboolean gst_encoding_container_profile_contains_profile (GstEncodingContainerProfile * container, GstEncodingProfile * profile) { g_return_val_if_fail (GST_IS_ENCODING_CONTAINER_PROFILE (container), FALSE); g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE); return (g_list_find_custom (container->encodingprofiles, profile, (GCompareFunc) _compare_encoding_profiles) != NULL); }
/** * gst_encoding_profile_get_type_nick: * @profile: a #GstEncodingProfile * * Returns: the human-readable name of the type of @profile. */ const gchar * gst_encoding_profile_get_type_nick (GstEncodingProfile * profile) { if (GST_IS_ENCODING_CONTAINER_PROFILE (profile)) return "container"; if (GST_IS_ENCODING_VIDEO_PROFILE (profile)) return "video"; if (GST_IS_ENCODING_AUDIO_PROFILE (profile)) return "audio"; return NULL; }
static gboolean ges_pipeline_update_caps (GESPipeline * self) { GList *ltrack, *tracks, *lstream; if (!self->priv->profile) return TRUE; GST_DEBUG ("Updating track caps"); tracks = ges_timeline_get_tracks (self->priv->timeline); /* Take each stream of the encoding profile and find a matching * track to set the caps on */ for (ltrack = tracks; ltrack; ltrack = ltrack->next) { GESTrack *track = (GESTrack *) ltrack->data; GList *allstreams; if (!GST_IS_ENCODING_CONTAINER_PROFILE (self->priv->profile)) { if (_track_is_compatible_with_profile (self, track, self->priv->profile)) { gst_object_unref (track); goto done; } else { gst_object_unref (track); continue; } } allstreams = (GList *) gst_encoding_container_profile_get_profiles ( (GstEncodingContainerProfile *) self->priv->profile); /* Find a matching stream setting */ for (lstream = allstreams; lstream; lstream = lstream->next) { GstEncodingProfile *prof = (GstEncodingProfile *) lstream->data; if (_track_is_compatible_with_profile (self, track, prof)) break; } gst_object_unref (track); } done: if (tracks) g_list_free (tracks); GST_DEBUG ("Done updating caps"); return TRUE; }
static gboolean is_video_profile (const GstEncodingProfile *profile) { const GList *i, *profiles_list; if (GST_IS_ENCODING_CONTAINER_PROFILE (profile)) { profiles_list = gst_encoding_container_profile_get_profiles (GST_ENCODING_CONTAINER_PROFILE (profile)); for (i = profiles_list ; i; i = i->next) if (GST_IS_ENCODING_VIDEO_PROFILE (i->data)) return TRUE; } return FALSE; }
/** * gst_encoding_profile_get_input_caps: * @profile: a #GstEncodingProfile * * Computes the full output caps that this @profile will be able to consume. * * Returns: (transfer full): The full caps the given @profile can consume. Call * gst_caps_unref() when you are done with the caps. */ GstCaps * gst_encoding_profile_get_input_caps (GstEncodingProfile * profile) { GstCaps *out, *tmp; GList *ltmp; GstStructure *st, *outst; GQuark out_name; guint i, len; GstCaps *fcaps; g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), NULL); if (GST_IS_ENCODING_CONTAINER_PROFILE (profile)) { GstCaps *res = gst_caps_new_empty (); for (ltmp = GST_ENCODING_CONTAINER_PROFILE (profile)->encodingprofiles; ltmp; ltmp = ltmp->next) { GstEncodingProfile *sprof = (GstEncodingProfile *) ltmp->data; res = gst_caps_merge (res, gst_encoding_profile_get_input_caps (sprof)); } return res; } fcaps = profile->format; /* fast-path */ if ((profile->restriction == NULL) || gst_caps_is_any (profile->restriction)) return gst_caps_ref (fcaps); /* Combine the format with the restriction caps */ outst = gst_caps_get_structure (fcaps, 0); out_name = gst_structure_get_name_id (outst); tmp = gst_caps_new_empty (); len = gst_caps_get_size (profile->restriction); for (i = 0; i < len; i++) { st = gst_structure_copy (gst_caps_get_structure (profile->restriction, i)); st->name = out_name; gst_caps_append_structure (tmp, st); } out = gst_caps_intersect (tmp, fcaps); gst_caps_unref (tmp); return out; }
static GstEncodingProfile * get_audio_encoding_profile (GstEncodingProfile *profile) { if (GST_IS_ENCODING_AUDIO_PROFILE (profile)) { return profile; } else if (GST_IS_ENCODING_CONTAINER_PROFILE (profile)) { const GList *l = gst_encoding_container_profile_get_profiles (GST_ENCODING_CONTAINER_PROFILE (profile)); for (; l != NULL; l = l->next) { GstEncodingProfile *p = get_audio_encoding_profile (l->data); if (p != NULL) { return p; } } } g_warning ("no audio encoding profile in profile %s", gst_encoding_profile_get_name (profile)); return NULL; }
char *encoding_profile_get_media_type(GstEncodingProfile *profile) { if (GST_IS_ENCODING_CONTAINER_PROFILE(profile)) { const GList *cl = gst_encoding_container_profile_get_profiles(GST_ENCODING_CONTAINER_PROFILE(profile)); for (; cl != NULL; cl = cl->next) { GstEncodingProfile *p = cl->data; if (GST_IS_ENCODING_AUDIO_PROFILE(p)) { return caps_to_media_type(gst_encoding_profile_get_format(p)); } } /* now what? */ return NULL; } else { return caps_to_media_type(gst_encoding_profile_get_format(profile)); } }
/** * gst_encoding_container_profile_add_profile: * @container: the #GstEncodingContainerProfile to use * @profile: (transfer full): the #GstEncodingProfile to add. * * Add a #GstEncodingProfile to the list of profiles handled by @container. * * No copy of @profile will be made, if you wish to use it elsewhere after this * method you should increment its reference count. * * Returns: %TRUE if the @stream was properly added, else %FALSE. */ gboolean gst_encoding_container_profile_add_profile (GstEncodingContainerProfile * container, GstEncodingProfile * profile) { g_return_val_if_fail (GST_IS_ENCODING_CONTAINER_PROFILE (container), FALSE); g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE); if (g_list_find_custom (container->encodingprofiles, profile, (GCompareFunc) _compare_encoding_profiles)) { GST_ERROR ("Encoding profile already contains an identical GstEncodingProfile"); return FALSE; } container->encodingprofiles = g_list_append (container->encodingprofiles, profile); return TRUE; }
void rygel_gst_utils_dump_encoding_profile (GstEncodingProfile *profile, gint indent) { gchar *indent_s; const GstCaps *caps; gchar *format_name; const GstCaps *restriction; g_return_if_fail (profile != NULL); indent_s = g_strnfill ((gsize) indent, ' '); g_debug ("%s%s:", indent_s, gst_encoding_profile_get_name (profile)); caps = gst_encoding_profile_get_format (profile); format_name = gst_caps_to_string (caps); g_debug ("%s Format: %s", indent_s, format_name); g_free (format_name); restriction = gst_encoding_profile_get_restriction (profile); if (restriction) { gchar *restriction_name = gst_caps_to_string (restriction); g_debug ("%s Restriction: %s", indent_s, restriction_name); g_free (restriction_name); } if (GST_IS_ENCODING_CONTAINER_PROFILE (profile)) { GstEncodingContainerProfile *container = GST_ENCODING_CONTAINER_PROFILE (profile); const GList *subprofile_collection = gst_encoding_container_profile_get_profiles (container); const GList *subprofile_it; for (subprofile_it = subprofile_collection; subprofile_it != NULL; subprofile_it = subprofile_it->next) { GstEncodingProfile *subprofile = GST_ENCODING_PROFILE (subprofile_it->data); rygel_gst_utils_dump_encoding_profile (subprofile, indent + 4); } } g_free (indent_s); }
void ges_base_xml_formatter_add_encoding_profile (GESBaseXmlFormatter * self, const gchar * type, const gchar * parent, const gchar * name, const gchar * description, GstCaps * format, const gchar * preset, const gchar * preset_name, guint id, guint presence, GstCaps * restriction, guint pass, gboolean variableframerate, GstStructure * properties, GError ** error) { const GList *tmp; GstEncodingProfile *profile; GstEncodingContainerProfile *parent_profile = NULL; GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self); if (priv->check_only) goto done; if (parent == NULL) { profile = _create_profile (self, type, parent, name, description, format, preset, preset_name, id, presence, restriction, pass, variableframerate); ges_project_add_encoding_profile (GES_FORMATTER (self)->project, profile); gst_object_unref (profile); goto done; } for (tmp = ges_project_list_encoding_profiles (GES_FORMATTER (self)->project); tmp; tmp = tmp->next) { GstEncodingProfile *tmpprofile = GST_ENCODING_PROFILE (tmp->data); if (g_strcmp0 (gst_encoding_profile_get_name (tmpprofile), gst_encoding_profile_get_name (tmpprofile)) == 0) { if (!GST_IS_ENCODING_CONTAINER_PROFILE (tmpprofile)) { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "Profile '%s' parent %s is not a container...'", name, parent); goto done; } parent_profile = GST_ENCODING_CONTAINER_PROFILE (tmpprofile); break; } } if (parent_profile == NULL) { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "Profile '%s' parent %s does not exist'", name, parent); goto done; } profile = _create_profile (self, type, parent, name, description, format, preset, preset_name, id, presence, restriction, pass, variableframerate); if (profile == NULL) goto done; gst_encoding_container_profile_add_profile (parent_profile, profile); done: if (format) gst_caps_unref (format); if (restriction) gst_caps_unref (restriction); }
static gboolean compare_encoding_profile_with_discoverer_stream (GstValidateFileChecker * fc, GstEncodingProfile * prof, GstDiscovererStreamInfo * stream, gchar ** msg) { gboolean ret = TRUE; GstCaps *caps = NULL; const GstCaps *profile_caps; const GstCaps *restriction_caps; caps = gst_discoverer_stream_info_get_caps (stream); profile_caps = gst_encoding_profile_get_format (prof); restriction_caps = gst_encoding_profile_get_restriction (prof); /* TODO need to consider profile caps restrictions */ if (!_gst_caps_can_intersect_safe (caps, profile_caps)) { gchar *caps_str = gst_caps_to_string (caps); gchar *profile_caps_str = gst_caps_to_string (profile_caps); SET_MESSAGE (msg, g_strdup_printf ("Caps '%s' didn't match profile '%s'", profile_caps_str, caps_str)); g_free (caps_str); g_free (profile_caps_str); ret = FALSE; goto end; } if (restriction_caps) { GstStructure *structure; gint i; gboolean found = FALSE; for (i = 0; i < gst_caps_get_size (restriction_caps); i++) { structure = gst_caps_get_structure (restriction_caps, i); structure = gst_structure_copy (structure); gst_structure_set_name (structure, gst_structure_get_name (gst_caps_get_structure (caps, 0))); if (gst_structure_can_intersect (structure, gst_caps_get_structure (caps, 0))) { gst_structure_free (structure); found = TRUE; break; } gst_structure_free (structure); } if (!found) { gchar *caps_str = gst_caps_to_string (caps); gchar *restriction_caps_str = gst_caps_to_string (restriction_caps); SET_MESSAGE (msg, g_strdup_printf ("Caps restriction '%s' wasn't respected on file " "with caps '%s'", restriction_caps_str, caps_str)); g_free (caps_str); g_free (restriction_caps_str); ret = FALSE; goto end; } } if (GST_IS_ENCODING_CONTAINER_PROFILE (prof)) { if (GST_IS_DISCOVERER_CONTAINER_INFO (stream)) { ret = ret & compare_container_profile_with_container_discoverer_stream (fc, (GstEncodingContainerProfile *) prof, (GstDiscovererContainerInfo *) stream, msg); } else { SET_MESSAGE (msg, g_strdup_printf ("Expected container profile but found stream of %s", gst_discoverer_stream_info_get_stream_type_nick (stream))); ret = FALSE; goto end; } } else if (GST_IS_ENCODING_VIDEO_PROFILE (prof)) { if (!GST_IS_DISCOVERER_VIDEO_INFO (stream)) { SET_MESSAGE (msg, g_strdup_printf ("Expected video profile but found stream of %s", gst_discoverer_stream_info_get_stream_type_nick (stream))); ret = FALSE; goto end; } } else if (GST_IS_ENCODING_AUDIO_PROFILE (prof)) { if (!GST_IS_DISCOVERER_AUDIO_INFO (stream)) { SET_MESSAGE (msg, g_strdup_printf ("Expected audio profile but found stream of %s", gst_discoverer_stream_info_get_stream_type_nick (stream))); ret = FALSE; goto end; } } else { g_assert_not_reached (); return FALSE; } end: if (caps) gst_caps_unref (caps); return ret; }
/** * gst_encoding_profile_get_file_extension: * @profile: a #GstEncodingProfile * * Returns: a suitable file extension for @profile, or NULL. */ const gchar * gst_encoding_profile_get_file_extension (GstEncodingProfile * profile) { GstEncodingContainerProfile *cprofile; const gchar *ext = NULL; gboolean has_video; GstCaps *caps; guint num_children; g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), NULL); caps = gst_encoding_profile_get_format (profile); ext = pb_utils_get_file_extension_from_caps (caps); if (!GST_IS_ENCODING_CONTAINER_PROFILE (profile)) goto done; cprofile = GST_ENCODING_CONTAINER_PROFILE (profile); num_children = g_list_length (cprofile->encodingprofiles); /* if it's a tag container profile (e.g. id3mux/apemux), we need * to look at what's inside it */ if (pb_utils_is_tag (caps)) { GST_DEBUG ("tag container profile"); if (num_children == 1) { GstEncodingProfile *child_profile = cprofile->encodingprofiles->data; ext = gst_encoding_profile_get_file_extension (child_profile); } else { GST_WARNING ("expected exactly one child profile with tag profile"); } goto done; } if (num_children == 0) goto done; /* special cases */ has_video = gst_encoding_container_profile_has_video (cprofile); /* Ogg */ if (strcmp (ext, "ogg") == 0) { /* ogg with video => .ogv */ if (has_video) { ext = "ogv"; goto done; } /* ogg with just speex audio => .spx */ if (num_children == 1) { GstEncodingProfile *child_profile = cprofile->encodingprofiles->data; if (GST_IS_ENCODING_AUDIO_PROFILE (child_profile) && gst_encoding_profile_has_format (child_profile, "audio/x-speex")) { ext = "spx"; goto done; } } /* does anyone actually use .oga for ogg audio files? */ goto done; } /* Matroska */ if (has_video && strcmp (ext, "mka") == 0) { ext = "mkv"; goto done; } /* Windows Media / ASF */ if (gst_encoding_profile_has_format (profile, "video/x-ms-asf")) { const GList *l; guint num_wmv = 0, num_wma = 0, num_other = 0; for (l = cprofile->encodingprofiles; l != NULL; l = l->next) { if (gst_encoding_profile_has_format (l->data, "video/x-wmv")) ++num_wmv; else if (gst_encoding_profile_has_format (l->data, "audio/x-wma")) ++num_wma; else ++num_other; } if (num_other > 0) ext = "asf"; else if (num_wmv > 0) ext = "wmv"; else if (num_wma > 0) ext = "wma"; goto done; } done: GST_INFO ("caps %" GST_PTR_FORMAT ", ext: %s", caps, GST_STR_NULL (ext)); gst_caps_unref (caps); return ext; }
/** * ges_pipeline_set_render_settings: * @pipeline: a #GESPipeline * @output_uri: the URI to which the timeline will be rendered * @profile: the #GstEncodingProfile to use to render the timeline. * * Specify where the pipeline shall be rendered and with what settings. * * A copy of @profile and @output_uri will be done internally, the caller can * safely free those values afterwards. * * This method must be called before setting the pipeline mode to * #GES_PIPELINE_MODE_RENDER * * Returns: %TRUE if the settings were aknowledged properly, else %FALSE */ gboolean ges_pipeline_set_render_settings (GESPipeline * pipeline, const gchar * output_uri, GstEncodingProfile * profile) { GError *err = NULL; GstEncodingProfile *set_profile; g_return_val_if_fail (GES_IS_PIPELINE (pipeline), FALSE); /* FIXME Properly handle multi track, for now GESPipeline * only hanles single track per type, so we should just set the * presence to 1. */ if (GST_IS_ENCODING_CONTAINER_PROFILE (profile)) { const GList *tmpprofiles = gst_encoding_container_profile_get_profiles (GST_ENCODING_CONTAINER_PROFILE (profile)); GList *tmptrack, *tracks = ges_timeline_get_tracks (pipeline->priv->timeline); for (; tmpprofiles; tmpprofiles = tmpprofiles->next) { for (tmptrack = tracks; tmptrack; tmptrack = tmptrack->next) { if ((GST_IS_ENCODING_AUDIO_PROFILE (tmpprofiles->data) && GES_IS_AUDIO_TRACK (tmptrack->data)) || (GST_IS_ENCODING_VIDEO_PROFILE (tmpprofiles->data) && GES_IS_VIDEO_TRACK (tmptrack->data))) { GST_DEBUG_OBJECT (pipeline, "Setting presence to 1!"); gst_encoding_profile_set_presence (tmpprofiles->data, 1); gst_encoding_profile_set_allow_dynamic_output (tmpprofiles->data, FALSE); } } } g_list_free_full (tracks, gst_object_unref); } /* Clear previous URI sink if it existed */ /* FIXME : We should figure out if it was added to the pipeline, * and if so, remove it. */ if (pipeline->priv->urisink) { gst_object_unref (pipeline->priv->urisink); pipeline->priv->urisink = NULL; } pipeline->priv->urisink = gst_element_make_from_uri (GST_URI_SINK, output_uri, "urisink", &err); if (G_UNLIKELY (pipeline->priv->urisink == NULL)) { GST_ERROR_OBJECT (pipeline, "Couldn't not create sink for URI %s: '%s'", output_uri, ((err && err->message) ? err->message : "failed to create element")); g_clear_error (&err); return FALSE; } if (pipeline->priv->profile) gst_encoding_profile_unref (pipeline->priv->profile); g_object_set (pipeline->priv->encodebin, "avoid-reencoding", !(!(pipeline->priv->mode & GES_PIPELINE_MODE_SMART_RENDER)), NULL); g_object_set (pipeline->priv->encodebin, "profile", profile, NULL); g_object_get (pipeline->priv->encodebin, "profile", &set_profile, NULL); if (set_profile == NULL) { GST_ERROR_OBJECT (pipeline, "Profile %" GST_PTR_FORMAT " could no be set", profile); return FALSE; } /* We got a referencer when getting back the profile */ pipeline->priv->profile = profile; return TRUE; }