/* GStreamer * Copyright (C) <2010> Edward Hervey * * 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., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, 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-int") || gst_structure_has_name (st, "audio/x-raw-float") || gst_structure_has_name (st, "video/x-raw-yuv") || gst_structure_has_name (st, "video/x-raw-rgb") || 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 = NULL, *res2; 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); } } res2 = gst_caps_normalize (res); gst_caps_unref (res); return res2; } /** * 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_longname (factory)); /* 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); tmpcaps = gst_caps_normalize (res); gst_caps_unref (res); return tmpcaps; }