diff --git a/configure.ac b/configure.ac index 64f877cf65..ff219a989f 100644 --- a/configure.ac +++ b/configure.ac @@ -995,6 +995,7 @@ tests/check/Makefile tests/examples/Makefile tests/examples/app/Makefile tests/examples/dynamic/Makefile +tests/examples/encoding/Makefile tests/examples/gio/Makefile tests/examples/overlay/Makefile tests/examples/seek/Makefile diff --git a/tests/examples/Makefile.am b/tests/examples/Makefile.am index 841338093f..48c38a55c4 100644 --- a/tests/examples/Makefile.am +++ b/tests/examples/Makefile.am @@ -8,8 +8,8 @@ if USE_GIO GIO_SUBDIRS = gio endif -SUBDIRS = app dynamic $(FT2_SUBDIRS) $(GIO_SUBDIRS) overlay playrec volume v4l +SUBDIRS = app dynamic $(FT2_SUBDIRS) $(GIO_SUBDIRS) overlay playrec volume v4l encoding -DIST_SUBDIRS = app dynamic gio overlay seek snapshot playrec volume v4l +DIST_SUBDIRS = app dynamic gio overlay seek snapshot playrec volume v4l encoding include $(top_srcdir)/common/parallel-subdirs.mak diff --git a/tests/examples/encoding/.gitignore b/tests/examples/encoding/.gitignore new file mode 100644 index 0000000000..c684c2e50a --- /dev/null +++ b/tests/examples/encoding/.gitignore @@ -0,0 +1 @@ +encoding diff --git a/tests/examples/encoding/Makefile.am b/tests/examples/encoding/Makefile.am new file mode 100644 index 0000000000..3e95e8aca3 --- /dev/null +++ b/tests/examples/encoding/Makefile.am @@ -0,0 +1,11 @@ +examples = encoding + +encoding_SOURCES = gstcapslist.c encoding.c +EXTRA_DIST = gstcapslist.h + +noinst_PROGRAMS = $(examples) + +LDADD = $(top_builddir)/gst-libs/gst/pbutils/libgstpbutils-@GST_MAJORMINOR@.la\ + -lgstpbutils-@GST_MAJORMINOR@ + $(GST_LIBS) +AM_CFLAGS = -I$(top_builddir)/gst-libs $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) diff --git a/tests/examples/encoding/encoding.c b/tests/examples/encoding/encoding.c new file mode 100644 index 0000000000..c668148f8b --- /dev/null +++ b/tests/examples/encoding/encoding.c @@ -0,0 +1,512 @@ +/* Example application for using GstProfile and encodebin + * Copyright (C) 2009 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include "gstcapslist.h" + +static gboolean silent = FALSE; + +static void +list_codecs (void) +{ + GstCaps *l; + GstCaps *caps; + guint i, len; + + caps = gst_caps_new_empty (); + + g_print ("Available container formats:\n"); + l = gst_caps_list_container_formats (GST_RANK_NONE); + len = gst_caps_get_size (l); + for (i = 0; i < len; i++) { + GstStructure *st = gst_caps_steal_structure (l, 0); + gchar *tmpstr, *desc; + + gst_caps_append_structure (caps, st); + + tmpstr = gst_caps_to_string (caps); + desc = gst_pb_utils_get_codec_description (caps); + g_print (" %s - %s\n", desc, tmpstr); + g_free (tmpstr); + if (desc) + g_free (desc); + gst_caps_remove_structure (caps, 0); + } + g_print ("\n"); + gst_caps_unref (l); + + g_print ("Available video codecs:\n"); + l = gst_caps_list_video_encoding_formats (GST_RANK_NONE); + len = gst_caps_get_size (l); + for (i = 0; i < len; i++) { + GstStructure *st = gst_caps_steal_structure (l, 0); + gchar *tmpstr, *desc; + + gst_caps_append_structure (caps, st); + + tmpstr = gst_caps_to_string (caps); + desc = gst_pb_utils_get_codec_description (caps); + g_print (" %s - %s\n", desc, tmpstr); + g_free (tmpstr); + if (desc) + g_free (desc); + gst_caps_remove_structure (caps, 0); + } + g_print ("\n"); + gst_caps_unref (l); + + g_print ("Available audio codecs:\n"); + l = gst_caps_list_audio_encoding_formats (GST_RANK_NONE); + len = gst_caps_get_size (l); + for (i = 0; i < len; i++) { + GstStructure *st = gst_caps_steal_structure (l, 0); + gchar *tmpstr, *desc; + + gst_caps_append_structure (caps, st); + + tmpstr = gst_caps_to_string (caps); + desc = gst_pb_utils_get_codec_description (caps); + g_print (" %s - %s\n", desc, tmpstr); + g_free (tmpstr); + if (desc) + g_free (desc); + gst_caps_remove_structure (caps, 0); + } + g_print ("\n"); + gst_caps_unref (l); + + gst_caps_unref (caps); +} + +static gchar * +generate_filename (const GstCaps * container, const GstCaps * vcodec, + const GstCaps * acodec) +{ + gchar *a, *b, *c; + gchar *res = NULL; + guint i; + + a = gst_pb_utils_get_codec_description (container); + b = gst_pb_utils_get_codec_description (vcodec); + c = gst_pb_utils_get_codec_description (acodec); + + if (!a) + a = g_strdup_printf ("%.10s", + g_uri_escape_string (gst_caps_to_string (container), NULL, FALSE)); + if (!b) + b = g_strdup_printf ("%.10s", + g_uri_escape_string (gst_caps_to_string (vcodec), NULL, FALSE)); + if (!c) + c = g_strdup_printf ("%.10s", + g_uri_escape_string (gst_caps_to_string (acodec), NULL, FALSE)); + + for (i = 0; i < 256 && res == NULL; i++) { + res = g_strdup_printf ("%s-%s-%s-%d.file", a, b, c, i); + if (g_file_test (res, G_FILE_TEST_EXISTS)) { + g_free (res); + res = NULL; + } + } + /* Make sure file doesn't already exist */ + + g_free (a); + g_free (b); + g_free (c); + + return res; +} + +static GstEncodingProfile * +create_profile (GstCaps * cf, GstCaps * vf, GstCaps * af) +{ + GstEncodingContainerProfile *cprof = NULL; + + cprof = + gst_encoding_container_profile_new ((gchar *) "test-application-profile", + NULL, cf, NULL); + + if (vf) + gst_encoding_container_profile_add_profile (cprof, + (GstEncodingProfile *) gst_encoding_video_profile_new (vf, + NULL, NULL, 0)); + if (af) + gst_encoding_container_profile_add_profile (cprof, (GstEncodingProfile *) + gst_encoding_audio_profile_new (af, NULL, NULL, 0)); + + /* Let's print out some info */ + if (!silent) { + gchar *desc = gst_pb_utils_get_codec_description (cf); + gchar *cd = gst_caps_to_string (cf); + g_print ("Encoding parameters\n"); + g_print (" Container format : %s (%s)\n", desc, cd); + g_free (desc); + g_free (cd); + if (vf) { + desc = gst_pb_utils_get_codec_description (vf); + cd = gst_caps_to_string (vf); + g_print (" Video format : %s (%s)\n", desc, cd); + g_free (desc); + g_free (cd); + } + if (af) { + desc = gst_pb_utils_get_codec_description (af); + cd = gst_caps_to_string (af); + g_print (" Audio format : %s (%s)\n", desc, cd); + g_free (desc); + g_free (cd); + } + } + + return (GstEncodingProfile *) cprof; +} + +static GstEncodingProfile * +create_profile_from_string (gchar * format, gchar * vformat, gchar * aformat) +{ + GstEncodingProfile *prof = NULL; + GstCaps *cf = NULL, *vf = NULL, *af = NULL; + + if (format) + cf = gst_caps_from_string (format); + if (vformat) + vf = gst_caps_from_string (vformat); + if (aformat) + af = gst_caps_from_string (aformat); + + if (G_UNLIKELY ((vformat && (vf == NULL)) || (aformat && (af == NULL)))) + goto beach; + + prof = create_profile (cf, vf, af); + +beach: + if (cf) + gst_caps_unref (cf); + if (vf) + gst_caps_unref (vf); + if (af) + gst_caps_unref (af); + + return prof; +} + +static void +pad_added_cb (GstElement * uridecodebin, GstPad * pad, GstElement * encodebin) +{ + GstPad *sinkpad; + + sinkpad = gst_element_get_compatible_pad (encodebin, pad, NULL); + + if (sinkpad == NULL) { + GstCaps *caps; + + /* Ask encodebin for a compatible pad */ + caps = gst_pad_get_caps (pad); + g_signal_emit_by_name (encodebin, "request-pad", caps, &sinkpad); + if (caps) + gst_caps_unref (caps); + } + if (sinkpad == NULL) { + g_print ("Couldn't get an encoding channel for pad %s:%s\n", + GST_DEBUG_PAD_NAME (pad)); + return; + } + + if (G_UNLIKELY (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)) { + g_print ("Couldn't link pads\n"); + } + + return; +} + +static gboolean +autoplug_continue_cb (GstElement * uridecodebin, GstPad * somepad, + GstCaps * caps, GstElement * encodebin) +{ + GstPad *sinkpad; + + g_signal_emit_by_name (encodebin, "request-pad", caps, &sinkpad); + + if (sinkpad == NULL) + return TRUE; + + return FALSE; +} + +static void +bus_message_cb (GstBus * bus, GstMessage * message, GMainLoop * mainloop) +{ + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_ERROR: + g_print ("ERROR\n"); + gst_bus_set_flushing (bus, TRUE); + g_main_loop_quit (mainloop); + break; + case GST_MESSAGE_EOS: + g_print ("Done\n"); + g_main_loop_quit (mainloop); + break; + default: + break; + } +} + +static void +transcode_file (gchar * uri, gchar * outputuri, GstEncodingProfile * prof) +{ + GstElement *pipeline; + GstElement *src; + GstElement *ebin; + GstElement *sink; + GstBus *bus; + GstCaps *profilecaps, *rescaps; + GMainLoop *mainloop; + + g_print (" Input URI : %s\n", uri); + g_print (" Output URI : %s\n", outputuri); + + sink = gst_element_make_from_uri (GST_URI_SINK, outputuri, "sink"); + if (G_UNLIKELY (sink == NULL)) { + g_print ("Can't create output sink, most likely invalid output URI !\n"); + return; + } + + src = gst_element_factory_make ("uridecodebin", NULL); + if (G_UNLIKELY (src == NULL)) { + g_print ("Can't create uridecodebin for input URI, aborting!\n"); + return; + } + + /* Figure out the streams that can be passed as-is to encodebin */ + g_object_get (src, "caps", &rescaps, NULL); + rescaps = gst_caps_copy (rescaps); + profilecaps = gst_encoding_profile_get_output_caps (prof); + gst_caps_append (rescaps, profilecaps); + + /* Set properties */ + g_object_set (src, "uri", uri, "caps", rescaps, NULL); + + ebin = gst_element_factory_make ("encodebin", NULL); + g_object_set (ebin, "profile", prof, NULL); + + g_signal_connect (src, "autoplug-continue", G_CALLBACK (autoplug_continue_cb), + ebin); + g_signal_connect (src, "pad-added", G_CALLBACK (pad_added_cb), ebin); + + pipeline = gst_pipeline_new ("encoding-pipeline"); + + gst_bin_add_many (GST_BIN (pipeline), src, ebin, sink, NULL); + + gst_element_link (ebin, sink); + + mainloop = g_main_loop_new (NULL, FALSE); + + bus = gst_pipeline_get_bus ((GstPipeline *) pipeline); + gst_bus_add_signal_watch (bus); + g_signal_connect (bus, "message", G_CALLBACK (bus_message_cb), mainloop); + + if (gst_element_set_state (pipeline, + GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { + g_print ("Failed to start the encoding\n"); + return; + } + + g_main_loop_run (mainloop); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); +} + +static gchar * +ensure_uri (gchar * location) +{ + gchar *res; + gchar *path; + + if (gst_uri_is_valid (location)) + return g_strdup (location); + + if (!g_path_is_absolute (location)) { + gchar *cur_dir; + cur_dir = g_get_current_dir (); + path = g_build_filename (cur_dir, location, NULL); + g_free (cur_dir); + } else + path = g_strdup (location); + + res = g_filename_to_uri (path, NULL, NULL); + g_free (path); + + return res; +} + +int +main (int argc, char **argv) +{ + GError *err = NULL; + gchar *outputuri = NULL; + gchar *format = NULL; + gchar *aformat = NULL; + gchar *vformat = NULL; + gboolean allmissing = FALSE; + gboolean listcodecs = FALSE; + GOptionEntry options[] = { + {"silent", 's', 0, G_OPTION_ARG_NONE, &silent, + "Don't output the information structure", NULL}, + {"outputuri", 'o', 0, G_OPTION_ARG_STRING, &outputuri, + "URI to encode to", "URI (://)"}, + {"format", 'f', 0, G_OPTION_ARG_STRING, &format, + "Container format", ""}, + {"vformat", 'v', 0, G_OPTION_ARG_STRING, &vformat, + "Video format", ""}, + {"aformat", 'a', 0, G_OPTION_ARG_STRING, &aformat, + "Audio format", ""}, + {"allmissing", 'm', 0, G_OPTION_ARG_NONE, &allmissing, + "encode to all matching format/codec that aren't specified", NULL}, + {"list-codecs", 'l', 0, G_OPTION_ARG_NONE, &listcodecs, + "list all available codecs and container formats", NULL}, + {NULL} + }; + GOptionContext *ctx; + GstEncodingProfile *prof; + gchar *inputuri; + + if (!g_thread_supported ()) + g_thread_init (NULL); + + ctx = g_option_context_new ("- encode URIs with GstProfile and encodebin"); + g_option_context_add_main_entries (ctx, options, NULL); + g_option_context_add_group (ctx, gst_init_get_option_group ()); + + if (!g_option_context_parse (ctx, &argc, &argv, &err)) { + g_print ("Error initializing: %s\n", err->message); + exit (1); + } + + if (listcodecs) { + list_codecs (); + g_option_context_free (ctx); + exit (0); + } + + if (outputuri == NULL || argc != 2) { + g_print ("%s", g_option_context_get_help (ctx, TRUE, NULL)); + g_option_context_free (ctx); + exit (-1); + } + + g_option_context_free (ctx); + + /* Fixup outputuri to be a URI */ + inputuri = ensure_uri (argv[1]); + outputuri = ensure_uri (outputuri); + + if (allmissing) { + GList *muxers; + GstCaps *formats = NULL; + GstCaps *vformats = NULL; + GstCaps *aformats = NULL; + guint f, v, a, flen, vlen, alen; + + if (!format) + formats = gst_caps_list_container_formats (GST_RANK_NONE); + else + formats = gst_caps_from_string (format); + + if (!vformat) + vformats = gst_caps_list_video_encoding_formats (GST_RANK_NONE); + else + vformats = gst_caps_from_string (vformat); + + if (!aformat) + aformats = gst_caps_list_audio_encoding_formats (GST_RANK_NONE); + else + aformats = gst_caps_from_string (aformat); + muxers = + gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_MUXER, + GST_RANK_NONE); + + flen = gst_caps_get_size (formats); + + for (f = 0; f < flen; f++) { + GstCaps *container = + gst_caps_new_full (gst_caps_steal_structure (formats, 0), NULL); + GstCaps *compatv = + gst_caps_list_compatible_codecs (container, vformats, muxers); + GstCaps *compata = + gst_caps_list_compatible_codecs (container, aformats, muxers); + + vlen = gst_caps_get_size (compatv); + alen = gst_caps_get_size (compata); + + + for (v = 0; v < vlen; v++) { + GstCaps *vcodec = + gst_caps_new_full (gst_structure_copy (gst_caps_get_structure + (compatv, v)), NULL); + for (a = 0; a < alen; a++) { + GstCaps *acodec = + gst_caps_new_full (gst_structure_copy (gst_caps_get_structure + (compata, a)), NULL); + + prof = + create_profile ((GstCaps *) container, (GstCaps *) vcodec, + (GstCaps *) acodec); + if (G_UNLIKELY (prof == NULL)) { + g_print ("Wrong arguments\n"); + break; + } + outputuri = + ensure_uri (generate_filename (container, vcodec, acodec)); + transcode_file (inputuri, outputuri, prof); + gst_encoding_profile_unref (prof); + + gst_caps_unref (acodec); + } + gst_caps_unref (vcodec); + } + gst_caps_unref (container); + } + + } else { + + /* Create the profile */ + prof = create_profile_from_string (format, vformat, aformat); + if (G_UNLIKELY (prof == NULL)) { + g_print ("Encoding arguments are not valid !\n"); + return 1; + } + + /* Trancode file */ + transcode_file (inputuri, outputuri, prof); + + /* cleanup */ + gst_encoding_profile_unref (prof); + + } + return 0; +} diff --git a/tests/examples/encoding/gstcapslist.c b/tests/examples/encoding/gstcapslist.c new file mode 100644 index 0000000000..4908e438c5 --- /dev/null +++ b/tests/examples/encoding/gstcapslist.c @@ -0,0 +1,286 @@ +/* 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; +} diff --git a/tests/examples/encoding/gstcapslist.h b/tests/examples/encoding/gstcapslist.h new file mode 100644 index 0000000000..fa0ed83bfe --- /dev/null +++ b/tests/examples/encoding/gstcapslist.h @@ -0,0 +1,35 @@ +/* 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 + +GstCaps *gst_caps_list_compatible_codecs (const GstCaps *containerformat, + GstCaps *codecformats, + GList *muxers); + +GstCaps *gst_caps_list_compatible_containers (GstCaps *mediaformat, + GList *containerformats); + + +GstCaps *gst_caps_list_container_formats (GstRank minrank); + +GstCaps *gst_caps_list_video_encoding_formats (GstRank minrank); + +GstCaps *gst_caps_list_audio_encoding_formats (GstRank minrank); +