static void
list_codecs (void)
{
    GstCaps *l, *caps;
    GstStructure *st;
    guint i, len;
    gchar *tmpstr, *desc;

    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++) {
        st = gst_caps_steal_structure (l, 0);
        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++) {
        st = gst_caps_steal_structure (l, 0);
        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++) {
        st = gst_caps_steal_structure (l, 0);
        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);
}
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 (<protocol>://<location>)"
        },
        {   "format", 'f', 0, G_OPTION_ARG_STRING, &format,
            "Container format", "<GstCaps>"
        },
        {   "vformat", 'v', 0, G_OPTION_ARG_STRING, &vformat,
            "Video format", "<GstCaps>"
        },
        {   "aformat", 'a', 0, G_OPTION_ARG_STRING, &aformat,
            "Audio format", "<GstCaps>"
        },
        {   "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;

    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;
        }

        /* Transcode file */
        transcode_file (inputuri, outputuri, prof);

        /* cleanup */
        gst_encoding_profile_unref (prof);

    }
    return 0;
}
/* creates/returns a list of CodecCap based on given filter function and caps */
static GList *
get_plugins_filtered_from_caps (FilterFunc filter,
                                GstCaps *caps,
                                GstPadDirection direction)
{
  GList *walk, *result;
  GList *list = NULL;
  GstCaps *matched_caps = NULL;

  result = gst_registry_get_feature_list (gst_registry_get (),
          GST_TYPE_ELEMENT_FACTORY);

  result = g_list_sort (result, (GCompareFunc) compare_ranks);

  for (walk = result; walk; walk = walk->next)
  {
    GstElementFactory *factory = GST_ELEMENT_FACTORY (walk->data);

    /* Ignore unranked plugins */
    if (gst_plugin_feature_get_rank (GST_PLUGIN_FEATURE (factory)) ==
        GST_RANK_NONE)
      continue;

    if (!filter (factory))
      continue;

    if (caps && !check_caps_compatibility (factory, caps, &matched_caps))
      continue;

    if (!matched_caps)
    {
      list = create_codec_cap_list (factory, direction, list, NULL);
    }
    else
    {
      gint i;
      GPtrArray *capslist = g_ptr_array_new_with_free_func (
        (GDestroyNotify) gst_caps_unref);

      while (gst_caps_get_size (matched_caps) > 0)
      {
        GstCaps *stolencaps = gst_caps_new_full (
          gst_caps_steal_structure (matched_caps, 0), NULL);
        gboolean got_match = FALSE;

        for (i = 0; i < capslist->len; i++)
        {
          GstCaps *intersect = gst_caps_intersect (stolencaps,
              g_ptr_array_index (capslist, i));

          if (gst_caps_is_empty (intersect))
          {
            gst_caps_unref (intersect);
          }
          else
          {
            got_match = TRUE;
            gst_caps_unref (g_ptr_array_index (capslist, i));
            g_ptr_array_index (capslist, i) = intersect;
          }
        }

        if (got_match)
          gst_caps_unref (stolencaps);
        else
          g_ptr_array_add (capslist, stolencaps);

      }
      gst_caps_unref (matched_caps);

      for (i = 0; i < capslist->len; i++)
        list = create_codec_cap_list (factory, direction, list,
            g_ptr_array_index (capslist, i));
      g_ptr_array_unref (capslist);
    }
  }

  gst_plugin_feature_list_free (result);

  return list;
}