1. About -------- - What is QtGstreamer? QtGstreamer aims to become a library providing C++ bindings for Gstreamer [1] with a Qt-style API plus some helper classes for integrating Gstreamer better in Qt [2] applications. [1]. http://gstreamer.freedesktop.org/ [2]. http://qt.nokia.com/ - What is QtGstreamer’s development state at the moment? QtGstreamer is still under development, but might be suitable for simple uses. However, note that there is no source or binary compatibility guarantee yet, so if you want to use QtGstreamer in your project, I would recommend to ship it with your sources and build it as a static library. - What are the differences between the C++ bindings of QtGstreamer and Gstreamermm? * QtGstreamer provides bindings that completely hide the Gstreamer ABI, so your application doesn’t need to link to Gstreamer itself. * QtGstreamer uses QtCore helper classes (QString, QList, etc..) where it can, to ease integration with Qt. * QtGstreamer provides support for connecting arbitrary GObject signals to slots, while in Gstreamermm every signal needs to be defined in the bindings, or else you need to use the C API for connecting it. This is especially useful for connecting signals from element plugins, where their interface is unknown at compile time. 2. Building ----------- 2.1 Dependencies ---------------- QtGstreamer requires the following software to be installed in order to build: * CMake 2.6 or later * Gstreamer 0.10.30 or later With its dependencies: - Glib / GObject * Qt 4 * Automoc * Boost (static_assert, type_traits, function, bind, preprocessor) * Flex * Bison 2.2 Compiler ------------ A decent compiler with proper support for advanced templates, including features such as partial template specialization, is required. QtGstreamer can also make use of C++0x features (see below for details). A compiler supporting at least some of them is recommended. Currently, only the GNU C++ compiler (g++) version 4.3 or later is known to support all the features that QtGstreamer uses. However, other compilers can be used too, but with some limitations. C++0x features in use: * static_assert(). Used to show nice error messages when the programmer is trying to use some template in the wrong way. If not present, the templates will still fail to compile if used in the wrong way, but the error messages may be quite weird to understand... * Variadic templates together with rvalue references. Used to support connecting and emitting GObject signals with any number of arguments. If not available, a hack-ish implementation using boost's preprocessor library, boost::function and boost::bind is used to provide support for up to 9 arguments. 2.3 Procedure ------------- The build procedure is simple: $ mkdir build && cd build $ cmake .. -DCMAKE_INSTALL_PREFIX=/path/to/installation/prefix $ make $ make install The above commands will build and install QtGstreamer as a shared library. If you prefer to build QtGstreamer as a static library, pass the -DSTATIC_QTGSTREAMER=1 option to cmake, like that: $ cmake .. -DCMAKE_INSTALL_PREFIX=/path/to/installation/prefix -DSTATIC_QTGSTREAMER=1 2.4 Generating documentation ---------------------------- QtGstreamer uses doxygen for documentation. To generate the documentation you need to install doxygen and run "make doc" after you have run cmake. This will generate the documentation in /doc/html/. 3. Using QtGstreamer -------------------- 3.1. Build system integration ----------------------------- If you are using cmake as your build system, using QtGstreamer is quite easy. You can just do: find_package(QtGstreamer) which will find QtGstreamer and define the following variables: QTGSTREAMER_FOUND - system has QtGstreamer QTGSTREAMER_INCLUDE_DIR - the QtGstreamer include directory QTGSTREAMER_INCLUDES - the include directories needed to use QtGstreamer QTGSTREAMER_LIBRARY - the QtGstreamer library QTGSTREAMER_LIBRARIES - the libraries needed to use QtGstreamer QTGSTREAMER_DEFINITIONS - definitions recommended for using QtGstreamer QTGSTREAMER_FLAGS - extra compiler switches recommended for using QtGstreamer Take a look at the CMakeLists.txt of the QtGstreamer examples to see how to use them. Alternatively, if you are using qmake, you can manually set the required variables, as demonstrated in the example qmake project files that you can find together with the QtGstreamer examples. Unfortunately qmake does not support dynamic detection of installed libraries, so those variables have to be set manually, or you will have to write some wrapper "configure" script that generates a qmake project file. This is quite painful, compared to cmake, thus cmake is recommended. 3.2. Headers ------------ The correct way to include a certain QtGstreamer header for a class is to use the #include syntax. For example: #include All the other lowercase headers (which all end with .h) are considered private and should not be used directly. 4. Developing QtGstreamer ------------------------- 4.1. Coding style ----------------- QtGstreamer follows the kdelibs coding style: http://techbase.kde.org/Policies/Kdelibs_Coding_Style 4.2. Naming policies -------------------- 4.2.1. The namespaces --------------------- The "G" namespace (GObject, GValue, etc...) is referred to as "QGlib". The "Gst" namespace (GstObject, GstElement, etc...) is referred to as "QGst". I didn't like them much when I chose them, better names could be discussed... 4.2.2. The class names ---------------------- Class names should be the same as their G* equivalents, with the namespace prefix removed. For example, "GstObject" becomes "QGst::Object", "GParamSpec" becomes "QGlib::ParamSpec", etc... 4.2.3. The method names ----------------------- In general the method names should be the same as the gstreamer ones, with the g[st]_ prefix removed and converted to camel case. For example, gboolean gst_caps_is_empty(const GstCaps *caps); becomes: bool isEmpty() const; (and member of the QGst::Caps class) There are cases where this may not be followed: 1) Properties. Most property getters have a "get" prefix, for example, gst_object_get_name(). In QtGstreamer the "get" prefix is omitted, so this becomes just name(). 2) Overloaded members. In C there is no possibility to have two methods with the same name, so overloaded members usually have some extra suffix, like "_full". For example, g_object_set_data and g_object_set_data_full. In C++ we just add a method with the same name, or put optional parameters in the existing method. 3) Other cases where the glib/gstreamer method name doesn't make much sense... For example, gst_element_is_locked_state(). That doesn't make sense in english, as "state" is the subject and should go before the verb "is". So, it becomes stateIsLocked(). 4.3. Refcounted wrappers policy ------------------------------- All reference counted classes must: 1) Inherit from QGlib::RefCountedObject and implement its virtual ref() and unref() methods (and possibly makeWritable() too). 2) Include the QGLIB_WRAPPER (or QGST_WRAPPER) macro in their class declaration. This is used like this: QGST_WRAPPER(ClassName). 3) Be used with QGlib::RefPointer and provide a typedef QGlib::RefPointer ClassNamePtr; No constructor/destructor/copy constructor/assignment operator is allowed for these classes and they are all defined as private in the QGLIB_WRAPPER/QGST_WRAPPER macros. RefPointer always creates a new instance of the wrapper class every time it is copied, but it keeps the m_object protected variable of RefCountedObject pointing to the same underlying glib/gstreamer object, using ref()/unref() to keep its reference count correct. For classes that implement the makeWritable() virtual method, this method is always called before accessing a non-const member function. This is to implement semantics similar to Qt's implicit sharing for gstreamer classes that use the concept of being writable only when their reference count is 1, such as GstMiniObject and GstCaps. The idea is that makeWritable() makes a copy of the object if its reference count is higher than 1, so when one accesses a non-const method on an object that has more than one references, it is automatically copied. 4.4. About codegen ------------------ Codegen is a simple code generator that does two basic jobs: 1) It generates all the implementations of the QGlib::GetType specializations. GetType() is used to get the GType of a type at runtime. Since we don't want the target application to include any glib/gstreamer headers and/or link to glib/gstreamer directly, this is the only way to be able to find the GType of a class in a template class or method, such as RefPointer::dynamicCast(), Value::init(), etc... The header declaration of all these specializations is added on the header of each class, with the QGLIB_REGISTER_TYPE() macro. This defines the declaration of the specialization and also acts as a keyword for codegen, which then generates the implementation. The usage is simple. For example: QGLIB_REGISTER_TYPE(QGst::Element) With this declaration, codegen will generate an implementation that returns GST_TYPE_ELEMENT. If a class name doesn't exactly reflect its GType getter macro, then one can tell codegen which is the real GType macro with a special "codegen instruction" comment after the QGLIB_REGISTER_TYPE keyword that goes like this: //codegen: GType=GST_TYPE_FOO For example, QGLIB_REGISTER_TYPE(QGlib::ParamSpec) would generate an implementation that returns G_TYPE_PARAM_SPEC. However, that macro doesn't really exist, the correct one is G_TYPE_PARAM. So, we define it like this: QGLIB_REGISTER_TYPE(QGst::ParamSpec) //codegen: GType=G_TYPE_PARAM 2) It generates static assertions for all the enums to make sure that their value is exactly the same as their glib/gstreamer equivalent. This is just used as a safety test for developers and doesn't have any impact on the library. Since, according to the coding style, all enums should be camel case, starting with a capital and glib's coding style says all enums should be capitals with underscores for separators, codegen does a style conversion to find out the glib/gstreamer equivalent of the enum. An enum that is defined as: FooBar in the namespace QGst will become GST_FOO_BAR. If an enum is defined in such a way that the conversion is not accurate, then one can use a "codegen instruction" after the opening brace of the enum definition that goes like this: //codegen: EnumToBeConverted=ENUM_HOW_IT_SHOULD_BE_CONVERTED, SecondEnum=SECONDENUM , ... This will assume that "EnumToBeConverted" is "GST_ENUM_HOW_IT_SHOULD_BE_CONVERTED" (assuming that the namespace is QGst), and similar for "SecondEnum" -> GST_SECONDENUM A real world example: ---- snip ---- namespace QGst { enum PadLinkReturn { //codegen: PadLinkNoFormat=PAD_LINK_NOFORMAT, PadLinkNoSched=PAD_LINK_NOSCHED PadLinkOk = 0, PadLinkWrongHierarchy = -1, PadLinkWasLinked = -2, PadLinkWrongDirection = -3, PadLinkNoFormat = -4, PadLinkNoSched = -5, PadLinkRefused = -6 }; } QGLIB_REGISTER_TYPE(QGst::PadLinkReturn) ---- endsnip ---- For this snippet, codegen will generate: ---- snip ---- QGLIB_REGISTER_TYPE_IMPLEMENTATION(QGst::PadLinkReturn,GST_TYPE_PAD_LINK_RETURN) namespace QGst { BOOST_STATIC_ASSERT(static_cast(PadLinkOk) == static_cast(GST_PAD_LINK_OK)); BOOST_STATIC_ASSERT(static_cast(PadLinkWrongHierarchy) == static_cast(GST_PAD_LINK_WRONG_HIERARCHY)); BOOST_STATIC_ASSERT(static_cast(PadLinkWasLinked) == static_cast(GST_PAD_LINK_WAS_LINKED)); BOOST_STATIC_ASSERT(static_cast(PadLinkWrongDirection) == static_cast(GST_PAD_LINK_WRONG_DIRECTION)); BOOST_STATIC_ASSERT(static_cast(PadLinkNoFormat) == static_cast(GST_PAD_LINK_NOFORMAT)); BOOST_STATIC_ASSERT(static_cast(PadLinkNoSched) == static_cast(GST_PAD_LINK_NOSCHED)); BOOST_STATIC_ASSERT(static_cast(PadLinkRefused) == static_cast(GST_PAD_LINK_REFUSED)); } ---- endsnip ---- 4.5. How to contribute ---------------------- Simply clone the repository on gitorious, develop the feature that you want there and when it's ready, send me a merge request. -- George Kiagiadakis Last updated: 11 July 2010