| /* Copyright (C) <2014> Intel Corporation | |
| * Copyright (C) <2014> Sreerenj Balachandran <sreerenj.balachandran@intel.com> | |
| * | |
| * Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com> | |
| * | |
| * 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. | |
| */ | |
| #ifdef HAVE_CONFIG_H | |
| #include "config.h" | |
| #endif | |
| #include <gst/gst.h> | |
| #include "gstplaybackutils.h" | |
| static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS ("audio/x-raw(ANY)"); | |
| static GstStaticCaps raw_video_caps = GST_STATIC_CAPS ("video/x-raw(ANY)"); | |
| /* unref the caps after usage */ | |
| static GstCaps * | |
| get_template_caps (GstElementFactory * factory, GstPadDirection direction) | |
| { | |
| const GList *templates; | |
| GstStaticPadTemplate *templ = NULL; | |
| GList *walk; | |
| templates = gst_element_factory_get_static_pad_templates (factory); | |
| for (walk = (GList *) templates; walk; walk = g_list_next (walk)) { | |
| templ = walk->data; | |
| if (templ->direction == direction) | |
| break; | |
| } | |
| if (templ) | |
| return gst_static_caps_get (&templ->static_caps); | |
| else | |
| return NULL; | |
| } | |
| static gboolean | |
| is_included (GList * list, GstCapsFeatures * cf) | |
| { | |
| for (; list; list = list->next) { | |
| if (gst_caps_features_is_equal ((GstCapsFeatures *) list->data, cf)) | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| /* compute the number of common caps features */ | |
| guint | |
| gst_playback_utils_get_n_common_capsfeatures (GstElementFactory * fact1, | |
| GstElementFactory * fact2, GstPlayFlags flags, gboolean isaudioelement) | |
| { | |
| GstCaps *fact1_tmpl_caps, *fact2_tmpl_caps; | |
| GstCapsFeatures *fact1_features, *fact2_features; | |
| GstStructure *fact1_struct, *fact2_struct; | |
| GList *cf_list = NULL; | |
| guint fact1_caps_size, fact2_caps_size; | |
| guint i, j, n_common_cf = 0; | |
| GstCaps *raw_caps = | |
| (isaudioelement) ? gst_static_caps_get (&raw_audio_caps) : | |
| gst_static_caps_get (&raw_video_caps); | |
| GstStructure *raw_struct = gst_caps_get_structure (raw_caps, 0); | |
| gboolean native_raw = | |
| (isaudioelement ? !!(flags & GST_PLAY_FLAG_NATIVE_AUDIO) : !!(flags & | |
| GST_PLAY_FLAG_NATIVE_VIDEO)); | |
| fact1_tmpl_caps = get_template_caps (fact1, GST_PAD_SRC); | |
| fact2_tmpl_caps = get_template_caps (fact2, GST_PAD_SINK); | |
| if (!fact1_tmpl_caps || !fact2_tmpl_caps) { | |
| GST_ERROR ("Failed to get template caps from decoder or sink"); | |
| if (fact1_tmpl_caps) | |
| gst_caps_unref (fact1_tmpl_caps); | |
| else if (fact2_tmpl_caps) | |
| gst_caps_unref (fact2_tmpl_caps); | |
| gst_clear_caps (&raw_caps); | |
| return 0; | |
| } | |
| fact1_caps_size = gst_caps_get_size (fact1_tmpl_caps); | |
| fact2_caps_size = gst_caps_get_size (fact2_tmpl_caps); | |
| for (i = 0; i < fact1_caps_size; i++) { | |
| fact1_features = | |
| gst_caps_get_features ((const GstCaps *) fact1_tmpl_caps, i); | |
| if (gst_caps_features_is_any (fact1_features)) | |
| continue; | |
| fact1_struct = | |
| gst_caps_get_structure ((const GstCaps *) fact1_tmpl_caps, i); | |
| for (j = 0; j < fact2_caps_size; j++) { | |
| fact2_features = | |
| gst_caps_get_features ((const GstCaps *) fact2_tmpl_caps, j); | |
| if (gst_caps_features_is_any (fact2_features)) | |
| continue; | |
| fact2_struct = | |
| gst_caps_get_structure ((const GstCaps *) fact2_tmpl_caps, j); | |
| /* A common caps feature is given if the caps features are equal | |
| * and the structures can intersect. If the NATIVE_AUDIO/NATIVE_VIDEO | |
| * flags are not set we also allow if both structures are raw caps with | |
| * system memory caps features, because in that case we have converters in | |
| * place. | |
| */ | |
| if (gst_caps_features_is_equal (fact1_features, fact2_features) && | |
| (gst_structure_can_intersect (fact1_struct, fact2_struct) || | |
| (!native_raw | |
| && gst_caps_features_is_equal (fact1_features, | |
| GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY) | |
| && gst_structure_can_intersect (raw_struct, fact1_struct) | |
| && gst_structure_can_intersect (raw_struct, fact2_struct))) | |
| && !is_included (cf_list, fact2_features)) { | |
| cf_list = g_list_prepend (cf_list, fact2_features); | |
| n_common_cf++; | |
| } | |
| } | |
| } | |
| if (cf_list) | |
| g_list_free (cf_list); | |
| gst_caps_unref (fact1_tmpl_caps); | |
| gst_caps_unref (fact2_tmpl_caps); | |
| gst_clear_caps (&raw_caps); | |
| return n_common_cf; | |
| } | |
| gint | |
| gst_playback_utils_compare_factories_func (gconstpointer p1, gconstpointer p2) | |
| { | |
| GstPluginFeature *f1, *f2; | |
| gboolean is_parser1, is_parser2; | |
| f1 = (GstPluginFeature *) p1; | |
| f2 = (GstPluginFeature *) p2; | |
| is_parser1 = gst_element_factory_list_is_type (GST_ELEMENT_FACTORY_CAST (f1), | |
| GST_ELEMENT_FACTORY_TYPE_PARSER); | |
| is_parser2 = gst_element_factory_list_is_type (GST_ELEMENT_FACTORY_CAST (f2), | |
| GST_ELEMENT_FACTORY_TYPE_PARSER); | |
| /* We want all parsers first as we always want to plug parsers | |
| * before decoders */ | |
| if (is_parser1 && !is_parser2) | |
| return -1; | |
| else if (!is_parser1 && is_parser2) | |
| return 1; | |
| /* And if it's a both a parser we first sort by rank | |
| * and then by factory name */ | |
| return gst_plugin_feature_rank_compare_func (p1, p2); | |
| } | |
| /* gst_playback_utils_stream_in_list: | |
| * @streams: A list of #GstStream | |
| * @stream: A #GstStream | |
| * | |
| * Searchs whether the given @stream is present in @streams. This also handles | |
| * the case where the actual @stream was rewritten but contains the same | |
| * stream-id and type. | |
| * | |
| * Returns: TRUE if @stream is in @streams. | |
| * | |
| **/ | |
| gboolean | |
| gst_playback_utils_stream_in_list (GList * streams, GstStream * stream) | |
| { | |
| GList *iter; | |
| const gchar *stream_id = gst_stream_get_stream_id (stream); | |
| GstStreamType stream_type = gst_stream_get_stream_type (stream); | |
| for (iter = streams; iter; iter = iter->next) { | |
| GstStream *cand = iter->data; | |
| if (iter->data == stream) | |
| return TRUE; | |
| /* Compare the stream type */ | |
| if (gst_stream_get_stream_type (cand) != stream_type) | |
| continue; | |
| /* Compare the stream-id */ | |
| if (!g_strcmp0 (stream_id, gst_stream_get_stream_id (cand))) | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } |