| /* GStreamer | |
| * Copyright (C) <2010> Edward Hervey <edward.hervey@collabora.co.uk> | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Library General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Library General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Library General Public | |
| * License along with this library; if not, write to the | |
| * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, | |
| * Boston, MA 02110-1301, USA. | |
| */ | |
| #include "gstcapslist.h" | |
| /* | |
| * Caps listing convenience functions | |
| */ | |
| static gboolean | |
| remove_range_foreach (GQuark field_id, const GValue * value, GstStructure * st) | |
| { | |
| GType ftype = G_VALUE_TYPE (value); | |
| /* const gchar *fname; */ | |
| if (ftype == GST_TYPE_INT_RANGE || ftype == GST_TYPE_DOUBLE_RANGE || | |
| ftype == GST_TYPE_FRACTION_RANGE) { | |
| gst_structure_remove_field (st, g_quark_to_string (field_id)); | |
| return FALSE; | |
| } | |
| /* fname = g_quark_to_string (field_id); */ | |
| /* if (strstr (fname, "framerate") || strstr (fname, "pixel-aspect-ratio") || */ | |
| /* strstr (fname, "rate")) { */ | |
| /* gst_structure_remove_field (st, g_quark_to_string (field_id)); */ | |
| /* return FALSE; */ | |
| /* } */ | |
| return TRUE; | |
| } | |
| static void | |
| clear_caps (GstCaps * caps, GstCaps * rescaps) | |
| { | |
| GstCaps *res; | |
| GstStructure *st; | |
| guint i; | |
| res = gst_caps_make_writable (caps); | |
| GST_DEBUG ("incoming caps %" GST_PTR_FORMAT, res); | |
| /* Remove width/height/framerate/depth/width fields */ | |
| for (i = gst_caps_get_size (res); i; i--) { | |
| st = gst_caps_get_structure (res, i - 1); | |
| /* Remove range fields */ | |
| while (!gst_structure_foreach (st, | |
| (GstStructureForeachFunc) remove_range_foreach, st)); | |
| } | |
| GST_DEBUG ("stripped %" GST_PTR_FORMAT, res); | |
| /* And append to list without duplicates */ | |
| while ((st = gst_caps_steal_structure (res, 0))) { | |
| /* Skip fake codecs/containers */ | |
| if (gst_structure_has_name (st, "audio/x-raw") || | |
| gst_structure_has_name (st, "video/x-raw") || | |
| gst_structure_has_name (st, "unknown/unknown")) { | |
| gst_structure_free (st); | |
| continue; | |
| } | |
| gst_caps_append_structure (rescaps, st); | |
| } | |
| gst_caps_unref (res); | |
| } | |
| static GstCaps * | |
| get_all_caps (GList * elements, GstPadDirection direction) | |
| { | |
| GstCaps *res; | |
| GList *tmp; | |
| res = gst_caps_new_empty (); | |
| for (tmp = elements; tmp; tmp = tmp->next) { | |
| GstElementFactory *factory = (GstElementFactory *) tmp->data; | |
| const GList *templates; | |
| GList *walk; | |
| templates = gst_element_factory_get_static_pad_templates (factory); | |
| for (walk = (GList *) templates; walk; walk = g_list_next (walk)) { | |
| GstStaticPadTemplate *templ = walk->data; | |
| if (templ->direction == direction) | |
| clear_caps (gst_static_caps_get (&templ->static_caps), res); | |
| } | |
| } | |
| res = gst_caps_normalize (res); | |
| return res; | |
| } | |
| /** | |
| * gst_caps_list_container_formats: | |
| * @minrank: The minimum #GstRank | |
| * | |
| * Returns a #GstCaps corresponding to all the container formats | |
| * one can mux to on this system. | |
| * | |
| * Returns: A #GstCaps. Unref with %gst_caps_unref when done with it. | |
| */ | |
| GstCaps * | |
| gst_caps_list_container_formats (GstRank minrank) | |
| { | |
| GstCaps *res; | |
| GList *muxers; | |
| muxers = | |
| gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_MUXER, | |
| minrank); | |
| res = get_all_caps (muxers, GST_PAD_SRC); | |
| gst_plugin_feature_list_free (muxers); | |
| return res; | |
| } | |
| static GstCaps * | |
| gst_caps_list_encoding_formats (GstRank minrank) | |
| { | |
| GstCaps *res; | |
| GList *encoders; | |
| encoders = | |
| gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_ENCODER, | |
| minrank); | |
| res = get_all_caps (encoders, GST_PAD_SRC); | |
| gst_plugin_feature_list_free (encoders); | |
| return res; | |
| } | |
| /** | |
| * gst_caps_list_video_encoding_formats: | |
| * @minrank: The minimum #GstRank | |
| * | |
| * Returns a #GstCaps corresponding to all the video or image formats one | |
| * can encode to on this system. | |
| * | |
| * Returns: A #GstCaps. Unref with %gst_caps_unref when done with it. | |
| */ | |
| GstCaps * | |
| gst_caps_list_video_encoding_formats (GstRank minrank) | |
| { | |
| GstCaps *res; | |
| GList *encoders; | |
| encoders = | |
| gst_element_factory_list_get_elements | |
| (GST_ELEMENT_FACTORY_TYPE_VIDEO_ENCODER, minrank); | |
| res = get_all_caps (encoders, GST_PAD_SRC); | |
| gst_plugin_feature_list_free (encoders); | |
| return res; | |
| } | |
| /** | |
| * gst_caps_list_audio_encoding_formats: | |
| * @minrank: The minimum #GstRank | |
| * | |
| * Returns a #GstCaps corresponding to all the audio formats one | |
| * can encode to on this system. | |
| * | |
| * Returns: A #GstCaps. Unref with %gst_caps_unref when done with it. | |
| */ | |
| GstCaps * | |
| gst_caps_list_audio_encoding_formats (GstRank minrank) | |
| { | |
| GstCaps *res; | |
| GList *encoders; | |
| encoders = | |
| gst_element_factory_list_get_elements | |
| (GST_ELEMENT_FACTORY_TYPE_AUDIO_ENCODER, minrank); | |
| res = get_all_caps (encoders, GST_PAD_SRC); | |
| gst_plugin_feature_list_free (encoders); | |
| return res; | |
| } | |
| /** | |
| * gst_caps_list_compatible_codecs: | |
| * @containerformat: A #GstCaps corresponding to a container format | |
| * @codecformats: An optional #GstCaps of codec formats | |
| * @muxers: An optional #GList of muxer #GstElementFactory. | |
| * | |
| * Returns an array of #GstCaps corresponding to the audio/video/text formats | |
| * one can encode to and that can be muxed in the provided @containerformat. | |
| * | |
| * If specified, only the #GstCaps contained in @codecformats will be checked | |
| * against, else all compatible audio/video formats will be returned. | |
| * | |
| * If specified, only the #GstElementFactory contained in @muxers will be checked, | |
| * else all available muxers on the system will be checked. | |
| * | |
| * Returns: A #GstCaps containing all compatible formats. Unref with %gst_caps_unref | |
| * when done. | |
| */ | |
| GstCaps * | |
| gst_caps_list_compatible_codecs (const GstCaps * containerformat, | |
| GstCaps * codecformats, GList * muxers) | |
| { | |
| const GList *templates; | |
| GstElementFactory *factory; | |
| GList *walk; | |
| GstCaps *res = NULL; | |
| GstCaps *tmpcaps; | |
| GList *tmp; | |
| gboolean hadmuxers = (muxers != NULL); | |
| gboolean hadcodecs = (codecformats != NULL); | |
| GST_DEBUG ("containerformat: %" GST_PTR_FORMAT, containerformat); | |
| GST_DEBUG ("codecformats: %" GST_PTR_FORMAT, codecformats); | |
| if (!hadmuxers) | |
| muxers = | |
| gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_MUXER, | |
| GST_RANK_NONE); | |
| if (!hadcodecs) | |
| codecformats = gst_caps_list_encoding_formats (GST_RANK_NONE); | |
| /* Get the highest rank muxer matching containerformat */ | |
| tmp = | |
| gst_element_factory_list_filter (muxers, containerformat, GST_PAD_SRC, | |
| TRUE); | |
| if (G_UNLIKELY (tmp == NULL)) | |
| goto beach; | |
| factory = (GstElementFactory *) tmp->data; | |
| GST_DEBUG ("Trying with factory %s", | |
| gst_element_factory_get_metadata (factory, | |
| GST_ELEMENT_METADATA_LONGNAME)); | |
| /* Match all muxer sink pad templates against the available codec formats */ | |
| templates = gst_element_factory_get_static_pad_templates (factory); | |
| gst_plugin_feature_list_free (tmp); | |
| tmpcaps = gst_caps_new_empty (); | |
| for (walk = (GList *) templates; walk; walk = walk->next) { | |
| GstStaticPadTemplate *templ = walk->data; | |
| if (templ->direction == GST_PAD_SINK) { | |
| GstCaps *templ_caps; | |
| templ_caps = gst_static_caps_get (&templ->static_caps); | |
| gst_caps_append (tmpcaps, gst_caps_copy (templ_caps)); | |
| } | |
| } | |
| res = gst_caps_intersect (tmpcaps, codecformats); | |
| gst_caps_unref (tmpcaps); | |
| beach: | |
| if (!hadmuxers) | |
| gst_plugin_feature_list_free (muxers); | |
| if (!hadcodecs) | |
| gst_caps_unref (codecformats); | |
| res = gst_caps_normalize (res); | |
| return res; | |
| } |