pbutils: New Profile library
authorEdward Hervey <edward.hervey@collabora.co.uk>
Fri, 13 Aug 2010 15:27:52 +0000 (17:27 +0200)
committerEdward Hervey <edward.hervey@collabora.co.uk>
Wed, 15 Dec 2010 10:54:32 +0000 (11:54 +0100)
https://bugzilla.gnome.org/show_bug.cgi?id=627476

14 files changed:
docs/design/Makefile.am
docs/design/design-encoding.txt [new file with mode: 0644]
docs/libs/gst-plugins-base-libs-docs.sgml
docs/libs/gst-plugins-base-libs-sections.txt
docs/libs/gst-plugins-base-libs.types
gst-libs/gst/pbutils/Makefile.am
gst-libs/gst/pbutils/encoding-profile.c [new file with mode: 0644]
gst-libs/gst/pbutils/encoding-profile.h [new file with mode: 0644]
gst-libs/gst/pbutils/encoding-target.c [new file with mode: 0644]
gst-libs/gst/pbutils/encoding-target.h [new file with mode: 0644]
tests/check/Makefile.am
tests/check/libs/.gitignore
tests/check/libs/profile.c [new file with mode: 0644]
win32/common/libgstpbutils.def

index f2e0b71..357af4c 100644 (file)
@@ -4,6 +4,7 @@ SUBDIRS =
 EXTRA_DIST = \
        design-audiosinks.txt      \
        design-decodebin.txt       \
+       design-encoding.txt       \
        design-orc-integration.txt \
        draft-keyframe-force.txt   \
        draft-va.txt               \
diff --git a/docs/design/design-encoding.txt b/docs/design/design-encoding.txt
new file mode 100644 (file)
index 0000000..dda79ad
--- /dev/null
@@ -0,0 +1,571 @@
+Encoding and Muxing
+-------------------
+
+Summary
+-------
+ A. Problems
+ B. Goals
+ 1. EncodeBin
+ 2. Encoding Profile System
+ 3. Helper Library for Profiles
+ I. Use-cases researched
+
+
+A. Problems this proposal attempts to solve
+-------------------------------------------
+
+* Duplication of pipeline code for gstreamer-based applications
+  wishing to encode and or mux streams, leading to subtle differences
+  and inconsistencies accross those applications.
+
+* No unified system for describing encoding targets for applications
+  in a user-friendly way.
+
+* No unified system for creating encoding targets for applications,
+  resulting in duplication of code accross all applications,
+  differences and inconsistencies that come with that duplication,
+  and applications hardcoding element names and settings resulting in
+  poor portability.
+
+
+
+B. Goals
+--------
+
+1. Convenience encoding element
+
+  Create a convenience GstBin for encoding and muxing several streams,
+  hereafter called 'EncodeBin'.
+
+  This element will only contain one single property, which is a
+  profile.
+
+2. Define a encoding profile system
+
+2. Encoding profile helper library
+
+  Create a helper library to:
+  * create EncodeBin instances based on profiles, and
+  * help applications to create/load/save/browse those profiles.
+
+
+
+
+1. EncodeBin
+------------
+
+1.1 Proposed API
+----------------
+
+  EncodeBin is a GstBin subclass.
+
+  It implements the GstTagSetter interface, by which it will proxy the
+  calls to the muxer.
+
+  Only two introspectable property (i.e. usable without extra API):
+  * A GstEncodingProfile*
+  * The name of the profile to use
+
+  When a profile is selected, encodebin will:
+  * Add REQUEST sinkpads for all the GstStreamProfile
+  * Create the muxer and expose the source pad
+
+  Whenever a request pad is created, encodebin will:
+  * Create the chain of elements for that pad
+  * Ghost the sink pad
+  * Return that ghost pad
+
+  This allows reducing the code to the minimum for applications
+  wishing to encode a source for a given profile:
+
+  ...
+
+  encbin = gst_element_factory_make("encodebin, NULL);
+  g_object_set (encbin, "profile", "N900/H264 HQ", NULL);
+  gst_element_link (encbin, filesink);
+
+  ...
+
+  vsrcpad = gst_element_get_src_pad(source, "src1");
+  vsinkpad = gst_element_get_request_pad (encbin, "video_%d");
+  gst_pad_link(vsrcpad, vsinkpad);
+
+  ...
+
+
+1.2 Explanation of the Various stages in EncodeBin
+--------------------------------------------------
+
+  This describes the various stages which can happen in order to end
+  up with a multiplexed stream that can then be stored or streamed.
+
+1.2.1 Incoming streams
+
+  The streams fed to EncodeBin can be of various types:
+
+  * Video
+   * Uncompressed (but maybe subsampled)
+   * Compressed
+  * Audio
+   * Uncompressed (audio/x-raw-{int|float})
+   * Compressed
+  * Timed text
+  * Private streams
+
+
+1.2.2 Steps involved for raw video encoding
+
+(0) Incoming Stream
+
+(1) Transform raw video feed (optional)
+
+ Here we modify the various fundamental properties of a raw video
+ stream to be compatible with the intersection of:
+  * The encoder GstCaps and
+  * The specified "Stream Restriction" of the profile/target
+
+ The fundamental properties that can be modified are:
+  * width/height
+    This is done with a video scaler.
+    The DAR (Display Aspect Ratio) MUST be respected.
+    If needed, black borders can be added to comply with the target DAR.
+  * framerate
+  * format/colorspace/depth
+    All of this is done with a colorspace converter
+
+(2) Actual encoding (optional for raw streams)
+
+ An encoder (with some optional settings) is used.
+
+(3) Muxing
+
+ A muxer (with some optional settings) is used.
+
+(4) Outgoing encoded and muxed stream
+
+
+1.2.3 Steps involved for raw audio encoding
+
+ This is roughly the same as for raw video, expect for (1)
+
+(1) Transform raw audo feed (optional)
+
+ We modify the various fundamental properties of a raw audio stream to
+ be compatible with the intersection of:
+  * The encoder GstCaps and
+  * The specified "Stream Restriction" of the profile/target
+
+ The fundamental properties that can be modifier are:
+ * Number of channels
+ * Type of raw audio (integer or floating point)
+ * Depth (number of bits required to encode one sample)
+
+
+1.2.4 Steps involved for encoded audio/video streams
+
+ Steps (1) and (2) are replaced by a parser if a parser is available
+ for the given format.
+
+
+1.2.5 Steps involved for other streams
+
+ Other streams will just be forwarded as-is to the muxer, provided the
+ muxer accepts the stream type.
+
+
+
+2. Encoding Profile System
+--------------------------
+
+ This work is based on:
+ * The existing GstPreset system for elements [0]
+ * The gnome-media GConf audio profile system [1]
+ * The investigation done into device profiles by Arista and
+ Transmageddon [2 and 3]
+
+2.2 Terminology
+---------------
+
+* Encoding Target Category
+  A Target Category is a classification of devices/systems/use-cases
+  for encoding.
+
+  Such a classification is required in order for:
+  * Applications with a very-specific use-case to limit the number of
+    profiles they can offer the user. A screencasting application has
+    no use with the online services targets for example. 
+  * Offering the user some initial classification in the case of a
+    more generic encoding application (like a video editor or a
+    transcoder). 
+
+  Ex:
+   Consumer devices
+   Online service
+   Intermediate Editing Format
+   Screencast
+   Capture
+   Computer
+
+* Encoding Profile Target
+  A Profile Target describes a specific entity for which we wish to
+  encode.
+  A Profile Target must belong to at least one Target Category.
+  It will define at least one Encoding Profile.
+
+  Ex (with category):
+   Nokia N900 (Consumer device)
+   Sony PlayStation 3 (Consumer device)
+   Youtube (Online service)
+   DNxHD (Intermediate editing format)
+   HuffYUV (Screencast)
+   Theora (Computer)
+
+* Encoding Profile
+  A specific combination of muxer, encoders, presets and limitations.
+
+  Ex:
+   Nokia N900/H264 HQ
+   Ipod/High Quality
+   DVD/Pal
+   Youtube/High Quality
+   HTML5/Low Bandwith
+   DNxHD
+
+2.3 Encoding Profile
+--------------------
+
+An encoding profile requires the following information:
+
+ * Name
+   This string is not translatable and must be unique.
+   A recommendation to guarantee uniqueness of the naming could be:
+      <target>/<name>
+ * Description
+   This is a translatable string describing the profile
+ * Muxing format
+   This is a string containing the GStreamer media-type of the
+   container format.
+ * Muxing preset
+   This is an optional string describing the preset(s) to use on the
+   muxer.
+ * Multipass setting
+   This is a boolean describing whether the profile requires several
+   passes.
+ * List of Stream Profile
+
+2.3.1 Stream Profiles
+
+A Stream Profile consists of:
+
+ * Type
+   The type of stream profile (audio, video, text, private-data)
+ * Encoding Format
+   This is a string containing the GStreamer media-type of the encoding
+   format to be used. If encoding is not to be applied, the raw audio
+   media type will be used.
+ * Encoding preset
+   This is an optional string describing the preset(s) to use on the
+   encoder.
+ * Restriction
+   This is an optional GstCaps containing the restriction of the
+   stream that can be fed to the encoder.
+   This will generally containing restrictions in video
+   width/heigh/framerate or audio depth.
+ * presence
+   This is an integer specifying how many streams can be used in the
+   containing profile. 0 means that any number of streams can be
+   used.
+ * pass
+   This is an integer which is only meaningful if the multipass flag
+   has been set in the profile. If it has been set it indicates which
+   pass this Stream Profile corresponds to.
+2.4 Example profile
+-------------------
+
+The representation used here is XML only as an example. No decision is
+made as to which formatting to use for storing targets and profiles.
+
+<gst-encoding-target>
+  <name>Nokia N900</name>
+  <category>Consumer Device</category>
+  <profiles>
+    <profile>Nokia N900/H264 HQ</profile>
+    <profile>Nokia N900/MP3</profile>
+    <profile>Nokia N900/AAC</profile>
+  </profiles>
+</gst-encoding-target>
+
+<gst-encoding-profile>
+  <name>Nokia N900/H264 HQ</name>
+  <description>
+    High Quality H264/AAC for the Nokia N900
+  </description>
+  <format>video/quicktime,variant=iso</format>
+  <streams>
+    <stream-profile>
+      <type>audio</type>
+      <format>audio/mpeg,mpegversion=4</format>
+      <preset>Quality High/Main</preset>
+      <restriction>audio/x-raw-int,channels=[1,2]</restriction>
+      <presence>1</presence>
+    </stream-profile>
+    <stream-profile>
+      <type>video</type>
+      <format>video/x-h264</format>
+      <preset>Profile Baseline/Quality High</preset>
+      <restriction>
+        video/x-raw-yuv,width=[16, 800],\
+       height=[16, 480],framerate=[1/1, 30000/1001]
+      </restriction>
+      <presence>1</presence>
+    </stream-profile>
+  </streams>
+  
+</gst-encoding-profile>
+
+2.5 API
+-------
+  A proposed C API is contained in the gstprofile.h file in this directory.
+
+
+2.6 Modifications required in the existing GstPreset system
+-----------------------------------------------------------
+
+2.6.1. Temporary preset.
+
+  Currently a preset needs to be saved on disk in order to be
+  used.
+
+  This makes it impossible to have temporary presets (that exist only
+  during the lifetime of a process), which might be required in the
+  new proposed profile system
+
+2.6.2 Categorisation of presets.
+
+  Currently presets are just aliases of a group of property/value
+  without any meanings or explanation as to how they exclude each
+  other.
+
+  Take for example the H264 encoder. It can have presets for:
+  * passes (1,2 or 3 passes)
+  * profiles (Baseline, Main, ...)
+  * quality (Low, medium, High)
+
+  In order to programmatically know which presets exclude each other,
+  we here propose the categorisation of these presets.
+
+  This can be done in one of two ways
+  1. in the name (by making the name be [<category>:]<name>)
+    This would give for example: "Quality:High", "Profile:Baseline"
+  2. by adding a new _meta key
+    This would give for example: _meta/category:quality
+
+2.6.3 Aggregation of presets.
+
+  There can be more than one choice of presets to be done for an
+  element (quality, profile, pass).
+
+  This means that one can not currently describe the full
+  configuration of an element with a single string but with many.
+
+  The proposal here is to extend the GstPreset API to be able to set
+  all presets using one string and a well-known separator ('/').
+
+  This change only requires changes in the core preset handling code.
+
+  This would allow doing the following:
+  gst_preset_load_preset (h264enc,
+                          "pass:1/profile:baseline/quality:high");
+
+2.7 Points to be determined
+---------------------------
+
+  This document hasn't determined yet how to solve the following
+  problems:
+
+2.7.1 Storage of profiles
+
+  One proposal for storage would be to use a system wide directory
+  (like $prefix/share/gstreamer-0.10/profiles) and store XML files for
+  every individual profiles.
+
+  Users could then add their own profiles in ~/.gstreamer-0.10/profiles
+
+  This poses some limitations as to what to do if some applications
+  want to have some profiles limited to their own usage.
+
+
+3. Helper library for profiles
+------------------------------
+
+ These helper methods could also be added to existing libraries (like
+ GstPreset, GstPbUtils, ..).
+
+ The various API proposed are in the accompanying gstprofile.h file.
+
+3.1 Getting user-readable names for formats
+
+ This is already provided by GstPbUtils.
+
+3.2 Hierarchy of profiles
+
+ The goal is for applications to be able to present to the user a list
+ of combo-boxes for choosing their output profile:
+
+ [      Category      ]       # optional, depends on the application
+ [    Device/Site/..  ]       # optional, depends on the application
+ [      Profile       ]
+
+ Convenience methods are offered to easily get lists of categories,
+ devices, and profiles.
+
+3.3 Creating Profiles
+
+ The goal is for applications to be able to easily create profiles.
+
+ The applications needs to be able to have a fast/efficient way to:
+ * select a container format and see all compatible streams he can use
+ with it.
+ * select a codec format and see which container formats he can use
+ with it.
+
+ The remaining parts concern the restrictions to encoder
+ input.
+
+3.4 Ensuring availability of plugins for Profiles
+
+ When an application wishes to use a Profile, it should be able to
+ query whether it has all the needed plugins to use it.
+
+ This part will use GstPbUtils to query, and if needed install the
+ missing plugins through the installed distribution plugin installer.
+
+
+I. Use-cases researched
+-----------------------
+
+ This is a list of various use-cases where encoding/muxing is being
+ used.
+
+* Transcoding
+
+  The goal is to convert with as minimal loss of quality any input
+  file for a target use.
+  A specific variant of this is transmuxing (see below).
+
+  Example applications: Arista, Transmageddon
+
+* Rendering timelines
+
+  The incoming streams are a collection of various segments that need
+  to be rendered.
+  Those segments can vary in nature (i.e. the video width/height can
+  change).
+  This requires the use of identiy with the single-segment property
+  activated to transform the incoming collection of segments to a
+  single continuous segment.
+
+  Example applications: PiTiVi, Jokosher
+
+* Encoding of live sources
+
+  The major risk to take into account is the encoder not encoding the
+  incoming stream fast enough. This is outside of the scope of
+  encodebin, and should be solved by using queues between the sources
+  and encodebin, as well as implementing QoS in encoders and sources
+  (the encoders emitting QoS events, and the upstream elements
+  adapting themselves accordingly).
+
+  Example applications: camerabin, cheese
+
+* Screencasting applications
+
+  This is similar to encoding of live sources.
+  The difference being that due to the nature of the source (size and
+  amount/frequency of updates) one might want to do the encoding in
+  two parts:
+  * The actual live capture is encoded with a 'almost-lossless' codec
+  (such as huffyuv)
+  * Once the capture is done, the file created in the first step is
+  then rendered to the desired target format.
+
+  Fixing sources to only emit region-updates and having encoders
+  capable of encoding those streams would fix the need for the first
+  step but is outside of the scope of encodebin.
+
+  Example applications: Istanbul, gnome-shell, recordmydesktop
+
+* Live transcoding
+
+  This is the case of an incoming live stream which will be
+  broadcasted/transmitted live.
+  One issue to take into account is to reduce the encoding latency to
+  a minimum. This should mostly be done by picking low-latency
+  encoders.
+
+  Example applications: Rygel, Coherence
+
+* Transmuxing
+
+  Given a certain file, the aim is to remux the contents WITHOUT
+  decoding into either a different container format or the same
+  container format.
+  Remuxing into the same container format is useful when the file was
+  not created properly (for example, the index is missing).
+  Whenever available, parsers should be applied on the encoded streams
+  to validate and/or fix the streams before muxing them.
+
+  Metadata from the original file must be kept in the newly created
+  file.
+
+  Example applications: Arista, Transmaggedon
+
+* Loss-less cutting
+
+  Given a certain file, the aim is to extract a certain part of the
+  file without going through the process of decoding and re-encoding
+  that file.
+  This is similar to the transmuxing use-case.
+
+  Example applications: PiTiVi, Transmageddon, Arista, ...
+
+* Multi-pass encoding
+
+  Some encoders allow doing a multi-pass encoding.
+  The initial pass(es) are only used to collect encoding estimates and
+  are not actually muxed and outputted.
+  The final pass uses previously collected information, and the output
+  is then muxed and outputted.
+
+* Archiving and intermediary format
+
+  The requirement is to have lossless
+
+* CD ripping
+
+  Example applications: Sound-juicer
+
+* DVD ripping
+
+  Example application: Thoggen
+
+
+
+* Research links
+
+  Some of these are still active documents, some other not
+
+[0] GstPreset API documentation
+    http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPreset.html
+
+[1] gnome-media GConf profiles
+    http://www.gnome.org/~bmsmith/gconf-docs/C/gnome-media.html
+
+[2] Research on a Device Profile API
+    http://gstreamer.freedesktop.org/wiki/DeviceProfile
+
+[3] Research on defining presets usage
+    http://gstreamer.freedesktop.org/wiki/PresetDesign
+
index 94a3451..b7b61a7 100644 (file)
       <xi:include href="xml/gstpbutilsmissingplugins.xml" />
       <xi:include href="xml/gstpbutilsinstallplugins.xml" />
       <xi:include href="xml/gstdiscoverer.xml" />
+      <xi:include href="xml/encoding-profile.xml" />
     </chapter>
 
     <chapter id="gstreamer-video">
index aff1cdb..da6134b 100644 (file)
@@ -1907,6 +1907,91 @@ gst_codec_utils_mpeg4video_get_level
 gst_codec_utils_mpeg4video_caps_set_level_and_profile
 </SECTION>
 
+<SECTION>
+<FILE>encoding-profile</FILE>
+<INCLUDE>gst/pbutils/encoding-profile.h</INCLUDE>
+GstEncodingProfile
+gst_encoding_profile_unref
+gst_encoding_profile_ref
+gst_encoding_profile_get_name
+gst_encoding_profile_get_description
+gst_encoding_profile_get_format
+gst_encoding_profile_get_preset
+gst_encoding_profile_get_presence
+gst_encoding_profile_get_restriction
+gst_encoding_profile_set_name
+gst_encoding_profile_set_description
+gst_encoding_profile_set_format
+gst_encoding_profile_set_preset
+gst_encoding_profile_set_restriction
+gst_encoding_profile_set_presence
+gst_encoding_profile_is_equal
+gst_encoding_profile_get_output_caps
+gst_encoding_profile_get_type_nick
+<SUBSECTION container>
+GstEncodingContainerProfile
+gst_encoding_container_profile_new
+gst_encoding_container_profile_add_profile
+gst_encoding_container_profile_contains_profile
+gst_encoding_container_profile_get_profiles
+<SUBSECTION audio>
+GstEncodingAudioProfile
+gst_encoding_audio_profile_new
+<SUBSECTION video>
+GstEncodingVideoProfile
+gst_encoding_video_profile_new
+gst_encoding_video_profile_get_pass
+gst_encoding_video_profile_get_variableframerate
+gst_encoding_video_profile_set_pass
+gst_encoding_video_profile_set_variableframerate
+<SUBSECTION targets>
+GST_ENCODING_CATEGORY_DEVICE
+GST_ENCODING_CATEGORY_ONLINE_SERVICE
+GST_ENCODING_CATEGORY_STORAGE_EDITING
+GST_ENCODING_CATEGORY_CAPTURE
+GstEncodingTarget
+gst_encoding_target_unref
+gst_encoding_target_ref
+gst_encoding_target_new
+gst_encoding_target_get_name
+gst_encoding_target_get_category
+gst_encoding_target_get_description
+gst_encoding_target_get_profiles
+gst_encoding_target_add_profile
+gst_encoding_target_save
+gst_encoding_target_save_to
+gst_encoding_target_load
+gst_encoding_target_load_from
+<SUBSECTION Standard>
+GST_ENCODING_PROFILE
+GST_IS_ENCODING_PROFILE
+GST_TYPE_ENCODING_PROFILE
+gst_encoding_profile_get_type
+GST_ENCODING_TARGET
+GST_IS_ENCODING_TARGET
+GST_TYPE_ENCODING_TARGET
+gst_encoding_target_get_type
+GstEncodingProfileClass
+GST_TYPE_ENCODING_CONTAINER_PROFILE
+GST_ENCODING_CONTAINER_PROFILE
+gst_encoding_container_profile_get_type
+GST_TYPE_ENCODING_VIDEO_PROFILE
+GST_ENCODING_VIDEO_PROFILE
+GST_IS_ENCODING_VIDEO_PROFILE
+GstEncodingVideoProfileClass
+gst_encoding_video_profile_get_type
+GST_TYPE_ENCODING_AUDIO_PROFILE
+GST_ENCODING_AUDIO_PROFILE
+GST_IS_ENCODING_AUDIO_PROFILE
+GstEncodingAudioProfileClass
+gst_encoding_audio_profile_get_type
+GST_IS_ENCODING_CONTAINER_PROFILE
+GstEncodingContainerProfileClass
+GstEncodingTargetClass
+</SECTION>
+
+
+
 # video
 
 <SECTION>
index db3818a..f6c06af 100644 (file)
@@ -59,3 +59,14 @@ gst_video_sink_get_type
 
 #include <gst/pbutils/pbutils.h>
 gst_discoverer_get_type
+
+#include <gst/pbutils/encoding-profile.h>
+#include <gst/pbutils/encoding-target.h>
+gst_encoding_profile_get_type
+gst_encoding_video_profile_get_type
+gst_encoding_video_profile_get_type
+gst_encoding_audio_profile_get_type
+gst_encoding_container_profile_get_type
+gst_encoding_target_get_type
+
+
index 9a261f5..73251e1 100644 (file)
@@ -4,6 +4,8 @@ headers_pbutils = \
        pbutils.h         \
        codec-utils.h     \
        descriptions.h    \
+       encoding-profile.h      \
+       encoding-target.h       \
        install-plugins.h \
        missing-plugins.h \
        gstdiscoverer.h
@@ -22,6 +24,8 @@ libgstpbutils_@GST_MAJORMINOR@_la_SOURCES = \
        pbutils.c         \
        codec-utils.c     \
        descriptions.c    \
+       encoding-profile.c      \
+       encoding-target.c       \
        install-plugins.c \
        missing-plugins.c \
        gstdiscoverer.c   \
diff --git a/gst-libs/gst/pbutils/encoding-profile.c b/gst-libs/gst/pbutils/encoding-profile.c
new file mode 100644 (file)
index 0000000..8c364c8
--- /dev/null
@@ -0,0 +1,834 @@
+/* GStreamer encoding profiles library
+ * Copyright (C) 2009-2010 Edward Hervey <edward.hervey@collabora.co.uk>
+ *           (C) 2009-2010 Nokia Corporation
+ *
+ * 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.
+ */
+
+/**
+ * SECTION:encoding-profile
+ * @short_description: Encoding profile library
+ *
+ * <refsect2>
+ * <para>
+ * Functions to create and handle encoding profiles.
+ * </para>
+ * <para>
+ * Encoding profiles describe the media types and settings one wishes to use for
+ * an encoding process. The top-level profiles are commonly
+ * #GstEncodingContainerProfile(s) (which contains user-readable name and 
+ * description along with which container format to use) which references one or
+ * more #GstEncodingProfile(s) which indicate which encoding format should be
+ * used on each individual streams.
+ * </para>
+ * <para>
+ * #GstEncodingProfile(s) can be provided to the 'encodebin' element, which will take
+ * care of selecting and setting up the required elements to produce an output stream
+ * conforming to the specifications of the profile.
+ * </para>
+ * <para>
+ * Unlike other systems, the encoding profiles do not specify which #GstElement to use
+ * for the various encoding and muxing steps, but instead relies on specifying the format
+ * one wishes to use.
+ * </para>
+ * <para>
+ * Encoding profiles can be created at runtime by the application or loaded from (and saved
+ * to) file using the #GstEncodingTarget API.
+ * </para>
+ * </refsect2>
+ * <refsect2>
+ * <title>Example: Creating a profile</title>
+ * <para>
+ * |[
+ * #include <gst/pbutils/encoding-profile.h>
+ * ...
+ * GstEncodingProfile *
+ * create_ogg_theora_profile(void)
+ *{
+ *  GstEncodingContainerProfile *prof;
+ *  GstCaps *caps;
+ *
+ *  caps = gst_caps_from_string("application/ogg");
+ *  prof = gst_encoding_container_profile_new("Ogg audio/video",
+ *     "Standard OGG/THEORA/VORBIS",
+ *     caps, NULL);
+ *  gst_caps_unref (caps);
+ *
+ *  caps = gst_caps_from_string("video/x-theora");
+ *  sprof = gst_encoding_container_profile_add_profile(
+ *       (GstEncodingProfile*) gst_encoding_video_profile_new(caps, NULL, NULL, 0));
+ *  gst_caps_unref (caps);
+ *
+ *  caps = gst_caps_from_string("audio/x-vorbis");
+ *  sprof = gst_encoding_container_profile_add_profile(
+ *       (GstEncodingProfile*) gst_encoding_audio_profile_new(caps, NULL, NULL, 0));
+ *  gst_caps_unref (caps);
+ *
+ *  return (GstEncodingProfile*) prof;
+ *}
+ *
+ *
+ * ]|
+ * </para>
+ * </refsect2>
+ * <refsect2>
+ * <title>Example: Loading a profile from disk</title>
+ * <para>
+ * |[
+ * #include <gst/pbutils/encoding-profile.h>
+ * ...
+ *GstEncodingProfile *
+ *get_ogg_theora_profile(const gchar *path, const gchar *profilename)
+ *{
+ *  GstEncodingProfile *prof = NULL;
+ *  GstEncodingTarget *target = NULL;
+ *  GList *tmp;
+ *
+ *  target = gst_encoding_target_load_from (path);
+ *  if (target == NULL)
+ *    return NULL;
+ *
+ *  for (tmp = target->profiles; tmp; tmp = tmp->next) {
+ *    GstEncodingProfile *ptmp = (GstEncodingProfile*) tmp->data;
+ *
+ *    if (!strcmp(gst_encoding_profile_get_name(ptmp), profilename)) {
+ *      prof = ptmp;
+ *      break;
+ *    }
+ *  }
+ *
+ *  return prof;
+ *}
+ * ]|
+ * </para>
+ * </refsect2>
+ *
+ * Since: 0.10.32
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "encoding-profile.h"
+
+/* GstEncodingProfile API */
+
+struct _GstEncodingProfile
+{
+  GstMiniObject parent;
+
+  /*< public > */
+  gchar *name;
+  gchar *description;
+  GstCaps *format;
+  gchar *preset;
+  guint presence;
+  GstCaps *restriction;
+};
+
+G_DEFINE_TYPE (GstEncodingProfile, gst_encoding_profile, GST_TYPE_MINI_OBJECT);
+
+static void
+gst_encoding_profile_init (GstEncodingProfile * prof)
+{
+  /* Nothing to initialize */
+}
+
+static void
+gst_encoding_profile_finalize (GstEncodingProfile * prof)
+{
+  if (prof->name)
+    g_free (prof->name);
+  if (prof->format)
+    gst_caps_unref (prof->format);
+  if (prof->preset)
+    g_free (prof->preset);
+  if (prof->description)
+    g_free (prof->description);
+  if (prof->restriction)
+    gst_caps_unref (prof->restriction);
+}
+
+static void
+gst_encoding_profile_class_init (GstMiniObjectClass * klass)
+{
+  klass->finalize =
+      (GstMiniObjectFinalizeFunction) gst_encoding_profile_finalize;
+}
+
+/**
+ * gst_encoding_profile_get_name:
+ * @profile: a #GstEncodingProfile
+ *
+ * Since: 0.10.32
+ *
+ * Returns: the name of the profile, can be %NULL.
+ */
+const gchar *
+gst_encoding_profile_get_name (GstEncodingProfile * profile)
+{
+  return profile->name;
+}
+
+/**
+ * gst_encoding_profile_get_description:
+ * @profile: a #GstEncodingProfile
+ *
+ * Since: 0.10.32
+ *
+ * Returns: the description of the profile, can be %NULL.
+ */
+const gchar *
+gst_encoding_profile_get_description (GstEncodingProfile * profile)
+{
+  return profile->description;
+}
+
+/**
+ * gst_encoding_profile_get_format:
+ * @profile: a #GstEncodingProfile
+ *
+ * Since: 0.10.32
+ *
+ * Returns: the media format used in the profile.
+ */
+const GstCaps *
+gst_encoding_profile_get_format (GstEncodingProfile * profile)
+{
+  return profile->format;
+}
+
+/**
+ * gst_encoding_profile_get_preset:
+ * @profile: a #GstEncodingProfile
+ *
+ * Since: 0.10.32
+ *
+ * Returns: the preset to be used in the profile.
+ */
+const gchar *
+gst_encoding_profile_get_preset (GstEncodingProfile * profile)
+{
+  return profile->preset;
+}
+
+/**
+ * gst_encoding_profile_get_presence:
+ * @profile: a #GstEncodingProfile
+ *
+ * Since: 0.10.32
+ *
+ * Returns: The number of time the profile is used in its parent
+ * container profile. If 0, it is not a mandatory stream
+ */
+const guint
+gst_encoding_profile_get_presence (GstEncodingProfile * profile)
+{
+  return profile->presence;
+}
+
+/**
+ * gst_encoding_profile_get_restriction:
+ * @profile: a #GstEncodingProfile
+ *
+ * Since: 0.10.32
+ *
+ * Returns: The restriction #GstCaps to apply before the encoder
+ * that will be used in the profile. Does not apply to #GstEncodingContainerProfile.
+ * Can be %NULL.
+ */
+const GstCaps *
+gst_encoding_profile_get_restriction (GstEncodingProfile * profile)
+{
+  return profile->restriction;
+}
+
+/**
+ * gst_encoding_profile_set_name:
+ * @profile: a #GstEncodingProfile
+ * @name: the name to set on the profile
+ *
+ * Since: 0.10.32
+ *
+ * Set @name as the given name for the @profile. A copy of @name will be made
+ * internally.
+ */
+void
+gst_encoding_profile_set_name (GstEncodingProfile * profile, const gchar * name)
+{
+  if (profile->name)
+    g_free (profile->name);
+  profile->name = g_strdup (name);
+}
+
+/**
+ * gst_encoding_profile_set_description:
+ * @profile: a #GstEncodingProfile
+ * @description: the description to set on the profile
+ *
+ * Since: 0.10.32
+ *
+ * Set @description as the given description for the @profile. A copy of @description will be made
+ * internally.
+ */
+void
+gst_encoding_profile_set_description (GstEncodingProfile * profile,
+    const gchar * description)
+{
+  if (profile->description)
+    g_free (profile->description);
+  profile->description = g_strdup (description);
+}
+
+/**
+ * gst_encoding_profile_set_format:
+ * @profile: a #GstEncodingProfile
+ * @format: the media format to use in the profile.
+ *
+ * Since: 0.10.32
+ *
+ * Sets the media format used in the profile.
+ */
+void
+gst_encoding_profile_set_format (GstEncodingProfile * profile, GstCaps * format)
+{
+  if (profile->format)
+    gst_caps_unref (profile->format);
+  profile->format = gst_caps_ref (format);
+}
+
+/**
+ * gst_encoding_profile_set_preset:
+ * @profile: a #GstEncodingProfile
+ * @preset: the element preset to use
+ *
+ * Since: 0.10.32
+ *
+ * Sets the preset to use for the profile.
+ */
+void
+gst_encoding_profile_set_preset (GstEncodingProfile * profile,
+    const gchar * preset)
+{
+  if (profile->preset)
+    g_free (profile->preset);
+  profile->preset = g_strdup (preset);
+}
+
+/**
+ * gst_encoding_profile_set_presence:
+ * @profile: a #GstEncodingProfile
+ * @presence: the number of time the profile can be used
+ *
+ * Since: 0.10.32
+ *
+ * Set the number of time the profile is used in its parent
+ * container profile. If 0, it is not a mandatory stream
+ */
+void
+gst_encoding_profile_set_presence (GstEncodingProfile * profile, guint presence)
+{
+  profile->presence = presence;
+}
+
+/**
+ * gst_encoding_profile_set_restriction:
+ * @profile: a #GstEncodingProfile
+ * @restriction: the restriction to apply
+ *
+ * Since: 0.10.32
+ *
+ * Set the restriction #GstCaps to apply before the encoder
+ * that will be used in the profile. Does not apply to #GstEncodingContainerProfile.
+ */
+void
+gst_encoding_profile_set_restriction (GstEncodingProfile * profile,
+    GstCaps * restriction)
+{
+  if (profile->restriction)
+    gst_caps_unref (profile->restriction);
+  profile->restriction = restriction;
+}
+
+/* Container profiles */
+
+struct _GstEncodingContainerProfile
+{
+  GstEncodingProfile parent;
+
+  GList *encodingprofiles;
+};
+
+G_DEFINE_TYPE (GstEncodingContainerProfile, gst_encoding_container_profile,
+    GST_TYPE_ENCODING_PROFILE);
+
+static void
+gst_encoding_container_profile_init (GstEncodingContainerProfile * prof)
+{
+  /* Nothing to initialize */
+}
+
+static void
+gst_encoding_container_profile_finalize (GstEncodingContainerProfile * prof)
+{
+  g_list_foreach (prof->encodingprofiles, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (prof->encodingprofiles);
+
+  GST_MINI_OBJECT_CLASS (gst_encoding_container_profile_parent_class)->finalize
+      ((GstMiniObject *) prof);
+}
+
+static void
+gst_encoding_container_profile_class_init (GstMiniObjectClass * klass)
+{
+  klass->finalize =
+      (GstMiniObjectFinalizeFunction) gst_encoding_container_profile_finalize;
+}
+
+const GList *
+gst_encoding_container_profile_get_profiles (GstEncodingContainerProfile *
+    profile)
+{
+  return profile->encodingprofiles;
+}
+
+/* Video profiles */
+
+struct _GstEncodingVideoProfile
+{
+  GstEncodingProfile parent;
+
+  guint pass;
+  gboolean variableframerate;
+};
+
+G_DEFINE_TYPE (GstEncodingVideoProfile, gst_encoding_video_profile,
+    GST_TYPE_ENCODING_PROFILE);
+
+static void
+gst_encoding_video_profile_init (GstEncodingVideoProfile * prof)
+{
+  /* Nothing to initialize */
+}
+
+static void
+gst_encoding_video_profile_class_init (GstMiniObjectClass * klass)
+{
+}
+
+/**
+ * gst_encoding_video_profile_get_pass:
+ * @prof: a #GstEncodingVideoProfile
+ *
+ * Since: 0.10.32
+ *
+ * Returns: The pass number if this is part of a multi-pass profile. Starts at
+ * 1 for multi-pass. 0 if this is not a multi-pass profile
+ **/
+guint
+gst_encoding_video_profile_get_pass (GstEncodingVideoProfile * prof)
+{
+  return prof->pass;
+}
+
+/**
+ * gst_encoding_video_profile_get_variableframerate:
+ * @prof: a #GstEncodingVideoProfile
+ *
+ * Since: 0.10.32
+ *
+ * Returns: Whether non-constant video framerate is allowed for encoding.
+ */
+gboolean
+gst_encoding_video_profile_get_variableframerate (GstEncodingVideoProfile *
+    prof)
+{
+  return prof->variableframerate;
+}
+
+/**
+ * gst_encoding_video_profile_set_pass:
+ * @prof: a #GstEncodingVideoProfile
+ * @pass: the pass number for this profile
+ *
+ * Since: 0.10.32
+ *
+ * Sets the pass number of this video profile. The first pass profile should have
+ * this value set to 1. If this video profile isn't part of a multi-pass profile,
+ * you may set it to 0 (the default value).
+ */
+void
+gst_encoding_video_profile_set_pass (GstEncodingVideoProfile * prof, guint pass)
+{
+  prof->pass = pass;
+}
+
+/**
+ * gst_encoding_video_profile_set_variableframerate:
+ * @prof: a #GstEncodingVideoProfile
+ * @variableframerate: a boolean
+ *
+ * Since: 0.10.32
+ *
+ * If set to %TRUE, then the incoming streamm will be allowed to have non-constant
+ * framerate. If set to %FALSE (default value), then the incoming stream will
+ * be normalized by dropping/duplicating frames in order to produce a
+ * constance framerate.
+ */
+void
+gst_encoding_video_profile_set_variableframerate (GstEncodingVideoProfile *
+    prof, gboolean variableframerate)
+{
+  prof->variableframerate = variableframerate;
+}
+
+/* Audio profiles */
+
+struct _GstEncodingAudioProfile
+{
+  GstEncodingProfile parent;
+};
+
+G_DEFINE_TYPE (GstEncodingAudioProfile, gst_encoding_audio_profile,
+    GST_TYPE_ENCODING_PROFILE);
+
+static void
+gst_encoding_audio_profile_init (GstEncodingAudioProfile * prof)
+{
+  /* Nothing to initialize */
+}
+
+static void
+gst_encoding_audio_profile_class_init (GstMiniObjectClass * klass)
+{
+}
+
+static inline gboolean
+_gst_caps_is_equal_safe (GstCaps * a, GstCaps * b)
+{
+  if (a == b)
+    return TRUE;
+  if ((a == NULL) || (b == NULL))
+    return FALSE;
+  return gst_caps_is_equal (a, b);
+}
+
+static gint
+_compare_container_encoding_profiles (GstEncodingContainerProfile * ca,
+    GstEncodingContainerProfile * cb)
+{
+  GList *tmp;
+
+  if (g_list_length (ca->encodingprofiles) !=
+      g_list_length (cb->encodingprofiles))
+    return -1;
+
+  for (tmp = ca->encodingprofiles; tmp; tmp = tmp->next) {
+    GstEncodingProfile *prof = (GstEncodingProfile *) tmp->data;
+    if (!gst_encoding_container_profile_contains_profile (ca, prof))
+      return -1;
+  }
+
+  return 0;
+}
+
+static gint
+_compare_encoding_profiles (const GstEncodingProfile * a,
+    const GstEncodingProfile * b)
+{
+  if ((G_TYPE_FROM_INSTANCE (a) != G_TYPE_FROM_INSTANCE (b)) ||
+      !_gst_caps_is_equal_safe (a->format, b->format) ||
+      (g_strcmp0 (a->preset, b->preset) != 0) ||
+      (g_strcmp0 (a->name, b->name) != 0) ||
+      (g_strcmp0 (a->description, b->description) != 0))
+    return -1;
+
+  if (GST_IS_ENCODING_CONTAINER_PROFILE (a))
+    return
+        _compare_container_encoding_profiles (GST_ENCODING_CONTAINER_PROFILE
+        (a), GST_ENCODING_CONTAINER_PROFILE (b));
+
+  if (GST_IS_ENCODING_VIDEO_PROFILE (a)) {
+    GstEncodingVideoProfile *va = (GstEncodingVideoProfile *) a;
+    GstEncodingVideoProfile *vb = (GstEncodingVideoProfile *) b;
+
+    if ((va->pass != vb->pass)
+        || (va->variableframerate != vb->variableframerate))
+      return -1;
+  }
+
+  return 0;
+}
+
+/**
+ * gst_encoding_container_profile_contains_profile:
+ * @container: a #GstEncodingContainerProfile
+ * @profile: a #GstEncodingProfile
+ *
+ * Checks if @container contains a #GstEncodingProfile identical to
+ * @profile.
+ *
+ * Since: 0.10.32
+ *
+ * Returns: %TRUE if @container contains a #GstEncodingProfile identical
+ * to @profile, else %FALSE.
+ */
+gboolean
+gst_encoding_container_profile_contains_profile (GstEncodingContainerProfile *
+    container, GstEncodingProfile * profile)
+{
+  g_return_val_if_fail (GST_IS_ENCODING_CONTAINER_PROFILE (container), FALSE);
+  g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
+
+  return (g_list_find_custom (container->encodingprofiles, profile,
+          (GCompareFunc) _compare_encoding_profiles) != NULL);
+}
+
+/**
+ * gst_encoding_container_profile_add_profile:
+ * @container: the #GstEncodingContainerProfile to use
+ * @profile: the #GstEncodingProfile to add.
+ *
+ * Add a #GstEncodingProfile to the list of profiles handled by @container.
+ * 
+ * No copy of @profile will be made, if you wish to use it elsewhere after this
+ * method you should increment its reference count.
+ *
+ * Since: 0.10.32
+ *
+ * Returns: %TRUE if the @stream was properly added, else %FALSE.
+ */
+gboolean
+gst_encoding_container_profile_add_profile (GstEncodingContainerProfile *
+    container, GstEncodingProfile * profile)
+{
+  g_return_val_if_fail (GST_IS_ENCODING_CONTAINER_PROFILE (container), FALSE);
+  g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
+
+  if (g_list_find_custom (container->encodingprofiles, profile,
+          (GCompareFunc) _compare_encoding_profiles)) {
+    GST_ERROR
+        ("Encoding profile already contains an identical GstEncodingProfile");
+    return FALSE;
+  }
+
+  container->encodingprofiles =
+      g_list_append (container->encodingprofiles, profile);
+
+  return TRUE;
+}
+
+static GstEncodingProfile *
+common_creation (GType objtype, GstCaps * format, const gchar * preset,
+    const gchar * name, const gchar * description, GstCaps * restriction,
+    guint presence)
+{
+  GstEncodingProfile *prof;
+
+  prof = (GstEncodingProfile *) gst_mini_object_new (objtype);
+
+  if (name)
+    prof->name = g_strdup (name);
+  if (description)
+    prof->description = g_strdup (description);
+  if (preset)
+    prof->preset = g_strdup (preset);
+  if (format)
+    prof->format = gst_caps_ref (format);
+  if (restriction)
+    prof->restriction = gst_caps_ref (restriction);
+  prof->presence = presence;
+
+  return prof;
+}
+
+/**
+ * gst_encoding_container_profile_new:
+ * @name: The name of the container profile, can be %NULL
+ * @description: The description of the container profile, can be %NULL
+ * @format: The format to use for this profile
+ * @preset: The preset to use for this profile
+ *
+ * Creates a new #GstEncodingContainerProfile.
+ *
+ * Since: 0.10.32
+ *
+ * Returns: The newly created #GstEncodingContainerProfile.
+ */
+GstEncodingContainerProfile *
+gst_encoding_container_profile_new (const gchar * name,
+    const gchar * description, GstCaps * format, const gchar * preset)
+{
+  return (GstEncodingContainerProfile *)
+      common_creation (GST_TYPE_ENCODING_CONTAINER_PROFILE, format, preset,
+      name, description, NULL, 0);
+}
+
+/**
+ * gst_encoding_video_profile_new:
+ * @format: the #GstCaps
+ * @preset: the preset(s) to use on the encoder, can be #NULL
+ * @restriction: the #GstCaps used to restrict the input to the encoder, can be
+ * NULL.
+ * @presence: the number of time this stream must be used. 0 means any number of
+ *  times (including never)
+ *
+ * Creates a new #GstEncodingVideoProfile
+ *
+ * All provided allocatable arguments will be internally copied, so can be
+ * safely freed/unreferenced after calling this method.
+ *
+ * If you wish to control the pass number (in case of multi-pass scenarios),
+ * please refer to the gst_encoding_video_profile_set_pass() documentation.
+ *
+ * If you wish to use/force a constant framerate please refer to the
+ * gst_encoding_video_profile_set_variableframerate() documentation.
+ *
+ * Since: 0.10.32
+ *
+ * Returns: the newly created #GstEncodingVideoProfile.
+ */
+GstEncodingVideoProfile *
+gst_encoding_video_profile_new (GstCaps * format, const gchar * preset,
+    GstCaps * restriction, guint presence)
+{
+  return (GstEncodingVideoProfile *)
+      common_creation (GST_TYPE_ENCODING_VIDEO_PROFILE, format, preset, NULL,
+      NULL, restriction, presence);
+}
+
+/**
+ * gst_encoding_audio_profile_new:
+ * @format: the #GstCaps
+ * @preset: the preset(s) to use on the encoder, can be #NULL
+ * @restriction: the #GstCaps used to restrict the input to the encoder, can be
+ * NULL.
+ * @presence: the number of time this stream must be used. 0 means any number of
+ *  times (including never)
+ *
+ * Creates a new #GstEncodingAudioProfile
+ *
+ * All provided allocatable arguments will be internally copied, so can be
+ * safely freed/unreferenced after calling this method.
+ *
+ * Since: 0.10.32
+ *
+ * Returns: the newly created #GstEncodingAudioProfile.
+ */
+GstEncodingAudioProfile *
+gst_encoding_audio_profile_new (GstCaps * format, const gchar * preset,
+    GstCaps * restriction, guint presence)
+{
+  return (GstEncodingAudioProfile *)
+      common_creation (GST_TYPE_ENCODING_AUDIO_PROFILE, format, preset, NULL,
+      NULL, restriction, presence);
+}
+
+
+/**
+ * gst_encoding_profile_is_equal:
+ * @a: a #GstEncodingProfile
+ * @b: a #GstEncodingProfile
+ *
+ * Checks whether the two #GstEncodingProfile are equal
+ *
+ * Since: 0.10.32
+ *
+ * Returns: %TRUE if @a and @b are equal, else %FALSE.
+ */
+gboolean
+gst_encoding_profile_is_equal (GstEncodingProfile * a, GstEncodingProfile * b)
+{
+  return (_compare_encoding_profiles (a, b) == 0);
+}
+
+
+/**
+ * gst_encoding_profile_get_output_caps:
+ * @profile: a #GstEncodingProfile
+ *
+ * Computes the full output caps that this @profile will be able to consume.
+ *
+ * Since: 0.10.32
+ *
+ * Returns: The full caps the given @profile can consume. Call gst_caps_unref()
+ * when you are done with the caps.
+ */
+GstCaps *
+gst_encoding_profile_get_output_caps (GstEncodingProfile * profile)
+{
+  GstCaps *out, *tmp;
+  GList *ltmp;
+  GstStructure *st, *outst;
+  GQuark out_name;
+  guint i, len;
+  const GstCaps *fcaps;
+
+  if (GST_IS_ENCODING_CONTAINER_PROFILE (profile)) {
+    GstCaps *res = gst_caps_new_empty ();
+
+    for (ltmp = GST_ENCODING_CONTAINER_PROFILE (profile)->encodingprofiles;
+        ltmp; ltmp = ltmp->next) {
+      GstEncodingProfile *sprof = (GstEncodingProfile *) ltmp->data;
+      gst_caps_merge (res, gst_encoding_profile_get_output_caps (sprof));
+    }
+    return res;
+  }
+
+  fcaps = profile->format;
+
+  /* fast-path */
+  if ((profile->restriction == NULL) || gst_caps_is_any (profile->restriction))
+    return gst_caps_copy (fcaps);
+
+  /* Combine the format with the restriction caps */
+  outst = gst_caps_get_structure (fcaps, 0);
+  out_name = gst_structure_get_name_id (outst);
+  tmp = gst_caps_new_empty ();
+  len = gst_caps_get_size (profile->restriction);
+
+  for (i = 0; i < len; i++) {
+    st = gst_structure_copy (gst_caps_get_structure (profile->restriction, i));
+    st->name = out_name;
+    gst_caps_append_structure (tmp, st);
+  }
+
+  out = gst_caps_intersect (tmp, fcaps);
+  gst_caps_unref (tmp);
+
+  return out;
+}
+
+/**
+ * gst_encoding_profile_get_type_nick:
+ * @profile: a #GstEncodingProfile
+ *
+ * Since: 0.10.32
+ *
+ * Returns: the human-readable name of the type of @profile.
+ */
+const gchar *
+gst_encoding_profile_get_type_nick (GstEncodingProfile * profile)
+{
+  if (GST_IS_ENCODING_CONTAINER_PROFILE (profile))
+    return "container";
+  if (GST_IS_ENCODING_VIDEO_PROFILE (profile))
+    return "video";
+  if (GST_IS_ENCODING_AUDIO_PROFILE (profile))
+    return "audio";
+  return NULL;
+}
diff --git a/gst-libs/gst/pbutils/encoding-profile.h b/gst-libs/gst/pbutils/encoding-profile.h
new file mode 100644 (file)
index 0000000..3c6f3c3
--- /dev/null
@@ -0,0 +1,184 @@
+/* GStreamer encoding profiles library
+ * Copyright (C) 2009-2010 Edward Hervey <edward.hervey@collabora.co.uk>
+ *           (C) 2009-2010 Nokia Corporation
+ *
+ * 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.
+ */
+
+#ifndef __GST_PROFILE_H__
+#define __GST_PROFILE_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#include <gst/pbutils/pbutils-enumtypes.h>
+
+/**
+ * GstEncodingProfile:
+ *
+ * The opaque base class object for all encoding profiles. This contains generic
+ * information like name, description, format and preset.
+ *
+ * Since: 0.10.32
+ */
+
+#define GST_TYPE_ENCODING_PROFILE                      \
+  (gst_encoding_profile_get_type ())
+#define GST_ENCODING_PROFILE(obj)                      \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ENCODING_PROFILE, GstEncodingProfile))
+#define GST_IS_ENCODING_PROFILE(obj)                   \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ENCODING_PROFILE))
+typedef struct _GstEncodingProfile GstEncodingProfile;
+typedef GstMiniObjectClass GstEncodingProfileClass;
+GType gst_encoding_profile_get_type (void);
+
+
+
+/**
+ * GstEncodingContainerProfile:
+ *
+ * Encoding profiles for containers. Keeps track of a list of #GstEncodingProfile
+ *
+ * Since: 0.10.32
+ */
+#define GST_TYPE_ENCODING_CONTAINER_PROFILE                    \
+  (gst_encoding_container_profile_get_type ())
+#define GST_ENCODING_CONTAINER_PROFILE(obj)                    \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ENCODING_CONTAINER_PROFILE, GstEncodingContainerProfile))
+#define GST_IS_ENCODING_CONTAINER_PROFILE(obj)                 \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ENCODING_CONTAINER_PROFILE))
+typedef struct _GstEncodingContainerProfile GstEncodingContainerProfile;
+typedef GstEncodingProfileClass GstEncodingContainerProfileClass;
+GType gst_encoding_container_profile_get_type (void);
+
+
+
+/**
+ * GstEncodingVideoProfile:
+ *
+ * Variant of #GstEncodingProfile for video streams, allows specifying the @pass.
+ *
+ * Since: 0.10.32
+ */
+#define GST_TYPE_ENCODING_VIDEO_PROFILE                        \
+  (gst_encoding_video_profile_get_type ())
+#define GST_ENCODING_VIDEO_PROFILE(obj)                        \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ENCODING_VIDEO_PROFILE, GstEncodingVideoProfile))
+#define GST_IS_ENCODING_VIDEO_PROFILE(obj)                     \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ENCODING_VIDEO_PROFILE))
+typedef struct _GstEncodingVideoProfile GstEncodingVideoProfile;
+typedef GstEncodingProfileClass GstEncodingVideoProfileClass;
+GType gst_encoding_video_profile_get_type (void);
+
+
+
+/**
+ * GstEncodingAudioProfile:
+ *
+ * Variant of #GstEncodingProfile for audio streams.
+ *
+ * Since: 0.10.32
+ */
+#define GST_TYPE_ENCODING_AUDIO_PROFILE                        \
+  (gst_encoding_audio_profile_get_type ())
+#define GST_ENCODING_AUDIO_PROFILE(obj)                        \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ENCODING_AUDIO_PROFILE, GstEncodingAudioProfile))
+#define GST_IS_ENCODING_AUDIO_PROFILE(obj)                     \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ENCODING_AUDIO_PROFILE))
+typedef struct _GstEncodingAudioProfile GstEncodingAudioProfile;
+typedef GstEncodingProfileClass GstEncodingAudioProfileClass;
+GType gst_encoding_audio_profile_get_type (void);
+
+
+
+/* GstEncodingProfile API */
+
+/**
+ * gst_encoding_profile_unref:
+ * @profile: a #GstEncodingProfile
+ *
+ * Decreases the reference count of the @profile, possibly freeing the @profile.
+ *
+ * Since: 0.10.32
+ */
+#define gst_encoding_profile_unref(profile) (gst_mini_object_unref ((GstMiniObject*) profile))
+
+/**
+ * gst_encoding_profile_ref:
+ * @profile: a #GstEncodingProfile
+ *
+ * Increases the reference count of the @profile.
+ *
+ * Since: 0.10.32
+ */
+#define gst_encoding_profile_ref(profile) (gst_mini_object_ref ((GstMiniObject*) profile))
+
+const gchar *  gst_encoding_profile_get_name(GstEncodingProfile *profile);
+const gchar *  gst_encoding_profile_get_description(GstEncodingProfile *profile);
+const GstCaps *        gst_encoding_profile_get_format(GstEncodingProfile *profile);
+const gchar *  gst_encoding_profile_get_preset(GstEncodingProfile *profile);
+const guint    gst_encoding_profile_get_presence(GstEncodingProfile *profile);
+const GstCaps *        gst_encoding_profile_get_restriction(GstEncodingProfile *profile);
+
+void   gst_encoding_profile_set_name(GstEncodingProfile *profile, const gchar *name);
+void   gst_encoding_profile_set_description(GstEncodingProfile *profile, const gchar *description);
+void   gst_encoding_profile_set_format(GstEncodingProfile *profile, GstCaps *format);
+void   gst_encoding_profile_set_preset(GstEncodingProfile *profile, const gchar *preset);
+void   gst_encoding_profile_set_restriction(GstEncodingProfile *profile, GstCaps *restriction);
+void   gst_encoding_profile_set_presence(GstEncodingProfile *profile, guint presence);
+
+gboolean gst_encoding_profile_is_equal (GstEncodingProfile *a,
+                                       GstEncodingProfile *b);
+GstCaps * gst_encoding_profile_get_output_caps (GstEncodingProfile *profile);
+
+const gchar *gst_encoding_profile_get_type_nick (GstEncodingProfile *profile);
+
+/* GstEncodingContainerProfile API */
+gboolean  gst_encoding_container_profile_add_profile       (GstEncodingContainerProfile *container,
+                                                           GstEncodingProfile *profile);
+gboolean  gst_encoding_container_profile_contains_profile  (GstEncodingContainerProfile * container,
+                                                           GstEncodingProfile *profile);
+const GList *gst_encoding_container_profile_get_profiles   (GstEncodingContainerProfile *profile);
+
+
+GstEncodingContainerProfile *  gst_encoding_container_profile_new (const gchar *name,
+                                                                  const gchar *description,
+                                                                  GstCaps *format,
+                                                                  const gchar *preset);
+
+
+/* Invidual stream encodingprofile API */
+GstEncodingVideoProfile * gst_encoding_video_profile_new (GstCaps *format,
+                                                         const gchar *preset,
+                                                         GstCaps *restriction,
+                                                         guint presence);
+GstEncodingAudioProfile * gst_encoding_audio_profile_new (GstCaps *format,
+                                                         const gchar *preset,
+                                                         GstCaps *restriction,
+                                                         guint presence);
+
+guint    gst_encoding_video_profile_get_pass              (GstEncodingVideoProfile *prof);
+gboolean gst_encoding_video_profile_get_variableframerate (GstEncodingVideoProfile *prof);
+
+void     gst_encoding_video_profile_set_pass              (GstEncodingVideoProfile *prof,
+                                                          guint pass);
+void     gst_encoding_video_profile_set_variableframerate (GstEncodingVideoProfile *prof,
+                                                          gboolean variableframerate);
+
+G_END_DECLS
+
+#endif /* __GST_PROFILE_H__ */
diff --git a/gst-libs/gst/pbutils/encoding-target.c b/gst-libs/gst/pbutils/encoding-target.c
new file mode 100644 (file)
index 0000000..19065e8
--- /dev/null
@@ -0,0 +1,724 @@
+/* GStreamer encoding profile registry
+ * Copyright (C) 2010 Edward Hervey <edward.hervey@collabora.co.uk>
+ *           (C) 2010 Nokia Corporation
+ *
+ * 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 <locale.h>
+#include "encoding-target.h"
+
+/*
+ * File format
+ *
+ * GKeyFile style.
+ *
+ * [_gstencodingtarget_]
+ * name : <name>
+ * category : <category>
+ * description : <description> #translatable
+ *
+ * [profile-<profile1name>]
+ * name : <name>
+ * description : <description> #optional
+ * format : <format>
+ * preset : <preset>
+ *
+ * [streamprofile-<id>]
+ * parent : <encodingprofile.name>[,<encodingprofile.name>..]
+ * type : <type> # "audio", "video", "text"
+ * format : <format>
+ * preset : <preset>
+ * restriction : <restriction>
+ * presence : <presence>
+ * pass : <pass>
+ * variableframerate : <variableframerate>
+ *  */
+
+#define GST_ENCODING_TARGET_HEADER "_gstencodingtarget_"
+
+struct _GstEncodingTarget
+{
+  GstMiniObject parent;
+
+  gchar *name;
+  gchar *category;
+  gchar *description;
+  GList *profiles;
+
+  /*< private > */
+  gchar *keyfile;
+};
+
+G_DEFINE_TYPE (GstEncodingTarget, gst_encoding_target, GST_TYPE_MINI_OBJECT);
+
+static void
+gst_encoding_target_init (GstEncodingTarget * target)
+{
+  /* Nothing to initialize */
+}
+
+static void
+gst_encoding_target_finalize (GstEncodingTarget * target)
+{
+  GST_DEBUG ("Finalizing");
+
+  if (target->name)
+    g_free (target->name);
+  if (target->category)
+    g_free (target->category);
+  if (target->description)
+    g_free (target->description);
+
+  g_list_foreach (target->profiles, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (target->profiles);
+}
+
+static void
+gst_encoding_target_class_init (GstMiniObjectClass * klass)
+{
+  klass->finalize =
+      (GstMiniObjectFinalizeFunction) gst_encoding_target_finalize;
+}
+
+/**
+ * gst_encoding_target_get_name:
+ * @target: a #GstEncodingTarget
+ *
+ * Since: 0.10.32
+ *
+ * Returns: The name of the @target.
+ */
+const gchar *
+gst_encoding_target_get_name (GstEncodingTarget * target)
+{
+  return target->name;
+}
+
+/**
+ * gst_encoding_target_get_category:
+ * @target: a #GstEncodingTarget
+ *
+ * Since: 0.10.32
+ *
+ * Returns: The category of the @target.
+ */
+const gchar *
+gst_encoding_target_get_category (GstEncodingTarget * target)
+{
+  return target->category;
+}
+
+/**
+ * gst_encoding_target_get_description:
+ * @target: a #GstEncodingTarget
+ *
+ * Since: 0.10.32
+ *
+ * Returns: The description of the @target.
+ */
+const gchar *
+gst_encoding_target_get_description (GstEncodingTarget * target)
+{
+  return target->description;
+}
+
+/**
+ * gst_encoding_target_get_profiles:
+ * @target: a #GstEncodingTarget
+ *
+ * Since: 0.10.32
+ *
+ * Returns: A list of #GstEncodingProfile(s) this @target handles.
+ */
+const GList *
+gst_encoding_target_get_profiles (GstEncodingTarget * target)
+{
+  return target->profiles;
+}
+
+
+/**
+ * gst_encoding_target_new:
+ * @name: The name of the target.
+ * @category: The name of the category to which this @target belongs.
+ * @description: A description of #GstEncodingTarget in the current locale.
+ * @profiles: A #GList of #GstEncodingProfile.
+ *
+ * Creates a new #GstEncodingTarget.
+ *
+ * Since: 0.10.32
+ *
+ * Returns: The newly created #GstEncodingTarget or %NULL if there was an 
+ * error.
+ */
+
+GstEncodingTarget *
+gst_encoding_target_new (const gchar * name, const gchar * category,
+    const gchar * description, const GList * profiles)
+{
+  GstEncodingTarget *res;
+
+  g_return_val_if_fail (name != NULL, NULL);
+  g_return_val_if_fail (category != NULL, NULL);
+  g_return_val_if_fail (description != NULL, NULL);
+
+  res = (GstEncodingTarget *) gst_mini_object_new (GST_TYPE_ENCODING_TARGET);
+  res->name = g_strdup (name);
+  res->category = g_strdup (category);
+  res->description = g_strdup (description);
+
+  while (profiles) {
+    GstEncodingProfile *prof = (GstEncodingProfile *) profiles->data;
+
+    res->profiles =
+        g_list_append (res->profiles, gst_encoding_profile_ref (prof));
+    profiles = profiles->next;
+  }
+
+  return res;
+}
+
+/**
+ * gst_encoding_target_add_profile:
+ * @target: the #GstEncodingTarget to add a profile to
+ * @profile: the #GstEncodingProfile to add
+ *
+ * Adds the given @profile to the @target.
+ *
+ * The @target will steal a reference to the @profile. If you wish to use
+ * the profile after calling this method, you should increase its reference
+ * count.
+ *
+ * Since: 0.10.32
+ *
+ * Returns: %TRUE if the profile was added, else %FALSE.
+ **/
+
+gboolean
+gst_encoding_target_add_profile (GstEncodingTarget * target,
+    GstEncodingProfile * profile)
+{
+  GList *tmp;
+
+  g_return_val_if_fail (GST_IS_ENCODING_TARGET (target), FALSE);
+  g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
+
+  /* Make sure profile isn't already controlled by this target */
+  for (tmp = target->profiles; tmp; tmp = tmp->next) {
+    GstEncodingProfile *prof = (GstEncodingProfile *) tmp->data;
+
+    if (!g_strcmp0 (gst_encoding_profile_get_name (profile),
+            gst_encoding_profile_get_name (prof))) {
+      GST_WARNING ("Profile already present in target");
+      return FALSE;
+    }
+  }
+
+  target->profiles = g_list_append (target->profiles, profile);
+
+  return TRUE;
+}
+
+static gboolean
+serialize_stream_profiles (GKeyFile * out, GstEncodingProfile * sprof,
+    const gchar * profilename, guint id)
+{
+  gchar *sprofgroupname;
+  gchar *tmpc;
+  const GstCaps *format, *restriction;
+  const gchar *preset, *name, *description;
+
+  sprofgroupname = g_strdup_printf ("streamprofile-%s-%d", profilename, id);
+
+  /* Write the parent profile */
+  g_key_file_set_value (out, sprofgroupname, "parent", profilename);
+
+  g_key_file_set_value (out, sprofgroupname, "type",
+      gst_encoding_profile_get_type_nick (sprof));
+
+  format = gst_encoding_profile_get_format (sprof);
+  if (format) {
+    tmpc = gst_caps_to_string (format);
+    g_key_file_set_value (out, sprofgroupname, "format", tmpc);
+    g_free (tmpc);
+  }
+
+  name = gst_encoding_profile_get_name (sprof);
+  if (name)
+    g_key_file_set_string (out, sprofgroupname, "name", name);
+
+  description = gst_encoding_profile_get_description (sprof);
+  if (description)
+    g_key_file_set_string (out, sprofgroupname, "description", description);
+
+  preset = gst_encoding_profile_get_preset (sprof);
+  if (preset)
+    g_key_file_set_string (out, sprofgroupname, "preset", preset);
+
+  restriction = gst_encoding_profile_get_restriction (sprof);
+  if (restriction) {
+    tmpc = gst_caps_to_string (restriction);
+    g_key_file_set_value (out, sprofgroupname, "restriction", tmpc);
+    g_free (tmpc);
+  }
+  g_key_file_set_integer (out, sprofgroupname, "presence",
+      gst_encoding_profile_get_presence (sprof));
+
+  if (GST_IS_ENCODING_VIDEO_PROFILE (sprof)) {
+    GstEncodingVideoProfile *vp = (GstEncodingVideoProfile *) sprof;
+
+    g_key_file_set_integer (out, sprofgroupname, "pass",
+        gst_encoding_video_profile_get_pass (vp));
+    g_key_file_set_boolean (out, sprofgroupname, "variableframerate",
+        gst_encoding_video_profile_get_variableframerate (vp));
+  }
+
+  g_free (sprofgroupname);
+  return TRUE;
+}
+
+/* Serialize the top-level profiles
+ * Note: They don't have to be containerprofiles */
+static gboolean
+serialize_encoding_profile (GKeyFile * out, GstEncodingProfile * prof)
+{
+  gchar *profgroupname;
+  const GList *tmp;
+  guint i;
+  const gchar *profname, *profdesc, *profpreset, *proftype;
+  const GstCaps *profformat, *profrestriction;
+
+  profname = gst_encoding_profile_get_name (prof);
+  profdesc = gst_encoding_profile_get_description (prof);
+  profformat = gst_encoding_profile_get_format (prof);
+  profpreset = gst_encoding_profile_get_preset (prof);
+  proftype = gst_encoding_profile_get_type_nick (prof);
+  profrestriction = gst_encoding_profile_get_restriction (prof);
+
+  profgroupname = g_strdup_printf ("profile-%s", profname);
+
+  g_key_file_set_string (out, profgroupname, "name", profname);
+
+  g_key_file_set_value (out, profgroupname, "type",
+      gst_encoding_profile_get_type_nick (prof));
+
+  if (profdesc)
+    g_key_file_set_locale_string (out, profgroupname, "description",
+        setlocale (LC_ALL, NULL), profdesc);
+  if (profformat) {
+    gchar *tmpc = gst_caps_to_string (profformat);
+    g_key_file_set_string (out, profgroupname, "format", tmpc);
+    g_free (tmpc);
+  }
+  if (profpreset)
+    g_key_file_set_string (out, profgroupname, "preset", profpreset);
+
+  /* stream profiles */
+  if (GST_IS_ENCODING_CONTAINER_PROFILE (prof)) {
+    for (tmp =
+        gst_encoding_container_profile_get_profiles
+        (GST_ENCODING_CONTAINER_PROFILE (prof)), i = 0; tmp;
+        tmp = tmp->next, i++) {
+      GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data;
+
+      if (!serialize_stream_profiles (out, sprof, profname, i))
+        return FALSE;
+    }
+  }
+  g_free (profgroupname);
+  return TRUE;
+}
+
+static gboolean
+serialize_target (GKeyFile * out, GstEncodingTarget * target)
+{
+  GList *tmp;
+
+  g_key_file_set_string (out, GST_ENCODING_TARGET_HEADER, "name", target->name);
+  g_key_file_set_string (out, GST_ENCODING_TARGET_HEADER, "category",
+      target->category);
+  g_key_file_set_string (out, GST_ENCODING_TARGET_HEADER, "description",
+      target->description);
+
+  for (tmp = target->profiles; tmp; tmp = tmp->next) {
+    GstEncodingProfile *prof = (GstEncodingProfile *) tmp->data;
+    if (!serialize_encoding_profile (out, prof))
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+ * parse_encoding_profile:
+ * @in: a #GKeyFile
+ * @parentprofilename: the parent profile name (including 'profile-' or 'streamprofile-' header)
+ * @profilename: the profile name group to parse
+ * @nbgroups: the number of top-level groups
+ * @groups: the top-level groups
+ */
+static GstEncodingProfile *
+parse_encoding_profile (GKeyFile * in, gchar * parentprofilename,
+    gchar * profilename, gsize nbgroups, gchar ** groups)
+{
+  GstEncodingProfile *sprof = NULL;
+  gchar **parent;
+  gchar *proftype, *format, *preset, *restriction, *pname, *description;
+  GstCaps *formatcaps = NULL;
+  GstCaps *restrictioncaps = NULL;
+  gboolean variableframerate;
+  gint pass, presence;
+  gsize i, nbencprofiles;
+
+  GST_DEBUG ("parentprofilename : %s , profilename : %s",
+      parentprofilename, profilename);
+
+  if (parentprofilename) {
+    gboolean found = FALSE;
+
+    parent =
+        g_key_file_get_string_list (in, profilename, "parent",
+        &nbencprofiles, NULL);
+    if (!parent || !nbencprofiles) {
+      return NULL;
+    }
+
+    /* Check if this streamprofile is used in <profilename> */
+    for (i = 0; i < nbencprofiles; i++) {
+      if (!g_strcmp0 (parent[i], parentprofilename)) {
+        found = TRUE;
+        break;
+      }
+    }
+    g_strfreev (parent);
+
+    if (!found) {
+      GST_DEBUG ("Stream profile '%s' isn't used in profile '%s'",
+          profilename, parentprofilename);
+      return NULL;
+    }
+  }
+
+  pname = g_key_file_get_value (in, profilename, "name", NULL);
+
+  /* First try to get localized description */
+  description =
+      g_key_file_get_locale_string (in, profilename, "description",
+      setlocale (LC_ALL, NULL), NULL);
+  if (description == NULL)
+    description = g_key_file_get_value (in, profilename, "description", NULL);
+
+  /* Parse the remaining fields */
+  proftype = g_key_file_get_value (in, profilename, "type", NULL);
+  if (!proftype) {
+    GST_WARNING ("Missing 'type' field for streamprofile %s", profilename);
+    return NULL;
+  }
+
+  format = g_key_file_get_value (in, profilename, "format", NULL);
+  if (format) {
+    formatcaps = gst_caps_from_string (format);
+    g_free (format);
+  }
+
+  preset = g_key_file_get_value (in, profilename, "preset", NULL);
+
+  restriction = g_key_file_get_value (in, profilename, "restriction", NULL);
+  if (restriction) {
+    restrictioncaps = gst_caps_from_string (restriction);
+    g_free (restriction);
+  }
+
+  presence = g_key_file_get_integer (in, profilename, "presence", NULL);
+  pass = g_key_file_get_integer (in, profilename, "pass", NULL);
+  variableframerate =
+      g_key_file_get_boolean (in, profilename, "variableframerate", NULL);
+
+  /* Build the streamprofile ! */
+  if (!g_strcmp0 (proftype, "container")) {
+    GstEncodingProfile *pprof;
+
+    sprof =
+        (GstEncodingProfile *) gst_encoding_container_profile_new (pname,
+        description, formatcaps, preset);
+    /* Now look for the stream profiles */
+    for (i = 0; i < nbgroups; i++) {
+      if (!g_ascii_strncasecmp (groups[i], "streamprofile-", 13)) {
+        pprof = parse_encoding_profile (in, pname, groups[i], nbgroups, groups);
+        if (pprof) {
+          gst_encoding_container_profile_add_profile (
+              (GstEncodingContainerProfile *) sprof, pprof);
+        }
+      }
+    }
+  } else if (!g_strcmp0 (proftype, "video")) {
+    sprof =
+        (GstEncodingProfile *) gst_encoding_video_profile_new (formatcaps,
+        preset, restrictioncaps, presence);
+    gst_encoding_video_profile_set_variableframerate ((GstEncodingVideoProfile
+            *) sprof, variableframerate);
+    gst_encoding_video_profile_set_pass ((GstEncodingVideoProfile *) sprof,
+        pass);
+  } else if (!g_strcmp0 (proftype, "audio")) {
+    sprof =
+        (GstEncodingProfile *) gst_encoding_audio_profile_new (formatcaps,
+        preset, restrictioncaps, presence);
+  } else
+    GST_ERROR ("Unknown profile format '%s'", proftype);
+
+  if (restrictioncaps)
+    gst_caps_unref (restrictioncaps);
+  if (formatcaps)
+    gst_caps_unref (formatcaps);
+
+  if (pname)
+    g_free (pname);
+  if (description)
+    g_free (description);
+  if (preset)
+    g_free (preset);
+  if (proftype)
+    g_free (proftype);
+
+  return sprof;
+}
+
+static GstEncodingTarget *
+parse_keyfile (GKeyFile * in, gchar * targetname, gchar * categoryname,
+    gchar * description)
+{
+  GstEncodingTarget *res = NULL;
+  GstEncodingProfile *prof;
+  gchar **groups;
+  gsize i, nbgroups;
+
+  res = gst_encoding_target_new (targetname, categoryname, description, NULL);
+
+  /* Figure out the various profiles */
+  groups = g_key_file_get_groups (in, &nbgroups);
+  for (i = 0; i < nbgroups; i++) {
+    if (!g_ascii_strncasecmp (groups[i], "profile-", 8)) {
+      prof = parse_encoding_profile (in, NULL, groups[i], nbgroups, groups);
+      if (prof)
+        gst_encoding_target_add_profile (res, prof);
+    }
+  }
+
+  g_strfreev (groups);
+
+  if (targetname)
+    g_free (targetname);
+  if (categoryname)
+    g_free (categoryname);
+  if (description)
+    g_free (description);
+
+  return res;
+}
+
+static GKeyFile *
+load_file_and_read_header (const gchar * path, gchar ** targetname,
+    gchar ** categoryname, gchar ** description, GError ** error)
+{
+  GKeyFile *in;
+  gboolean res;
+
+  in = g_key_file_new ();
+
+  GST_DEBUG ("path:%s", path);
+
+  res =
+      g_key_file_load_from_file (in, path,
+      G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, error);
+  if (!res || error != NULL)
+    goto load_error;
+
+  *targetname =
+      g_key_file_get_value (in, GST_ENCODING_TARGET_HEADER, "name", error);
+  if (!*targetname)
+    goto empty_name;
+
+  *categoryname =
+      g_key_file_get_value (in, GST_ENCODING_TARGET_HEADER, "category", NULL);
+  *description =
+      g_key_file_get_value (in, GST_ENCODING_TARGET_HEADER, "description",
+      NULL);
+
+  return in;
+
+load_error:
+  {
+    GST_WARNING ("Unable to read GstEncodingTarget file %s: %s",
+        path, (*error)->message);
+    g_key_file_free (in);
+    return NULL;
+  }
+
+empty_name:
+  {
+    GST_WARNING ("Wrong header in file %s: %s", path, (*error)->message);
+    g_key_file_free (in);
+    return NULL;
+  }
+}
+
+/**
+ * gst_encoding_target_load_from:
+ * @path: The file to load the #GstEncodingTarget from
+ * @error: If an error occured, this field will be filled in.
+ *
+ * Opens the provided file and returns the contained #GstEncodingTarget.
+ *
+ * Since: 0.10.32
+ *
+ * Returns: The #GstEncodingTarget contained in the file, else %NULL
+ */
+
+GstEncodingTarget *
+gst_encoding_target_load_from (const gchar * path, GError ** error)
+{
+  GKeyFile *in;
+  gchar *targetname, *categoryname, *description;
+  GstEncodingTarget *res = NULL;
+
+  in = load_file_and_read_header (path, &targetname, &categoryname,
+      &description, error);
+  if (!in)
+    goto beach;
+
+  res = parse_keyfile (in, targetname, categoryname, description);
+
+  g_key_file_free (in);
+
+beach:
+  return res;
+}
+
+/**
+ * gst_encoding_target_load:
+ * @name: the name of the #GstEncodingTarget to load.
+ * @error: If an error occured, this field will be filled in.
+ *
+ * Searches for the #GstEncodingTarget with the given name, loads it
+ * and returns it.
+ *
+ * Warning: NOT IMPLEMENTED.
+ *
+ * Since: 0.10.32
+ *
+ * Returns: The #GstEncodingTarget if available, else %NULL
+ */
+
+GstEncodingTarget *
+gst_encoding_target_load (const gchar * name, GError ** error)
+{
+  /* FIXME : IMPLEMENT */
+  return NULL;
+}
+
+/**
+ * gst_encoding_target_save:
+ * @target: a #GstEncodingTarget
+ * @error: If an error occured, this field will be filled in.
+ *
+ * Saves the @target to the default location.
+ *
+ * Warning: NOT IMPLEMENTED.
+ *
+ * Since: 0.10.32
+ *
+ * Returns: %TRUE if the target was correctly saved, else %FALSE.
+ **/
+
+gboolean
+gst_encoding_target_save (GstEncodingTarget * target, GError ** error)
+{
+  g_return_val_if_fail (GST_IS_ENCODING_TARGET (target), FALSE);
+
+  /* FIXME : IMPLEMENT */
+  return FALSE;
+}
+
+/**
+ * gst_encoding_target_save_to:
+ * @target: a #GstEncodingTarget
+ * @path: the location to store the @target at.
+ * @error: If an error occured, this field will be filled in.
+ *
+ * Saves the @target to the provided location.
+ *
+ * Since: 0.10.32
+ *
+ * Returns: %TRUE if the target was correctly saved, else %FALSE.
+ **/
+
+gboolean
+gst_encoding_target_save_to (GstEncodingTarget * target, const gchar * path,
+    GError ** error)
+{
+  GKeyFile *out;
+  gchar *data;
+  gsize data_size;
+
+  g_return_val_if_fail (GST_IS_ENCODING_TARGET (target), FALSE);
+  g_return_val_if_fail (path != NULL, FALSE);
+
+  /* FIXME : Check path is valid and writable
+   * FIXME : Strip out profiles already present in system target */
+
+  /* Get unique name... */
+
+  /* Create output GKeyFile */
+  out = g_key_file_new ();
+
+  if (!serialize_target (out, target))
+    goto serialize_failure;
+
+  if (!(data = g_key_file_to_data (out, &data_size, error)))
+    goto convert_failed;
+
+  if (!g_file_set_contents (path, data, data_size, error))
+    goto write_failed;
+
+  g_key_file_free (out);
+  g_free (data);
+
+  return TRUE;
+
+serialize_failure:
+  {
+    GST_ERROR ("Failure serializing target");
+    g_key_file_free (out);
+    return FALSE;
+  }
+
+convert_failed:
+  {
+    GST_ERROR ("Failure converting keyfile: %s", (*error)->message);
+    g_key_file_free (out);
+    g_free (data);
+    return FALSE;
+  }
+
+write_failed:
+  {
+    GST_ERROR ("Unable to write file %s: %s", path, (*error)->message);
+    g_key_file_free (out);
+    g_free (data);
+    return FALSE;
+  }
+}
diff --git a/gst-libs/gst/pbutils/encoding-target.h b/gst-libs/gst/pbutils/encoding-target.h
new file mode 100644 (file)
index 0000000..c23f526
--- /dev/null
@@ -0,0 +1,104 @@
+/* GStreamer encoding profile registry
+ * Copyright (C) 2010 Edward Hervey <edward.hervey@collabora.co.uk>
+ *           (C) 2010 Nokia Corporation
+ *
+ * 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.
+ */
+
+#ifndef __GST_PROFILE_REGISTRY_H__
+#define __GST_PROFILE_REGISTRY_H__
+
+#include <gst/pbutils/encoding-profile.h>
+
+G_BEGIN_DECLS
+
+
+/* FIXME/UNKNOWNS
+ *
+ * Should encoding categories be well-known strings/quarks ?
+ *
+ */
+
+#define GST_ENCODING_CATEGORY_DEVICE           "device"
+#define GST_ENCODING_CATEGORY_ONLINE_SERVICE   "online-service"
+#define GST_ENCODING_CATEGORY_STORAGE_EDITING   "storage-editing"
+#define GST_ENCODING_CATEGORY_CAPTURE          "capture"
+
+/**
+ * GstEncodingTarget:
+ *
+ * Collection of #GstEncodingProfile for a specific target or use-case.
+ *
+ * Since: 0.10.32
+ */
+#define GST_TYPE_ENCODING_TARGET                       \
+  (gst_encoding_target_get_type ())
+#define GST_ENCODING_TARGET(obj)                       \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ENCODING_TARGET, GstEncodingTarget))
+#define GST_IS_ENCODING_TARGET(obj)                    \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ENCODING_TARGET))
+
+typedef struct _GstEncodingTarget GstEncodingTarget;
+typedef GstMiniObjectClass GstEncodingTargetClass;
+
+GType gst_encoding_target_get_type (void);
+
+/**
+ * gst_encoding_target_unref:
+ * @target: a #GstEncodingTarget
+ *
+ * Decreases the reference count of the @target, possibly freeing it.
+ *
+ * Since: 0.10.32
+ */
+#define gst_encoding_target_unref(target) \
+  (gst_mini_object_unref ((GstMiniObject*) target))
+
+/**
+ * gst_encoding_target_ref:
+ * @target: a #GstEncodingTarget
+ *
+ * Increases the reference count of the @target.
+ *
+ * Since: 0.10.32
+ */
+#define gst_encoding_target_ref(target) \
+  (gst_mini_object_ref ((GstMiniObject*) target))
+
+GstEncodingTarget *
+gst_encoding_target_new (const gchar *name, const gchar *category,
+                        const gchar *description, const GList *profiles);
+const gchar *gst_encoding_target_get_name (GstEncodingTarget *target);
+const gchar *gst_encoding_target_get_category (GstEncodingTarget *target);
+const gchar *gst_encoding_target_get_description (GstEncodingTarget *target);
+const GList *gst_encoding_target_get_profiles (GstEncodingTarget *target);
+
+gboolean
+gst_encoding_target_add_profile (GstEncodingTarget *target, GstEncodingProfile *profile);
+
+gboolean gst_encoding_target_save (GstEncodingTarget *target,
+                                  GError **error);
+gboolean gst_encoding_target_save_to (GstEncodingTarget *target,
+                                     const gchar *path,
+                                     GError **error);
+GstEncodingTarget *gst_encoding_target_load (const gchar *name,
+                                            GError **error);
+GstEncodingTarget *gst_encoding_target_load_from (const gchar *path,
+                                                 GError **error);
+
+G_END_DECLS
+
+#endif /* __GST_PROFILE_REGISTRY_H__ */
index 15f2ec8..59ba740 100644 (file)
@@ -127,6 +127,7 @@ check_PROGRAMS = \
        libs/navigation \
        libs/netbuffer \
        libs/pbutils \
+       libs/profile \
        libs/rtp \
        libs/tag \
        libs/video \
@@ -238,6 +239,12 @@ libs_pbutils_LDADD = \
        $(top_builddir)/gst-libs/gst/video/libgstvideo-@GST_MAJORMINOR@.la \
        $(GST_BASE_LIBS) $(LDADD)
 
+libs_profile_CFLAGS = \
+       $(GST_PLUGINS_BASE_CFLAGS) \
+       $(AM_CFLAGS)
+libs_profile_LDADD = \
+       $(top_builddir)/gst-libs/gst/pbutils/libgstpbutils-@GST_MAJORMINOR@.la $(LDADD)
+
 elements_appsink_CFLAGS = \
        $(GST_PLUGINS_BASE_CFLAGS) \
        $(AM_CFLAGS)
index cd37258..326c47a 100644 (file)
@@ -6,6 +6,7 @@ mixer
 navigation
 netbuffer
 pbutils
+profile
 rtp
 tag
 utils
diff --git a/tests/check/libs/profile.c b/tests/check/libs/profile.c
new file mode 100644 (file)
index 0000000..a5640a6
--- /dev/null
@@ -0,0 +1,454 @@
+/* GStreamer unit test for gstprofile
+ *
+ * Copyright (C) <2009> Edward Hervey <edward.hervey@collabora.co.uk>
+ *
+ * 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 <fcntl.h> */
+#include <unistd.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <gst/check/gstcheck.h>
+
+#include <gst/pbutils/encoding-profile.h>
+#include <gst/pbutils/encoding-target.h>
+
+#define CHECK_PROFILE(profile, name, description, format, preset, presence, restriction) \
+  {                                                                    \
+  fail_if(profile == NULL);                                            \
+  fail_unless_equals_string (gst_encoding_profile_get_name (profile), name); \
+  fail_unless_equals_string (gst_encoding_profile_get_description (profile), description); \
+  fail_unless (gst_caps_is_equal (gst_encoding_profile_get_format (profile), format)); \
+  fail_unless_equals_string (gst_encoding_profile_get_preset (profile), preset); \
+  fail_unless_equals_int (gst_encoding_profile_get_presence (profile), presence); \
+  fail_unless (gst_caps_is_equal (gst_encoding_profile_get_restriction (profile), restriction)); \
+  }
+
+GST_START_TEST (test_profile_creation)
+{
+  GstEncodingProfile *encprof;
+  GstEncodingAudioProfile *audioprof;
+  GstEncodingVideoProfile *videoprof;
+  GstCaps *ogg, *vorbis, *theora;
+  GstCaps *test1, *test2;
+
+  ogg = gst_caps_new_simple ("application/ogg", NULL);
+  vorbis = gst_caps_new_simple ("audio/x-vorbis", NULL);
+  theora = gst_caps_new_simple ("video/x-theora", NULL);
+
+  encprof = (GstEncodingProfile *) gst_encoding_container_profile_new ((gchar *)
+      "ogg-theora-vorbis", "dumb-profile", ogg, (gchar *) "dumb-preset");
+  CHECK_PROFILE (encprof, "ogg-theora-vorbis", "dumb-profile", ogg,
+      "dumb-preset", 0, NULL);
+
+  audioprof = gst_encoding_audio_profile_new (vorbis, (gchar *) "HQ", NULL, 0);
+  CHECK_PROFILE ((GstEncodingProfile *) audioprof, NULL, NULL, vorbis, "HQ", 0,
+      NULL);
+
+  videoprof = gst_encoding_video_profile_new (theora, (gchar *) "HQ", NULL, 0);
+  CHECK_PROFILE ((GstEncodingProfile *) videoprof, NULL, NULL, theora, "HQ",
+      0, NULL);
+
+  fail_unless (gst_encoding_container_profile_add_profile (
+          (GstEncodingContainerProfile *) encprof,
+          (GstEncodingProfile *) audioprof));
+  fail_unless (gst_encoding_container_profile_add_profile (
+          (GstEncodingContainerProfile *) encprof,
+          (GstEncodingProfile *) videoprof));
+
+  /* Test caps */
+  test1 = gst_caps_from_string ("video/x-theora; audio/x-vorbis");
+  test2 = gst_encoding_profile_get_output_caps (encprof);
+  fail_unless (gst_caps_is_equal (test1, test2));
+  gst_caps_unref (test1);
+  gst_caps_unref (test2);
+
+  gst_encoding_profile_unref (encprof);
+  gst_caps_unref (ogg);
+  gst_caps_unref (theora);
+  gst_caps_unref (vorbis);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_profile_output_caps)
+{
+  GstEncodingProfile *sprof;
+  GstCaps *vorbis;
+  GstCaps *out, *restriction, *test1;
+
+  vorbis = gst_caps_new_simple ("audio/x-vorbis", NULL);
+
+  /* Simple case, no restriction */
+  sprof = (GstEncodingProfile *)
+      gst_encoding_audio_profile_new (vorbis, NULL, NULL, 0);
+  fail_if (sprof == NULL);
+
+  out = gst_encoding_profile_get_output_caps (sprof);
+  fail_if (out == NULL);
+  fail_unless (gst_caps_is_equal (out, vorbis));
+  gst_caps_unref (out);
+  gst_encoding_profile_unref (sprof);
+
+  /* One simple restriction */
+  restriction = gst_caps_from_string ("audio/x-raw-int,channels=2,rate=44100");
+  test1 = gst_caps_from_string ("audio/x-vorbis,channels=2,rate=44100");
+  fail_if (restriction == NULL);
+
+  sprof = (GstEncodingProfile *)
+      gst_encoding_audio_profile_new (vorbis, NULL, restriction, 0);
+  fail_if (sprof == NULL);
+
+  out = gst_encoding_profile_get_output_caps (sprof);
+  fail_if (out == NULL);
+  GST_DEBUG ("got caps %" GST_PTR_FORMAT, out);
+  fail_unless (gst_caps_is_equal (out, test1));
+  gst_caps_unref (out);
+  gst_caps_unref (restriction);
+  gst_caps_unref (test1);
+  gst_encoding_profile_unref (sprof);
+
+  gst_caps_unref (vorbis);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_containerless_profile)
+{
+  GstEncodingProfile *encprof;
+  GstEncodingAudioProfile *audioprof;
+  GstCaps *container = NULL, *vorbis;
+  GstCaps *test1, *test2;
+
+  vorbis = gst_caps_new_simple ("audio/x-vorbis", NULL);
+
+  GST_DEBUG ("Creating container profile without any caps");
+  encprof = (GstEncodingProfile *) gst_encoding_container_profile_new ((gchar *)
+      "container-vorbis", "dumb-profile", container, (gchar *) "dumb-preset");
+  CHECK_PROFILE (encprof, "container-vorbis", "dumb-profile", NULL,
+      "dumb-preset", 0, 0);
+
+  GST_DEBUG ("Creating audio profile");
+  audioprof = gst_encoding_audio_profile_new (vorbis, (gchar *) "HQ", NULL, 0);
+  CHECK_PROFILE ((GstEncodingProfile *) audioprof, NULL, NULL, vorbis, "HQ", 0,
+      0);
+
+  GST_DEBUG ("Adding audio profile to container");
+  /* We can add one stream profile to container-less profiles.. */
+  fail_unless (gst_encoding_container_profile_add_profile (
+          (GstEncodingContainerProfile *) encprof,
+          (GstEncodingProfile *) audioprof));
+  GST_DEBUG ("Adding audio profile to container a second time (should fail)");
+  /* .. but not two */
+  fail_if (gst_encoding_container_profile_add_profile (
+          (GstEncodingContainerProfile *) encprof,
+          (GstEncodingProfile *) audioprof));
+
+  GST_DEBUG ("Checking caps");
+  /* Test caps */
+  test1 = gst_caps_from_string ("audio/x-vorbis");
+  test2 = gst_encoding_profile_get_output_caps (encprof);
+  fail_unless (gst_caps_is_equal (test1, test2));
+  gst_caps_unref (test1);
+  gst_caps_unref (test2);
+
+  gst_encoding_profile_unref (encprof);
+  gst_caps_unref (vorbis);
+}
+
+GST_END_TEST;
+
+static GstEncodingTarget *
+create_saveload_target (void)
+{
+  GstEncodingTarget *target;
+  GstEncodingProfile *profile, *sprof;
+  GstCaps *caps, *caps2;
+
+  GST_DEBUG ("Creating target");
+
+  target = gst_encoding_target_new ("myponytarget", "herding",
+      "Plenty of pony glitter profiles", NULL);
+  caps = gst_caps_from_string ("animal/x-pony");
+  profile =
+      (GstEncodingProfile *) gst_encoding_container_profile_new ("pony",
+      "I don't want a description !", caps, NULL);
+  gst_caps_unref (caps);
+  gst_encoding_target_add_profile (target, profile);
+
+  caps = gst_caps_from_string ("audio/x-pony-song,pretty=True");
+  caps2 = gst_caps_from_string ("audio/x-raw-int,channels=1,rate=44100");
+  sprof =
+      (GstEncodingProfile *) gst_encoding_audio_profile_new (caps, NULL, caps2,
+      1);
+  gst_encoding_container_profile_add_profile ((GstEncodingContainerProfile *)
+      profile, sprof);
+  gst_caps_unref (caps);
+  gst_caps_unref (caps2);
+
+  caps = gst_caps_from_string ("video/x-glitter,sparkling=True");
+  caps2 =
+      gst_caps_from_string
+      ("video/x-raw-yuv,width=640,height=480,framerate=15/1");
+  sprof = (GstEncodingProfile *)
+      gst_encoding_video_profile_new (caps, "seriously glittery", caps2, 0);
+  gst_encoding_video_profile_set_variableframerate ((GstEncodingVideoProfile *)
+      sprof, TRUE);
+  gst_encoding_container_profile_add_profile ((GstEncodingContainerProfile *)
+      profile, sprof);
+  gst_caps_unref (caps);
+  gst_caps_unref (caps2);
+
+  return target;
+}
+
+GST_START_TEST (test_saving_profile)
+{
+  GstEncodingTarget *orig, *loaded = NULL;
+  GstEncodingProfile *proforig, *profloaded;
+  gchar *profile_file_name;
+
+  /* Create and store a target */
+  profile_file_name = g_build_filename (g_get_home_dir (), ".gstreamer-0.10",
+      "profile", "TestProfile2.profile", NULL);
+  orig = create_saveload_target ();
+  GST_DEBUG ("Saving target to '%s'", profile_file_name);
+  fail_unless (gst_encoding_target_save_to (orig, profile_file_name, NULL));
+
+  /* Check we can load it */
+  GST_DEBUG ("Loading target from '%s'", profile_file_name);
+  loaded = gst_encoding_target_load_from (profile_file_name, NULL);
+  fail_unless (loaded != NULL);
+  g_free (profile_file_name);
+
+  GST_DEBUG ("Checking targets are equal");
+  /* Check targets are identical */
+  /* 1. at the target level */
+  fail_unless_equals_string (gst_encoding_target_get_name (orig),
+      gst_encoding_target_get_name (loaded));
+  fail_unless_equals_string (gst_encoding_target_get_category (orig),
+      gst_encoding_target_get_category (loaded));
+  fail_unless_equals_string (gst_encoding_target_get_description (orig),
+      gst_encoding_target_get_description (loaded));
+  fail_unless_equals_int (g_list_length ((GList *)
+          gst_encoding_target_get_profiles (loaded)), 1);
+
+  /* 2. at the profile level */
+  profloaded =
+      (GstEncodingProfile *) gst_encoding_target_get_profiles (loaded)->data;
+  proforig =
+      (GstEncodingProfile *) gst_encoding_target_get_profiles (orig)->data;
+
+  fail_unless_equals_int (G_TYPE_FROM_INSTANCE (profloaded),
+      G_TYPE_FROM_INSTANCE (proforig));
+  GST_DEBUG ("Comparing loaded:%p to original:%p", profloaded, proforig);
+  fail_unless (gst_encoding_profile_is_equal (profloaded, proforig));
+
+  gst_encoding_target_unref (orig);
+  gst_encoding_target_unref (loaded);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_loading_profile)
+{
+  GstEncodingTarget *target;
+  gchar *profile_file_name;
+  GstEncodingProfile *prof;
+  GstCaps *tmpcaps, *tmpcaps2;
+  GstEncodingProfile *sprof1, *sprof2;
+
+  profile_file_name = g_build_filename (g_get_home_dir (), ".gstreamer-0.10",
+      "profile", "TestProfile.profile", NULL);
+
+  GST_DEBUG ("Loading target from '%s'", profile_file_name);
+  target = gst_encoding_target_load_from (profile_file_name, NULL);
+  g_free (profile_file_name);
+  fail_unless (target != NULL);
+
+  GST_DEBUG ("Checking the target properties");
+  /* Check the target  */
+  fail_unless_equals_string (gst_encoding_target_get_name (target),
+      "myponytarget");
+  fail_unless_equals_string (gst_encoding_target_get_category (target),
+      "herding");
+  fail_unless_equals_string (gst_encoding_target_get_description (target),
+      "Plenty of pony glitter profiles");
+
+  GST_DEBUG ("Checking the number of profiles the target contains");
+  fail_unless_equals_int (g_list_length ((GList *)
+          gst_encoding_target_get_profiles (target)), 1);
+
+
+  GST_DEBUG ("Checking the container profile");
+  /* Check the profile */
+  prof = (GstEncodingProfile *) gst_encoding_target_get_profiles (target)->data;
+  tmpcaps = gst_caps_from_string ("animal/x-pony");
+  CHECK_PROFILE (prof, "pony", "I don't want a description !", tmpcaps, NULL, 0,
+      0);
+  gst_caps_unref (tmpcaps);
+
+  GST_DEBUG ("Checking the container profile has 2 stream profiles");
+  /* Check the stream profiles */
+  fail_unless_equals_int (g_list_length ((GList *)
+          gst_encoding_container_profile_get_profiles (
+              (GstEncodingContainerProfile *) prof)), 2);
+
+  GST_DEBUG ("Checking the container profile has the audio/x-pony-song stream");
+  tmpcaps = gst_caps_from_string ("audio/x-pony-song,pretty=True");
+  tmpcaps2 = gst_caps_from_string ("audio/x-raw-int,channels=1,rate=44100");
+  sprof1 =
+      (GstEncodingProfile *) gst_encoding_audio_profile_new (tmpcaps, NULL,
+      tmpcaps2, 1);
+  fail_unless (gst_encoding_container_profile_contains_profile (
+          (GstEncodingContainerProfile *) prof, sprof1));
+  gst_encoding_profile_unref (sprof1);
+  gst_caps_unref (tmpcaps);
+  gst_caps_unref (tmpcaps2);
+
+  GST_DEBUG ("Checking the container profile has the video//x-glitter stream");
+  tmpcaps = gst_caps_from_string ("video/x-glitter,sparkling=True");
+  tmpcaps2 =
+      gst_caps_from_string
+      ("video/x-raw-yuv,width=640,height=480,framerate=15/1");
+  sprof2 = (GstEncodingProfile *)
+      gst_encoding_video_profile_new (tmpcaps, "seriously glittery", tmpcaps2,
+      0);
+  gst_encoding_video_profile_set_variableframerate ((GstEncodingVideoProfile *)
+      sprof2, TRUE);
+  fail_unless (gst_encoding_container_profile_contains_profile (
+          (GstEncodingContainerProfile *) prof, sprof2));
+  gst_encoding_profile_unref (sprof2);
+  gst_caps_unref (tmpcaps);
+  gst_caps_unref (tmpcaps2);
+
+  gst_encoding_target_unref (target);
+}
+
+GST_END_TEST;
+
+static const gchar *profile_string = "\
+[_gstencodingtarget_]\n\
+name=myponytarget\n\
+category=herding\n\
+description=Plenty of pony glitter profiles\n\
+\n\
+[profile-pony1]\n\
+name=pony\n\
+type=container\n\
+description=I don't want a description !\n\
+format=animal/x-pony\n\
+\n\
+[streamprofile-pony11]\n\
+parent=pony\n\
+type=audio\n\
+format=audio/x-pony-song,pretty=True\n\
+restriction=audio/x-raw-int,channels=1,rate=44100\n\
+presence=1\n\
+\n\
+[streamprofile-pony12]\n\
+parent=pony\n\
+type=video\n\
+preset=seriously glittery\n\
+format=video/x-glitter,sparkling=True\n\
+restriction=video/x-raw-yuv,width=640,height=480,framerate=15/1\n\
+presence=0\n\
+variableframerate=true\n\
+";
+
+static void
+remove_profile_file (void)
+{
+  gchar *profile_file_name;
+
+  profile_file_name = g_build_filename (g_get_home_dir (), ".gstreamer-0.10",
+      "profile", "TestProfile.profile", NULL);
+  g_unlink (profile_file_name);
+  g_free (profile_file_name);
+  profile_file_name = g_build_filename (g_get_home_dir (), ".gstreamer-0.10",
+      "profile", "TestProfile2.profile", NULL);
+  g_unlink (profile_file_name);
+  g_free (profile_file_name);
+}
+
+static void
+create_profile_file (void)
+{
+  gchar *profile_file_name;
+  gchar *profile_dir;
+  GError *error = NULL;
+
+  profile_dir =
+      g_build_filename (g_get_home_dir (), ".gstreamer-0.10", "profile", NULL);
+  profile_file_name =
+      g_build_filename (g_get_home_dir (), ".gstreamer-0.10", "profile",
+      "TestProfile.profile", NULL);
+  g_mkdir_with_parents (profile_dir, S_IRUSR | S_IWUSR | S_IXUSR);
+  if (!g_file_set_contents (profile_file_name, profile_string,
+          strlen (profile_string), &error))
+    GST_WARNING ("Couldn't write contents to file : %s", error->message);
+  g_free (profile_dir);
+  g_free (profile_file_name);
+}
+
+static void
+test_setup (void)
+{
+  create_profile_file ();
+}
+
+static void
+test_teardown (void)
+{
+  remove_profile_file ();
+}
+
+
+static Suite *
+profile_suite (void)
+{
+  Suite *s = suite_create ("profile support library");
+  TCase *tc_chain = tcase_create ("general");
+  gboolean can_write;
+  gchar *gst_dir;
+
+  /* cehck if we can create profiles */
+  gst_dir = g_build_filename (g_get_home_dir (), ".gstreamer-0.10", NULL);
+  can_write = (g_access (gst_dir, R_OK | W_OK | X_OK) == 0);
+  g_free (gst_dir);
+
+  suite_add_tcase (s, tc_chain);
+
+  tcase_add_test (tc_chain, test_profile_creation);
+  tcase_add_test (tc_chain, test_profile_output_caps);
+  tcase_add_test (tc_chain, test_containerless_profile);
+  if (can_write) {
+    tcase_add_test (tc_chain, test_loading_profile);
+    tcase_add_test (tc_chain, test_saving_profile);
+  }
+
+  tcase_add_unchecked_fixture (tc_chain, test_setup, test_teardown);
+
+  return s;
+}
+
+GST_CHECK_MAIN (profile);
index 34c79dc..6f43ee4 100644 (file)
@@ -58,6 +58,46 @@ EXPORTS
        gst_discoverer_video_info_get_width
        gst_discoverer_video_info_is_image
        gst_discoverer_video_info_is_interlaced
+       gst_encoding_audio_profile_get_type
+       gst_encoding_audio_profile_new
+       gst_encoding_container_profile_add_profile
+       gst_encoding_container_profile_contains_profile
+       gst_encoding_container_profile_get_profiles
+       gst_encoding_container_profile_get_type
+       gst_encoding_container_profile_new
+       gst_encoding_profile_get_description
+       gst_encoding_profile_get_format
+       gst_encoding_profile_get_name
+       gst_encoding_profile_get_output_caps
+       gst_encoding_profile_get_presence
+       gst_encoding_profile_get_preset
+       gst_encoding_profile_get_restriction
+       gst_encoding_profile_get_type
+       gst_encoding_profile_get_type_nick
+       gst_encoding_profile_is_equal
+       gst_encoding_profile_set_description
+       gst_encoding_profile_set_format
+       gst_encoding_profile_set_name
+       gst_encoding_profile_set_presence
+       gst_encoding_profile_set_preset
+       gst_encoding_profile_set_restriction
+       gst_encoding_target_add_profile
+       gst_encoding_target_get_category
+       gst_encoding_target_get_description
+       gst_encoding_target_get_name
+       gst_encoding_target_get_profiles
+       gst_encoding_target_get_type
+       gst_encoding_target_load
+       gst_encoding_target_load_from
+       gst_encoding_target_new
+       gst_encoding_target_save
+       gst_encoding_target_save_to
+       gst_encoding_video_profile_get_pass
+       gst_encoding_video_profile_get_type
+       gst_encoding_video_profile_get_variableframerate
+       gst_encoding_video_profile_new
+       gst_encoding_video_profile_set_pass
+       gst_encoding_video_profile_set_variableframerate
        gst_install_plugins_async
        gst_install_plugins_context_free
        gst_install_plugins_context_get_type