pbutils: New Profile library

https://bugzilla.gnome.org/show_bug.cgi?id=627476
This commit is contained in:
Edward Hervey 2010-08-13 17:27:52 +02:00
parent 3457bc7149
commit 82b4f9bfef
14 changed files with 3021 additions and 0 deletions

View file

@ -4,6 +4,7 @@ SUBDIRS =
EXTRA_DIST = \
design-audiosinks.txt \
design-decodebin.txt \
design-encoding.txt \
design-orc-integration.txt \
draft-keyframe-force.txt \
draft-va.txt \

View file

@ -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

View file

@ -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">

View file

@ -1907,6 +1907,91 @@ gst_codec_utils_mpeg4video_get_level
gst_codec_utils_mpeg4video_caps_set_level_and_profile
</SECTION>
<SECTION>
<FILE>encoding-profile</FILE>
<INCLUDE>gst/pbutils/encoding-profile.h</INCLUDE>
GstEncodingProfile
gst_encoding_profile_unref
gst_encoding_profile_ref
gst_encoding_profile_get_name
gst_encoding_profile_get_description
gst_encoding_profile_get_format
gst_encoding_profile_get_preset
gst_encoding_profile_get_presence
gst_encoding_profile_get_restriction
gst_encoding_profile_set_name
gst_encoding_profile_set_description
gst_encoding_profile_set_format
gst_encoding_profile_set_preset
gst_encoding_profile_set_restriction
gst_encoding_profile_set_presence
gst_encoding_profile_is_equal
gst_encoding_profile_get_output_caps
gst_encoding_profile_get_type_nick
<SUBSECTION container>
GstEncodingContainerProfile
gst_encoding_container_profile_new
gst_encoding_container_profile_add_profile
gst_encoding_container_profile_contains_profile
gst_encoding_container_profile_get_profiles
<SUBSECTION audio>
GstEncodingAudioProfile
gst_encoding_audio_profile_new
<SUBSECTION video>
GstEncodingVideoProfile
gst_encoding_video_profile_new
gst_encoding_video_profile_get_pass
gst_encoding_video_profile_get_variableframerate
gst_encoding_video_profile_set_pass
gst_encoding_video_profile_set_variableframerate
<SUBSECTION targets>
GST_ENCODING_CATEGORY_DEVICE
GST_ENCODING_CATEGORY_ONLINE_SERVICE
GST_ENCODING_CATEGORY_STORAGE_EDITING
GST_ENCODING_CATEGORY_CAPTURE
GstEncodingTarget
gst_encoding_target_unref
gst_encoding_target_ref
gst_encoding_target_new
gst_encoding_target_get_name
gst_encoding_target_get_category
gst_encoding_target_get_description
gst_encoding_target_get_profiles
gst_encoding_target_add_profile
gst_encoding_target_save
gst_encoding_target_save_to
gst_encoding_target_load
gst_encoding_target_load_from
<SUBSECTION Standard>
GST_ENCODING_PROFILE
GST_IS_ENCODING_PROFILE
GST_TYPE_ENCODING_PROFILE
gst_encoding_profile_get_type
GST_ENCODING_TARGET
GST_IS_ENCODING_TARGET
GST_TYPE_ENCODING_TARGET
gst_encoding_target_get_type
GstEncodingProfileClass
GST_TYPE_ENCODING_CONTAINER_PROFILE
GST_ENCODING_CONTAINER_PROFILE
gst_encoding_container_profile_get_type
GST_TYPE_ENCODING_VIDEO_PROFILE
GST_ENCODING_VIDEO_PROFILE
GST_IS_ENCODING_VIDEO_PROFILE
GstEncodingVideoProfileClass
gst_encoding_video_profile_get_type
GST_TYPE_ENCODING_AUDIO_PROFILE
GST_ENCODING_AUDIO_PROFILE
GST_IS_ENCODING_AUDIO_PROFILE
GstEncodingAudioProfileClass
gst_encoding_audio_profile_get_type
GST_IS_ENCODING_CONTAINER_PROFILE
GstEncodingContainerProfileClass
GstEncodingTargetClass
</SECTION>
# video
<SECTION>

View file

@ -59,3 +59,14 @@ gst_video_sink_get_type
#include <gst/pbutils/pbutils.h>
gst_discoverer_get_type
#include <gst/pbutils/encoding-profile.h>
#include <gst/pbutils/encoding-target.h>
gst_encoding_profile_get_type
gst_encoding_video_profile_get_type
gst_encoding_video_profile_get_type
gst_encoding_audio_profile_get_type
gst_encoding_container_profile_get_type
gst_encoding_target_get_type

View file

@ -4,6 +4,8 @@ headers_pbutils = \
pbutils.h \
codec-utils.h \
descriptions.h \
encoding-profile.h \
encoding-target.h \
install-plugins.h \
missing-plugins.h \
gstdiscoverer.h
@ -22,6 +24,8 @@ libgstpbutils_@GST_MAJORMINOR@_la_SOURCES = \
pbutils.c \
codec-utils.c \
descriptions.c \
encoding-profile.c \
encoding-target.c \
install-plugins.c \
missing-plugins.c \
gstdiscoverer.c \

View file

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

View file

@ -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__ */

View file

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

View file

@ -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__ */

View file

@ -127,6 +127,7 @@ check_PROGRAMS = \
libs/navigation \
libs/netbuffer \
libs/pbutils \
libs/profile \
libs/rtp \
libs/tag \
libs/video \
@ -238,6 +239,12 @@ libs_pbutils_LDADD = \
$(top_builddir)/gst-libs/gst/video/libgstvideo-@GST_MAJORMINOR@.la \
$(GST_BASE_LIBS) $(LDADD)
libs_profile_CFLAGS = \
$(GST_PLUGINS_BASE_CFLAGS) \
$(AM_CFLAGS)
libs_profile_LDADD = \
$(top_builddir)/gst-libs/gst/pbutils/libgstpbutils-@GST_MAJORMINOR@.la $(LDADD)
elements_appsink_CFLAGS = \
$(GST_PLUGINS_BASE_CFLAGS) \
$(AM_CFLAGS)

View file

@ -6,6 +6,7 @@ mixer
navigation
netbuffer
pbutils
profile
rtp
tag
utils

454
tests/check/libs/profile.c Normal file
View file

@ -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);

View file

@ -58,6 +58,46 @@ EXPORTS
gst_discoverer_video_info_get_width
gst_discoverer_video_info_is_image
gst_discoverer_video_info_is_interlaced
gst_encoding_audio_profile_get_type
gst_encoding_audio_profile_new
gst_encoding_container_profile_add_profile
gst_encoding_container_profile_contains_profile
gst_encoding_container_profile_get_profiles
gst_encoding_container_profile_get_type
gst_encoding_container_profile_new
gst_encoding_profile_get_description
gst_encoding_profile_get_format
gst_encoding_profile_get_name
gst_encoding_profile_get_output_caps
gst_encoding_profile_get_presence
gst_encoding_profile_get_preset
gst_encoding_profile_get_restriction
gst_encoding_profile_get_type
gst_encoding_profile_get_type_nick
gst_encoding_profile_is_equal
gst_encoding_profile_set_description
gst_encoding_profile_set_format
gst_encoding_profile_set_name
gst_encoding_profile_set_presence
gst_encoding_profile_set_preset
gst_encoding_profile_set_restriction
gst_encoding_target_add_profile
gst_encoding_target_get_category
gst_encoding_target_get_description
gst_encoding_target_get_name
gst_encoding_target_get_profiles
gst_encoding_target_get_type
gst_encoding_target_load
gst_encoding_target_load_from
gst_encoding_target_new
gst_encoding_target_save
gst_encoding_target_save_to
gst_encoding_video_profile_get_pass
gst_encoding_video_profile_get_type
gst_encoding_video_profile_get_variableframerate
gst_encoding_video_profile_new
gst_encoding_video_profile_set_pass
gst_encoding_video_profile_set_variableframerate
gst_install_plugins_async
gst_install_plugins_context_free
gst_install_plugins_context_get_type