summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/design/Makefile.am1
-rw-r--r--docs/design/design-encoding.txt571
-rw-r--r--docs/libs/gst-plugins-base-libs-docs.sgml1
-rw-r--r--docs/libs/gst-plugins-base-libs-sections.txt85
-rw-r--r--docs/libs/gst-plugins-base-libs.types11
-rw-r--r--gst-libs/gst/pbutils/Makefile.am4
-rw-r--r--gst-libs/gst/pbutils/encoding-profile.c834
-rw-r--r--gst-libs/gst/pbutils/encoding-profile.h184
-rw-r--r--gst-libs/gst/pbutils/encoding-target.c724
-rw-r--r--gst-libs/gst/pbutils/encoding-target.h104
-rw-r--r--tests/check/Makefile.am7
-rw-r--r--tests/check/libs/.gitignore1
-rw-r--r--tests/check/libs/profile.c454
-rw-r--r--win32/common/libgstpbutils.def40
14 files changed, 3021 insertions, 0 deletions
diff --git a/docs/design/Makefile.am b/docs/design/Makefile.am
index f2e0b71b6..357af4ce9 100644
--- a/docs/design/Makefile.am
+++ b/docs/design/Makefile.am
@@ -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
index 000000000..dda79addf
--- /dev/null
+++ b/docs/design/design-encoding.txt
@@ -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
+
diff --git a/docs/libs/gst-plugins-base-libs-docs.sgml b/docs/libs/gst-plugins-base-libs-docs.sgml
index 94a34519a..b7b61a70a 100644
--- a/docs/libs/gst-plugins-base-libs-docs.sgml
+++ b/docs/libs/gst-plugins-base-libs-docs.sgml
@@ -206,6 +206,7 @@
<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">
diff --git a/docs/libs/gst-plugins-base-libs-sections.txt b/docs/libs/gst-plugins-base-libs-sections.txt
index aff1cdb04..da6134bce 100644
--- a/docs/libs/gst-plugins-base-libs-sections.txt
+++ b/docs/libs/gst-plugins-base-libs-sections.txt
@@ -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>
diff --git a/docs/libs/gst-plugins-base-libs.types b/docs/libs/gst-plugins-base-libs.types
index db3818a1d..f6c06af2c 100644
--- a/docs/libs/gst-plugins-base-libs.types
+++ b/docs/libs/gst-plugins-base-libs.types
@@ -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
+
+
diff --git a/gst-libs/gst/pbutils/Makefile.am b/gst-libs/gst/pbutils/Makefile.am
index 9a261f51b..73251e1ae 100644
--- a/gst-libs/gst/pbutils/Makefile.am
+++ b/gst-libs/gst/pbutils/Makefile.am
@@ -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
index 000000000..8c364c887
--- /dev/null
+++ b/gst-libs/gst/pbutils/encoding-profile.c
@@ -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
index 000000000..3c6f3c3d3
--- /dev/null
+++ b/gst-libs/gst/pbutils/encoding-profile.h
@@ -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
index 000000000..19065e8fe
--- /dev/null
+++ b/gst-libs/gst/pbutils/encoding-target.c
@@ -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
index 000000000..c23f52660
--- /dev/null
+++ b/gst-libs/gst/pbutils/encoding-target.h
@@ -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__ */
diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am
index 15f2ec82f..59ba7403f 100644
--- a/tests/check/Makefile.am
+++ b/tests/check/Makefile.am
@@ -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)
diff --git a/tests/check/libs/.gitignore b/tests/check/libs/.gitignore
index cd372588c..326c47aa4 100644
--- a/tests/check/libs/.gitignore
+++ b/tests/check/libs/.gitignore
@@ -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
index 000000000..a5640a646
--- /dev/null
+++ b/tests/check/libs/profile.c
@@ -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);
diff --git a/win32/common/libgstpbutils.def b/win32/common/libgstpbutils.def
index 34c79dc63..6f43ee4e8 100644
--- a/win32/common/libgstpbutils.def
+++ b/win32/common/libgstpbutils.def
@@ -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