Getting Started Guide for RidgeRun iMX6 Graphics-Server

From RidgeRun Developer Wiki


Keywords: IMX6 Nitrogen, OpenGL, GPU, Graphics-Server, rendering, hardware acceleration

Demo Video

Introduction

Graphics-Server is an API based on OpenGL 2.0 that allows you to easily make GPU hardware accelerated video, image, and text renderings. It allows you to create graphic objects such as planes or cubes with different textures, for example pictures and USB video. Also, RidgeRun's Graphics-Server gives you the ability to customize the created graphics objects and add animation effects.

RidgeRun provides a C API header and library for the interaction between your application and the Graphics-Server. The interprocess communication is done via DBUS.

Key Features

General:

  • Based on OpenGL 2.0.
  • Provides a C API for the interaction via DBUS with the graphics-server.
  • The dimensions and position of the objects are normalized values, meaning that a value of 1 indicates the whole screen width or height (depending on the parameter) regardless of the screen resolution. This allows to easily keep the graphics object aspect ratio independent of the display device.
  • Auto detect full screen resolution if the output resolution value is not set.
  • If a change in the screen resolution occurs, all what the user has to do is to call the graphicsRestore() function with the new resolution standard in order to adjust the graphics rendering to the new screen resolution.
  • Customizable alpha, position, size and rotation degrees of each graphics object.
  • Mask frames: This feature consists of a filter that give the possibility to only render a specific section in a particular shape of a video or an image. The shape and section of the rendered video/image is determined by a PNG picture who act as a mask. The alphas of the PNG mask are assigned to the video/image, so only the non-transparent pixels of the mask are rendered with the video/image, the transparent pixels of the mask are removed from the video/image (rendered as transparent pixels).
  • Chroma-Key: This feature consists of a filter that removes pixels from an image that are under the range of a specific RGB signature + RGB Threshold configured by the user. The pixels that fits in that range do not get rendered (become transparent pixels).
  • Alpha Blending: This feature allows to display frame-buffer 0 and frame-buffer 1 outputs superimposed one over the other. The Graphics-Server render its output on frame-buffer 1, so frame-buffer 0 is available for other purposes. If the Alpha blending feature is activated and the rendered output do not have a solid background, you could see the Graphics-Server output displayed on top of the content of the frame-buffer 0.

Text Rendering:

  • Text rendering supports different colors and fonts.
  • Text rendering uses a "text chart" graphic object. This automatically adjusts the size of the text string to fill the maximum possible area of the text chart, thus automatically adjusting the text size to fit in the text chart size.

Animation:

  • Available animations for any graphic object:
    • Shift (x,y plane).
    • Rotate (x,y,z axes).
    • Scale (up/down scale).
    • Fade.
  • Auto-Movement, Auto-Scaling, Auto-Rotation animations.
  • Configurable rotation rate in rotate animations.
  • Configurable movement interval (time from start to end position) and acceleration in shift animations.
  • Configurable scaling time interval in scale animations.
  • Configurable fading time interval, initial and final alpha values in fade animations.
  • Animation group: This feature consists in a group of individual and diverse elements treated as one entity as far as control tasks are concerned. This allows you to control the animation execution flow of a group of elements. For example: This make possible to start or stop the available animations of all the elements under the group at the same time.


Limitations and Future Enhancements

Limitations:

  • Only works on Vivante GPU units.
  • Currently supports display video from a USB source captured with V4l2src and using the common 640x480 resolution.
  • Currently supports to display one video object at a time.
  • Chroma-Key feature works fine with images that has well-defined colors, but has some problems with video (Display some pixels of the undesired color configured in the chroma-Key). For example: If you configured the green color to be blocked by the chroma-key feature (RGB color signature + rgb threshold), the chroma-key feature will only remove the pixels that matches exactly with the configured color signature plus threshold, if there are different green color tones (darker or lighter) in the picture that get out of the RGB range defined by the RGB color signature + threshold, those pixels will be rendered in the final image.

Future enhancement:

  • Add support to display video from different video sources (could be video streams from a file or even the network) and different standard resolutions.
  • Add support to multiple video objects at a time.
  • Improve Chroma-Key implementation to fix issues when it is applied to a video element and to be less sensitive to a specific RGB color signature.
  • Add support to render video in a cube element.
  • Add support to create different 3D figures (not only a cube, mesh loading).
  • Add shaders to support several video transformations.


System Requirements

To run Graphics-Server you need to meet the following system requirements:

  • Linux Kernel 3.0 or above version
  • OpenGL version 2.0
  • GStreamer 1.0 or above version
  • DBus
  • Vivante GPU Drivers


Installation Guide

Using the RR-SDK

The Graphics-Server has been tested using the IMX6-Nitrogen RidgeRun SDK. Following you will find the installation steps under the RR-SDK:

  • 1) Uncompress the Graphics-Server app tarball into the proprietary directory of the SDK
  • 2) Run "make config" command on the SDK root (DEVDIR)
  • 3) Select the following elements:
-> Proprietary software
 -> [*] Ridgerun Graphics Server                                                                                                                        
       -> [*] Ridgerun Graphics Library
       -> [*] Ridgerun Graphics Library demo                                                                                            
  • 4) Run "make" command on the SDK root (DEVDIR), or in the Graphics-Server directory run: "make build install"

Using any other Linux distribution

The Graphics-Server has only been installed and tested using the RidgeRun SDK for IMX6-Nitrogen platform, but it should work fine in other platforms that meet the requirements by just make a quick and easy adjustment in the configuration files, and then just run "make" command. If you are interested in running the Graphics-Server in another platform with a custom Linux distribution please feel free to contact us and we will help you in the process.


Graphics-Server API Documentation

Graphics-Server has a very complete and descriptive documentation generated by Doxygen. To get access to the API documentation go to $Graphics-Server-Installation-DIR/Doc/html/ path and open the index.html file with any browser. For example:

google-chrome Doc/html/index.html

which will open the documentation in the browser window.


Graphics-Server Screen Plane Coordinates

In the below picture you can see a diagram that specifies the coordinates of the Graphics-Server Screen Plane workspace. I it is important to recall that Graphics-Server dimensions and position of the objects are normalized values, meaning that a value of 1 indicates the whole screen width or height (depending on the parameter) regardless of the screen resolution. This allows to easily keep the graphics object aspect ratio no matter the screen resolution.

Graphics-Server Screen Plane Coordinates diagram
Graphics-Server Screen Plane Coordinates diagram


Graphics-Server Demo

We made a basic demo that expose all the Graphics-Server features to demonstrate its capabilities.

Execution commands

Graphics-Server execution commands:

  • 1) (Optional) Run in background a GStreamer pipeline that plays a video display it on frame-buffer 0. This allows showing the alpha blending capabilities of the Graphics-Server on IMX6 Nitrogen6X. The video is rendered on frame-buffer 0 and the Graphics-server output is rendered on frame-buffer 1. With alpha blending capabilities the Graphics-Server output (which does not have a solid background) is rendered on top of the playing video, allowing us to see both buffer-frames superimposed one over the other.
FB_MULTI_BUFFER=2 gst-launch-1.0 -v filesrc location=big_buck_bunny_480p_h264.mov \
! qtdemux ! queue ! vpudec ! imxeglvivsink native-display=0 &
  • 2) Run the graphics-server graphics-demo-app:
graphics-demo-app
  • 3) Stop the demo-app and Kill the graphics-server:
Ctrl c
killall graphics-server
  • 4) Restart the graphics-server:
./etc/init.d/graphics-server start

Demo Execution Results

Refer to the first section of this wiki: "Demo Video"

CPU Performance Statistics

Here is some example output from running the top -d1 command while also running the Graphics-Server demo and the background video play GStreamer pipeline:

//Before running the graphics-demo-app:
4% gst-launch-1.0 -v filesrc location=big
2% graphics-server

6% gst-launch-1.0 -v filesrc location=big
3% graphics-server

6% gst-launch-1.0 -v filesrc location=big
3% graphics-server

5% gst-launch-1.0 -v filesrc location=big
3% graphics-server

//After running the graphics-demo-app:
6% graphics-server
4% gst-launch-1.0 -v filesrc location=big
0% graphics-demo-app

8% graphics-server
5% gst-launch-1.0 -v filesrc location=big
1% graphics-demo-app

5% gst-launch-1.0 -v filesrc location=big
2% graphics-server
0% graphics-demo-app

6% gst-launch-1.0 -v filesrc location=big
4% graphics-server
0% graphics-demo-app

8% graphics-server
6% gst-launch-1.0 -v filesrc location=big
0% graphics-demo-app

10% graphics-server
6% gst-launch-1.0 -v filesrc location=big
0% graphics-demo-app

10% graphics-server
6% gst-launch-1.0 -v filesrc location=big
0% graphics-demo-app

8% graphics-server
5% gst-launch-1.0 -v filesrc location=big
0% graphics-demo-app

9% graphics-server
5% gst-launch-1.0 -v filesrc location=big
1% graphics-demo-app

8% graphics-server
4% gst-launch-1.0 -v filesrc location=big
0% graphics-demo-app

6% graphics-server
4% gst-launch-1.0 -v filesrc location=big
0% graphics-demo-app

7% graphics-server
5% gst-launch-1.0 -v filesrc location=big
0% graphics-demo-app

6% graphics-server
5% gst-launch-1.0 -v filesrc location=big
0% graphics-demo-app

8% graphics-server
5% gst-launch-1.0 -v filesrc location=big
1% graphics-demo-app

Demo Code

You can find the demo source code under: $GRAPHICS_SERVER_INSTALL_DIR/src/src/demo/main.c

//--------------------------------------------------------------------------------------
// File: main.cpp
//--------------------------------------------------------------------------------------
#include <iostream>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <fcntl.h>
#include <malloc.h>
#include <math.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <termios.h>
#include <unistd.h>
#include <time.h>

#include <pthread.h>
#include <sys/time.h>

#include "graphics-client.h"

#define DEBUG 1
#include "debug.h"

#include <sys/ioctl.h>
#include <fcntl.h>   
#include <unistd.h>  
#include <linux/videodev2.h>

#include <linux/mxcfb.h>

#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>

bool fade_in;

/* Returns an integer in the range [0, n).
 *
 * Uses rand(), and so is affected-by/affects the same seed.
 */
int randint(int n) {
  if ((n - 1) == RAND_MAX) {
    return rand();
  } else {
    // Chop off all of the values that would cause skew...
    long end = RAND_MAX / n; // truncate skew
    assert (end > 0L);
    end *= n;

    // ... and ignore results from rand() than fall above that limit.
    // (Worst case the loop condition should succeed 50% of the time, so we can
    // expect to bail out of this loop pretty quickly.)
    int r;
    while ((r = rand()) >= end);

    return r % n;
  }
}

//Callback function that evaluates move/fade animations end flag in an asynchronous way (execute actions in a separated tread)
void on_graphicsMessageCallback(Graphics *object, gint type, const gchar *tag){	
	switch(type){
		case ANIMATION_MOVING_END:
			/* Upscale animation of logo plane picture */
			graphicsStartAutoScaling("logo2");
			graphicsSetVisible("logo2", true);
			sleep(3);
			/* Fade-in animation of logo plane picture */
	        graphicsSetFadingInterval("logo2", 230, 0, 3000);
	        graphicsEnableFading("logo2", true);
	        graphicsEnableEmitMessage("logo", false);
	        graphicsEnableEmitMessage("logo2", true);
	        graphicsStartFading("logo2");
	        fade_in = true;
	        break;
		case ANIMATION_FADING_END:
		    /* Fade-in/fade-out continuous animation of logo plane picture */
		    if (fade_in==true){
				graphicsSetFadingInterval("logo2", 0, 230, 3000);
				graphicsStartFading("logo2");
				fade_in = false;
			}
			else{
				graphicsSetFadingInterval("logo2", 230, 0, 3000);
				graphicsStartFading("logo2");
				fade_in = true;
			}
			break;
		default: break;
	}
	debug_info("Getting message (%d) from (%s)\n", type, tag);
}


int main (int argc, char **argv)
{	
        //Enable alpha blending of frame-buffer 1. Displayed output will be a blend of fb0 and fb1.
	int alpha_blend = alpha_pixel_enable(1); 
	
	/*INIT*/
	graphicsInit();
	
	/*Rotary and movable RidgeRun Logo picture cube element*/
	graphicsNewPicture("logo", "/usr/share/ridgerun/media/RR-Logo.png", GRAPHICS_SURFACE_CUBE);
	graphicsSetRotationRate("logo", 0, 90, 0);
	graphicsSetSize("logo", 0.15, 0.15, OBJECT_TOP_LEFT);
	graphicsSetMoveAcceleration("logo", 0.2);
	graphicsSetMoveInterval("logo", 0.1, 0.9, 0.125, 0.15, 6000);
	graphicsEnableAutoRotation("logo", true);
	graphicsEnableAutoMovement("logo", true);
	graphicsEnableEmitMessage("logo", true);
	graphicsSetVisible("logo", true);
	graphicsStartAutoRotation("logo");
	graphicsStartAutoMovement("logo");
	
	/*Rotary, masked and movable video element*/
	graphicsNewVideo("video", "auto", 0.0, 0.0);
	graphicsSetVisible("video", false);
	graphicsSetSize("video",0.35,0.35, OBJECT_TOP_LEFT);
	graphicsSetMask("video", "/usr/share/ridgerun/media/gear.png");
	graphicsSetMoveAcceleration("video", 0);
	graphicsSetMoveInterval("video", 0.0, 0.0, 0.5, 0.5, 6000);
	graphicsSetRotationRate("video", 45, 45, 0);
	graphicsEnableMask("video", true);
	graphicsEnableAutoMovement("video", true);
	graphicsEnableAutoRotation("video", true);
	graphicsSetVisible("video", true);
	graphicsStartAutoMovement("video");
	graphicsStartAutoRotation("video");
	
	/* Fading and scalable logo plane picture */
	graphicsNewPicture("logo2", "/usr/share/ridgerun/media/RR-Logo.png", GRAPHICS_SURFACE_PLANE);
	graphicsSetPosition("logo2", 0.2, 0.7);
	graphicsSetScalingCenter("logo2", OBJECT_CENTER);
	graphicsSetScalingInterval("logo2", 0.05, 0.05, 0.25, 0.15, 3000);
	graphicsEnableAutoScaling("logo2", true);
	graphicsSetAlpha("logo2", 230);
	
	/*Text chart element*/
	graphicsNewText("text", "/usr/share/fonts/truetype/tlwg/TlwgTypewriter-BoldOblique.ttf");
	graphicsSetSize("text", 0.2, 0.1, OBJECT_TOP_LEFT);
	graphicsSetPosition("text", 0.5, 0.1);
	graphicsSetVisible("text", true);
	graphicsSetText("text", "GRAPHICS SERVER");
	
	usleep(4*1000*1000);
	
	/*Text chart element -> Changing text content*/
	char text[16];
	for(int i = 0; i < 10; i++){
		sprintf(text, "CHANGING TEXT (%d)", i);
		graphicsSetText("text", text);
		sleep(1);
	}

    /* Changing Text Font */
	char fonts[6][64];
	sprintf(fonts[0],"/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans-BoldOblique.ttf");
	sprintf(fonts[1], "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono-Bold.ttf");
	sprintf(fonts[2], "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansCondensed.ttf");
	sprintf(fonts[3], "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSerif-Italic.ttf");
	sprintf(fonts[4], "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSerifCondensed-BoldItalic.ttf");
	sprintf(fonts[5], "/usr/share/fonts/truetype/tlwg/TlwgTypewriter-BoldOblique.ttf");
	
	for (int i = 0; i < 6; i++){
		graphicsSetFont("text", fonts[i]);
		graphicsSetText("text", "CHANGING FONT");
		sleep(2);
	}

	/* Changing Text Color */
	graphicsSetText("text", "CHANGING COLOR");
	for (int i = 0; i < 10; i++){
		graphicsSetFontColor("text", randint(255), randint(255), randint(255));
		sleep(2);
	}
	
	graphicsSetText("text", "DONE!!");
	
	// Continuous demo loop
	while(1){
		usleep(100000);
		debug_info("Continuous demo loop.\n");
		}
	
	debug_info("Exit\n");

	// Destroy objects
	graphicsDestroy();
	
	return 0;
}

Demo Code Overview

Rotary and movable RidgeRun Logo picture cube element

This are the necessary functions to create the rotary and movable cube picture element of the demo:

// Creates a new picture element from a given path. GRAPHICS Surface Cube picture element with RidgeRun Logo
graphicsNewPicture("logo", "/usr/share/ridgerun/media/RR-Logo.png", GRAPHICS_SURFACE_CUBE);
// Set Rotation Rate = 90 degrees/second in Y axis
graphicsSetRotationRate("logo", 0, 90, 0);
// Set element size -> 0.15x0.15 (Width x Height Normalized) Scaled from Top Left corner
graphicsSetSize("logo", 0.15, 0.15, OBJECT_TOP_LEFT);
// Set moving animation acceleration
graphicsSetMoveAcceleration("logo", 0.2);
// Set time duration, initial and final position of the moving animation 
graphicsSetMoveInterval("logo", 0.1, 0.9, 0.125, 0.15, 6000);
// Enable element Auto-rotation animation
graphicsEnableAutoRotation("logo", true);
// Enable element Auto-movement animation
graphicsEnableAutoMovement("logo", true);
// Enable element to emit end-animation flag.
graphicsEnableEmitMessage("logo", true);
// Set visible the element on screen. Enable element rendering
graphicsSetVisible("logo", true);
// Start picture cube element rotation animation
graphicsStartAutoRotation("logo");
// Start picture cube element movement animation
graphicsStartAutoMovement("logo");

Rotary, masked and movable video element

This are the necessary functions to create the rotary, masked and movable video element of the demo:

// Creates a new video object
graphicsNewVideo("video", "auto", 0.0, 0.0);
// Set invisible the element on screen. Disable element rendering
graphicsSetVisible("video", false);
// Set element size -> 0.3x0.3 (Width x Height Normalized) Scaled from Top Left corner
graphicsSetSize("video",0.35,0.35, OBJECT_TOP_LEFT);
// Set Mask frame (The video will be only rendered in the non-transparent pixels of the png mask picture).
graphicsSetMask("video", "/usr/share/ridgerun/media/gear.png");
// Set moving animation acceleration
graphicsSetMoveAcceleration("video", 0);
// Set time duration, initial and final position of the moving animation 
graphicsSetMoveInterval("video", 0.0, 0.0, 0.5, 0.5, 6000);
// Set Rotation Rate = 45 degrees/second in X and Y axis
graphicsSetRotationRate("video", 45, 45, 0);
// Enable Mask frame on the element
graphicsEnableMask("video", true);
// Enable element Auto-movement animation
graphicsEnableAutoMovement("video", true);
// Enable element Auto-rotation animation
graphicsEnableAutoRotation("video", true);
// Set visible the element on screen. Enable element rendering
graphicsSetVisible("video", true);
// Start element Auto-movement animation
graphicsStartAutoMovement("video"); 
// Start element Auto-rotation animation
graphicsStartAutoRotation("video");

Fading and scalable logo plane picture element

This are the necessary functions to set the fading and scalable animation to the logo picture element of the demo:

// Creates a new picture element from a given path. GRAPHICS Surface Cube picture element with RidgeRun Logo
graphicsNewPicture("logo2", "/usr/share/ridgerun/media/RR-Logo.png", GRAPHICS_SURFACE_PLANE);
// Set element position -> Element normalized top-left corner=(0.2,0.7) Note:Top left corner of the screen (0,0) is the plane start point
graphicsSetPosition("logo2", 0.2, 0.7);
// Set scaling animation center point
graphicsSetScalingCenter("logo2", OBJECT_CENTER);
// Set time duration, initial and final size of the scaling animation
graphicsSetScalingInterval("logo2", 0.05, 0.05, 0.25, 0.15, 3000);
// Enable the auto-scaling animation 
graphicsEnableAutoScaling("logo2", true);
// Set element initial alpha 
graphicsSetAlpha("logo2", 230);
                                      ==
                                      ==

//Callback function that evaluates move/fade animations end flag in an asynchronous way (execute actions in a separated tread)
void on_graphicsMessageCallback(Graphics *object, gint type, const gchar *tag){	
	switch(type){
		case ANIMATION_MOVING_END:
			/* Upscale animation of logo plane picture */
                        // Start the auto-scaling animation
			graphicsStartAutoScaling("logo2");
			// Set visible the element on screen. Enable element rendering
                        graphicsSetVisible("logo2", true);
			sleep(3);
			/* Fade-in animation of logo plane picture */
                        // Sets the fading interval. Initial_alpha=230, Final_alpha=0, transitiom_time(ms)=3000
	                graphicsSetFadingInterval("logo2", 230, 0, 3000);
	                // Enable the fading animation for the element
                        graphicsEnableFading("logo2", true);
                        // Disable element to emit end-animation flag.
	                graphicsEnableEmitMessage("logo", false);
                        // Enable "End animation" message and flag. The user can use this flag to determine when moving or fading animation ends
	                graphicsEnableEmitMessage("logo2", true);
	                // Start fading animation
                        graphicsStartFading("logo2");
	                fade_in = true;
	                break;
		case ANIMATION_FADING_END:
		    /* Fade-in/fade-out continuous animation of logo plane picture */
		    if (fade_in==true){
				graphicsSetFadingInterval("logo2", 0, 230, 3000);
				graphicsStartFading("logo2");
				fade_in = false;
			}
			else{
				graphicsSetFadingInterval("logo2", 230, 0, 3000);
				graphicsStartFading("logo2");
				fade_in = true;
			}
			break;
		default: break;
	}
	debug_info("Getting message (%d) from (%s)\n", type, tag);
}

Text chart element

This are the necessary functions to create the text chart element of the demo:

     // Creates a new text object with the given font path 
     graphicsNewText("text", "/usr/share/fonts/truetype/tlwg/TlwgTypewriter-BoldOblique.ttf");
     // Set element size -> 0.2x0.1 (Width x Height Normalized) Scaled from Top Left corner.
     graphicsSetSize("text", 0.2, 0.1, OBJECT_TOP_LEFT);
     // Set element position -> Element normalized top-left corner=(0.5,0.1) Note:Top left    corner of the screen (0,0) is the plane start point
     graphicsSetPosition("text", 0.5, 0.1);
     // Set visible the element on screen. Enable element rendering
     graphicsSetVisible("text", true);
     // Set text content of the text element
     graphicsSetText("text", "RIDGERUN");
    /*Text chart element -> Changing text content*/
	char text[16];
	for(int i = 0; i < 10; i++){
		sprintf(text, "CHANGING TEXT (%d)", i);
		graphicsSetText("text", text);
		sleep(1);
	}

    /* Changing Text Font */
	char fonts[6][64];
	sprintf(fonts[0],"/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans-BoldOblique.ttf");
	sprintf(fonts[1], "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono-Bold.ttf");
	sprintf(fonts[2], "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansCondensed.ttf");
	sprintf(fonts[3], "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSerif-Italic.ttf");
	sprintf(fonts[4], "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSerifCondensed-BoldItalic.ttf");
	sprintf(fonts[5], "/usr/share/fonts/truetype/tlwg/TlwgTypewriter-BoldOblique.ttf");
	
        // Changing font loop
	for (int i = 0; i < 6; i++){
		graphicsSetFont("text", fonts[i]);
		graphicsSetText("text", "CHANGING FONT");
		sleep(2);
	}

	/* Changing Text Color */
	graphicsSetText("text", "CHANGING COLOR");
        // Changing color loop. The color is assigned in an aleatory way 
	for (int i = 0; i < 10; i++){
		graphicsSetFontColor("text", randint(255), randint(255), randint(255));
		sleep(2);
	}
	
	graphicsSetText("text", "DONE!!");


Set Debug Level

To change the debug level of the Graphics-Server, you have to change the DEBUG_LEVEL_CONFIG variable value on the principal Makefile accordingly to the following description and recompile the app. By default this variable is set to 0 (No debug).

 #~  DEBUG_LEVEL:
 #~ * 0:	print only errors
 #~ * 1:	print errors and warnings
 #~ * 2:	print errors, warnings and info messages
 #~ * 3:	print errors, warnings, info and debug messages
 #~ * 4:	print errors, warnings, info, debug and log messages
 #~ * 5:	print errors, warnings, info, debug, log and trace messages
DEBUG_LEVEL_CONFIG=0