1 /* GStreamer
2  * Copyright (C) <2010> Edward Hervey <edward.hervey@collabora.co.uk>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #include "gstcapslist.h"
21 
22 /*
23  * Caps listing convenience functions
24  */
25 
26 static gboolean
remove_range_foreach(GQuark field_id,const GValue * value,GstStructure * st)27 remove_range_foreach (GQuark field_id, const GValue * value, GstStructure * st)
28 {
29   GType ftype = G_VALUE_TYPE (value);
30   /* const gchar *fname; */
31 
32   if (ftype == GST_TYPE_INT_RANGE || ftype == GST_TYPE_DOUBLE_RANGE ||
33       ftype == GST_TYPE_FRACTION_RANGE) {
34     gst_structure_remove_field (st, g_quark_to_string (field_id));
35     return FALSE;
36   }
37 
38   /* fname = g_quark_to_string (field_id); */
39   /* if (strstr (fname, "framerate") || strstr (fname, "pixel-aspect-ratio") || */
40   /*     strstr (fname, "rate")) { */
41   /*   gst_structure_remove_field (st, g_quark_to_string (field_id)); */
42   /*   return FALSE; */
43   /* } */
44 
45   return TRUE;
46 }
47 
48 static void
clear_caps(GstCaps * caps,GstCaps * rescaps)49 clear_caps (GstCaps * caps, GstCaps * rescaps)
50 {
51   GstCaps *res;
52   GstStructure *st;
53   guint i;
54 
55   res = gst_caps_make_writable (caps);
56 
57   GST_DEBUG ("incoming caps %" GST_PTR_FORMAT, res);
58 
59   /* Remove width/height/framerate/depth/width fields */
60   for (i = gst_caps_get_size (res); i; i--) {
61     st = gst_caps_get_structure (res, i - 1);
62 
63     /* Remove range fields */
64     while (!gst_structure_foreach (st,
65             (GstStructureForeachFunc) remove_range_foreach, st));
66   }
67 
68   GST_DEBUG ("stripped %" GST_PTR_FORMAT, res);
69 
70   /* And append to list without duplicates */
71   while ((st = gst_caps_steal_structure (res, 0))) {
72     /* Skip fake codecs/containers */
73     if (gst_structure_has_name (st, "audio/x-raw") ||
74         gst_structure_has_name (st, "video/x-raw") ||
75         gst_structure_has_name (st, "unknown/unknown")) {
76       gst_structure_free (st);
77       continue;
78     }
79 
80     gst_caps_append_structure (rescaps, st);
81   }
82 
83   gst_caps_unref (res);
84 }
85 
86 static GstCaps *
get_all_caps(GList * elements,GstPadDirection direction)87 get_all_caps (GList * elements, GstPadDirection direction)
88 {
89   GstCaps *res;
90   GList *tmp;
91 
92   res = gst_caps_new_empty ();
93 
94   for (tmp = elements; tmp; tmp = tmp->next) {
95     GstElementFactory *factory = (GstElementFactory *) tmp->data;
96     const GList *templates;
97     GList *walk;
98 
99     templates = gst_element_factory_get_static_pad_templates (factory);
100     for (walk = (GList *) templates; walk; walk = g_list_next (walk)) {
101       GstStaticPadTemplate *templ = walk->data;
102       if (templ->direction == direction)
103         clear_caps (gst_static_caps_get (&templ->static_caps), res);
104     }
105   }
106 
107   res = gst_caps_normalize (res);
108 
109   return res;
110 }
111 
112 /**
113  * gst_caps_list_container_formats:
114  * @minrank: The minimum #GstRank
115  *
116  * Returns a #GstCaps corresponding to all the container formats
117  * one can mux to on this system.
118  *
119  * Returns: A #GstCaps. Unref with %gst_caps_unref when done with it.
120  */
121 GstCaps *
gst_caps_list_container_formats(GstRank minrank)122 gst_caps_list_container_formats (GstRank minrank)
123 {
124   GstCaps *res;
125   GList *muxers;
126 
127   muxers =
128       gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_MUXER,
129       minrank);
130   res = get_all_caps (muxers, GST_PAD_SRC);
131   gst_plugin_feature_list_free (muxers);
132 
133   return res;
134 }
135 
136 static GstCaps *
gst_caps_list_encoding_formats(GstRank minrank)137 gst_caps_list_encoding_formats (GstRank minrank)
138 {
139   GstCaps *res;
140   GList *encoders;
141 
142   encoders =
143       gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_ENCODER,
144       minrank);
145   res = get_all_caps (encoders, GST_PAD_SRC);
146   gst_plugin_feature_list_free (encoders);
147 
148   return res;
149 }
150 
151 /**
152  * gst_caps_list_video_encoding_formats:
153  * @minrank: The minimum #GstRank
154  *
155  * Returns a #GstCaps corresponding to all the video or image formats one
156  * can encode to on this system.
157  *
158  * Returns: A #GstCaps. Unref with %gst_caps_unref when done with it.
159  */
160 GstCaps *
gst_caps_list_video_encoding_formats(GstRank minrank)161 gst_caps_list_video_encoding_formats (GstRank minrank)
162 {
163   GstCaps *res;
164   GList *encoders;
165 
166   encoders =
167       gst_element_factory_list_get_elements
168       (GST_ELEMENT_FACTORY_TYPE_VIDEO_ENCODER, minrank);
169   res = get_all_caps (encoders, GST_PAD_SRC);
170   gst_plugin_feature_list_free (encoders);
171 
172   return res;
173 }
174 
175 
176 /**
177  * gst_caps_list_audio_encoding_formats:
178  * @minrank: The minimum #GstRank
179  *
180  * Returns a #GstCaps corresponding to all the audio formats one
181  * can encode to on this system.
182  *
183  * Returns: A  #GstCaps. Unref with %gst_caps_unref when done with it.
184  */
185 GstCaps *
gst_caps_list_audio_encoding_formats(GstRank minrank)186 gst_caps_list_audio_encoding_formats (GstRank minrank)
187 {
188   GstCaps *res;
189   GList *encoders;
190 
191   encoders =
192       gst_element_factory_list_get_elements
193       (GST_ELEMENT_FACTORY_TYPE_AUDIO_ENCODER, minrank);
194   res = get_all_caps (encoders, GST_PAD_SRC);
195   gst_plugin_feature_list_free (encoders);
196 
197   return res;
198 }
199 
200 /**
201  * gst_caps_list_compatible_codecs:
202  * @containerformat: A #GstCaps corresponding to a container format
203  * @codecformats: An optional #GstCaps of codec formats
204  * @muxers: An optional #GList of muxer #GstElementFactory.
205  *
206  * Returns an array of #GstCaps corresponding to the audio/video/text formats
207  * one can encode to and that can be muxed in the provided @containerformat.
208  *
209  * If specified, only the #GstCaps contained in @codecformats will be checked
210  * against, else all compatible audio/video formats will be returned.
211  *
212  * If specified, only the #GstElementFactory contained in @muxers will be checked,
213  * else all available muxers on the system will be checked.
214  *
215  * Returns: A #GstCaps containing all compatible formats. Unref with %gst_caps_unref
216  * when done.
217  */
218 GstCaps *
gst_caps_list_compatible_codecs(const GstCaps * containerformat,GstCaps * codecformats,GList * muxers)219 gst_caps_list_compatible_codecs (const GstCaps * containerformat,
220     GstCaps * codecformats, GList * muxers)
221 {
222   const GList *templates;
223   GstElementFactory *factory;
224   GList *walk;
225   GstCaps *res = NULL;
226   GstCaps *tmpcaps;
227   GList *tmp;
228   gboolean hadmuxers = (muxers != NULL);
229   gboolean hadcodecs = (codecformats != NULL);
230 
231   GST_DEBUG ("containerformat: %" GST_PTR_FORMAT, containerformat);
232   GST_DEBUG ("codecformats: %" GST_PTR_FORMAT, codecformats);
233 
234   if (!hadmuxers)
235     muxers =
236         gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_MUXER,
237         GST_RANK_NONE);
238   if (!hadcodecs)
239     codecformats = gst_caps_list_encoding_formats (GST_RANK_NONE);
240 
241   /* Get the highest rank muxer matching containerformat */
242   tmp =
243       gst_element_factory_list_filter (muxers, containerformat, GST_PAD_SRC,
244       TRUE);
245   if (G_UNLIKELY (tmp == NULL))
246     goto beach;
247 
248   factory = (GstElementFactory *) tmp->data;
249 
250   GST_DEBUG ("Trying with factory %s",
251       gst_element_factory_get_metadata (factory,
252           GST_ELEMENT_METADATA_LONGNAME));
253 
254   /* Match all muxer sink pad templates against the available codec formats */
255   templates = gst_element_factory_get_static_pad_templates (factory);
256   gst_plugin_feature_list_free (tmp);
257 
258   tmpcaps = gst_caps_new_empty ();
259 
260   for (walk = (GList *) templates; walk; walk = walk->next) {
261     GstStaticPadTemplate *templ = walk->data;
262 
263     if (templ->direction == GST_PAD_SINK) {
264       GstCaps *templ_caps;
265 
266       templ_caps = gst_static_caps_get (&templ->static_caps);
267       gst_caps_append (tmpcaps, gst_caps_copy (templ_caps));
268     }
269   }
270 
271   res = gst_caps_intersect (tmpcaps, codecformats);
272   gst_caps_unref (tmpcaps);
273 
274 beach:
275   if (!hadmuxers)
276     gst_plugin_feature_list_free (muxers);
277   if (!hadcodecs)
278     gst_caps_unref (codecformats);
279 
280   res = gst_caps_normalize (res);
281 
282   return res;
283 }
284