data/attach/1907/fjoc0btieiuzbbimo7dix150ms8eemnt.jpg
在基于linux的嵌入式仿真平台开发中,终端的美观和可定制是一个重要的问题。单调的“白纸黑字”型表现方式可谓大煞风景。改造linux控制台使之美观可定制地展示开机信息和logo成为基于嵌入式linux应用的一项重要工作。
在本节主要讲解如何使用DirectFB来实现开机动画
架构
详细设计
DFB资源初始化
主要使用 DirectFB、Layer、Window、Surface这四种资源,其关系见资料“DirectFB、Layer、Window、Surface之间关系”
DirectFBInit(&argc, &argv);
DirectFBCreate(&dfb);
/* Get the display layer.*/
dfb->GetDisplayLayer(dfb, 0, &layer);
layer->GetConfiguration(layer, &config);
/* Create the window. */
layer->CreateWindow(layer, &desc, &window);
window->SetOpacity(window, 0xFF);
/* Get the window's surface. */
window->GetSurface(window, surface);
DFB资源释放
/* Release the window's surface. */
surface->Release(surface);
/* Release the window. */
window->Release(window);
/* Release the layer. */
layer->Release(layer);
dfb->Release(dfb);
图片资源初始化
DFBSurfaceDescription img_dsc;
IDirectFBImageProvider *provider = NULL;
/* 将要显示的图片及其相关信息保存在一个imageprovider中 */
ret = dfb->CreateImageProvider(dfb, filename, &provider);
/* 将保存在provider中的图片信息提取出来,存于surface description中 */
ret = provider->GetSurfaceDescription(provider, &img_dsc);
/* 根据surface description创建surface,尺寸与图片大小完全一致 */
ret = dfb->CreateSurface(dfb, &img_dsc, surface);
/* 将图片呈递给刚才建立的logo平面,如果大小不一致,则进行缩放 */
ret = provider->RenderTo(provider, *surface, NULL);
/* release provider */
provider->Release(provider);
图片资源初始化
imgSfc->Release(imgSfc);
动画渲染
static void fillDFBSurface(
IDirectFBSurface *primary_sfc,
IDirectFBSurface *img_sfc,
int x, int y)
{
primary_sfc->Clear(primary_sfc, 0, 0, 0, 255);
/*
* blit即将两张位图(即thiz和source)按拉操作的方法组合成一张图片。
* 在DirectFB中,其定义的动作也是合理的:将img_sfc blit到primary_sfc上去,
* 两个平面上的内容会产生叠加
*/
primary_sfc->Blit(primary_sfc, img_sfc, NULL, x, y);
/* 变换、更新surface buffer */
primary_sfc->Flip(primary_sfc, NULL, DSFLIP_WAITFORSYNC);
return ;
}
全文代码示例
/**********************************************
* Author: younger.liucn@hotmail.com
* File name: animation.c
* Description: animation
* Version, Desc
* 1.1 Created
**********************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "animation.h"
/* config information */
#define ANIM_IMAGES_COUNT 12
/* support png, jpg */
#define ANIM_IMAGE_FORMAT "png"
#define ANIM_FILE_NAME_MAX_SIZE 255
#define ANIM_IMG_DEFAULT_WIDTH 960
#define ANIM_IMG_DEFAULT_HEIGHT 540
#define ANIM_IMG_DEFAULT_FPS 10
#define ANIM_MAX_RUNNING_MTIME (20000)
#define ANIM_BLACK_IMAGE "/home/younger/DFB/animApp/images/black.png"
#define ANIM_DEFAULT_LOGO_NAME "/home/younger/DFB/animApp/images/welcome.jpg"
#define ANIM_DEFAULT_LOGO_PATH "/home/younger/DFB/animApp/images/default"
/*********************************************************
* log flags and func of debug and error infor.[Begin]
********************************************************/
//#define ANIM_SYS_LAYER
//#define _ANIM_DEBUG_
#ifdef _ANIM_DEBUG_
#define ANIM_DEBUG(format, ...) do {
printf("[BootAnimation:%4dL]DEBUG: "format, __LINE__, ##__VA_ARGS__);
} while (0)
#else
#define ANIM_DEBUG(format, ...) do {} while (0)
#endif
#define ANIM_NOTICE(format, ...) do {
printf("[BootAnimation:%4dL]INFO: "format, __LINE__, ##__VA_ARGS__);
} while (0)
#define ANIM_ERROR(format, ...) do {
printf("[BootAnimation:%4dL]ERROR: "format, __LINE__, ##__VA_ARGS__);
} while (0)
#define DFBCHECK(x...)
do {
DFBResult err = x;
if (err != (DFBResult)DFB_OK)
{
fprintf(stderr, "[%s:%s() L:%u] DFB Error:", __FILE__, __FUNCTION__, __LINE__);
DirectFBErrorFatal(#x, err);
}
} while(0)
/*********************************************************
* log flags and func of debug and error infor.[End]
********************************************************/
/*********************************************************
* Data structure and Global variants [Begin]
********************************************************/
/* 使用directFB画图所需的四个DFB资源 */
struct bootanimation_dsc {
IDirectFB *dfb;
IDirectFBDisplayLayer *layer;
IDirectFBWindow *window;
IDirectFBSurface *surface;
};
static struct bootanimation_dsc badsc;
/* 定义图片Surface */
static IDirectFBSurface *imgSfc[ANIM_IMAGES_COUNT];
/*********************************************************
* Data structure and Global variants [End]
********************************************************/
/*********************************************************
* Some functions help animation [Begin]
********************************************************/
/* if exist, return 1; otherwise, return 0. */
static inline int checkFileExist(const char *filename)
{
if((access(filename, R_OK)) != -1)
return 1;
return 0;
}
/*********************************************************
* Some functions help animation [End]
********************************************************/
void freeResources()
{
/* Release the window's surface. */
if(badsc.surface)
badsc.surface->Release(badsc.surface);
/* Release the window. */
if (badsc.window)
badsc.window->Release(badsc.window);
/* Release the layer. */
if (badsc.layer)
badsc.layer->Release(badsc.layer);
badsc.dfb->Release(badsc.dfb);
return ;
}
static void initResources(int argc, char **argv)
{
DFBResult ret;
badsc.window = NULL;
badsc.surface = NULL;
badsc.dfb = NULL;
IDirectFB *dfb = NULL;
DFBWindowDescription desc;
DFBDisplayLayerConfig config;
/* 初始化DirectFB */
DirectFBInit(&argc, &argv);
DirectFBCreate(&dfb);
if (!dfb) {
ANIM_ERROR("directfb interface is NULL
");
return ;
}
badsc.dfb = dfb;
/* 初始化 display layer:其中ANIM_LAYERID_USING设置为0.*/
ret = badsc.dfb->GetDisplayLayer(badsc.dfb, ANIM_LAYERID_USING, &(badsc.layer));
if(ret != (DFBResult)DFB_OK) {
ANIM_ERROR("Get layer(%d) failed!
", ANIM_LAYERID_USING);
goto fail;
} else {
ANIM_DEBUG("Get layer(%d) independently.
", ANIM_LAYERID_USING);
}
/* 获取display layer的配置,. */
badsc.layer->GetConfiguration(badsc.layer, &config);
/* 设置window参数,并创建Window */
desc.flags = (DFBWindowDescriptionFlags)(DWDESC_POSX | DWDESC_POSY | DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_CAPS | DWDESC_OPTIONS);
desc.posx = 0;
desc.posy = 0;
desc.width = config.width;
desc.height = config.height;
desc.caps = (DFBWindowCapabilities)(DWCAPS_NODECORATION);
desc.options = (DFBWindowOptions) (DWOP_GHOST);
ret = badsc.layer->CreateWindow(badsc.layer, &desc, &(badsc.window));
if(ret != (DFBResult)DFB_OK) {
ANIM_ERROR("Create window failed!
");
goto fail;
}
/* 设置透明度 */
ret = badsc.window->SetOpacity(badsc.window, 0xFF);
if(ret != (DFBResult)DFB_OK) {
ANIM_ERROR("SetOpacity failed!
");
goto fail;
}
/* 获取window的surface. */
ret = badsc.window->GetSurface(badsc.window, &(badsc.surface));
if(ret != (DFBResult)DFB_OK) {
ANIM_ERROR("SetOpacity failed!
");
goto fail;
}
return ;
fail:
freeResources();
return ;
}
/* free images */
static void deinitImages()
{
int i = 0;
for (i = 0; i <= ANIM_IMAGES_COUNT; i++) {
if (imgSfc[i]) {
imgSfc[i]->Release(imgSfc[i]);
} else {
break;
}
}
return ;
}
static int doLoadImg(const char *filename,
IDirectFBSurface **surface,
unsigned int *width,
unsigned int *height)
{
int ret;
IDirectFB *dfb = badsc.dfb;
DFBSurfaceDescription img_dsc;
IDirectFBImageProvider *provider = NULL;
if(NULL == surface || NULL == filename) {
ANIM_ERROR("doLoadImg() failed for %d.
", -EINVAL);
return -EINVAL;
}
ANIM_DEBUG("doLoadImg() entry:%s .
", filename);
if(!checkFileExist(filename)) {
ANIM_ERROR("file %s does not exist.
", filename);
return -EINVAL;
}
/* 将要显示的图片及其相关信息保存在一个image provider中 */
ret = dfb->CreateImageProvider(dfb, filename, &provider);
if(ret) {
ANIM_ERROR("CreateImageProvider() for %s failed %d.
", filename, ret);
return ret;
}
/* 将保存在provider中的图片信息提取出来,存于surface description中 */
ret = provider->GetSurfaceDescription(provider, &img_dsc);
if(ret) {
ANIM_ERROR("GetSurfaceDescription() for %s failed %d.
",
filename, ret);
provider->Release(provider);
return ret;
}
/* 根据surface description创建surface,尺寸与图片大小完全一致 */
ret = dfb->CreateSurface(dfb, &img_dsc, surface);
if(ret) {
ANIM_ERROR("CreateSurface() for %s failed %d.
", filename, ret);
provider->Release(provider);
return ret;
}
/* 将图片呈递给刚才建立的logo平面,如果大小不一致,则进行缩放 */
ret = provider->RenderTo(provider, *surface, NULL);
if(ret) {
ANIM_ERROR("RenderTo() for %s failed %d.
", filename, ret);
(*surface)->Release(*surface);
provider->Release(provider);
return ret;
}
/* Return width / height? */
if(width) {
*width = img_dsc.width;
}
if(height){
*height = img_dsc.height;
}
/* release provider */
provider->Release(provider);
ANIM_DEBUG("doLoadImg() exit.
");
return ret;
}
static int initImages()
{
int ret = 0, i = 0;
char filename[ANIM_FILE_NAME_MAX_SIZE];
IDirectFBSurface *tmp_sfc = NULL;
for (i = 0; i < ANIM_IMAGES_COUNT; i++) {
imgSfc[i] = NULL;
}
for (i = 0; i < ANIM_IMAGES_COUNT; i++) {
tmp_sfc = NULL;
memset(filename, 0x0, sizeof(filename));
snprintf(filename, ANIM_FILE_NAME_MAX_SIZE,
"%s/%d.%s", ANIM_DEFAULT_LOGO_PATH, i, ANIM_IMAGE_FORMAT);
ret = doLoadImg(filename, &tmp_sfc, NULL, NULL);
if (ret != 0) {
goto bail;
}
imgSfc[i] = tmp_sfc;
}
return 0;
bail:
deinitImages();
return -1;
}
static void fillDFBSurface(
IDirectFBSurface *primary_sfc,
IDirectFBSurface *img_sfc,
int x, int y)
{
primary_sfc->Clear(primary_sfc, 0, 0, 0, 255);
/*
* blit即将两张位图(即thiz和source)按拉操作的方法组合成一张图片。
* 在DirectFB中,其定义的动作也是合理的:将img_sfc blit到primary_sfc上去,
* 两个平面上的内容会产生叠加
*/
primary_sfc->Blit(primary_sfc, img_sfc, NULL, x, y);
/* 变换、更新surface buffer */
primary_sfc->Flip(primary_sfc, NULL, DSFLIP_WAITFORSYNC);
return ;
}
/* 计算两个时刻的时间差(b-a),单位毫秒 (From kernel) */
static unsigned long deltaMsecs(struct timespec *a,
struct timespec *b)
{
long delta_secs = 0, delta_msecs = 0;
if(a->tv_sec < b->tv_sec ||
(a->tv_sec == b->tv_sec && a->tv_nsec < b->tv_nsec)) {
return 0;
}
delta_secs = a->tv_sec - b->tv_sec;
delta_msecs = (a->tv_nsec - b->tv_nsec) / 1000000;
while(delta_msecs < 0) {
delta_secs--;
delta_msecs += 1000;
}
return delta_secs * 1000 + delta_msecs;
}
static void doMovie()
{
int ret, i;
int width = 0, height = 0;
struct timespec before_draw, after_draw;
unsigned long elapsed_msec, total_msec;
IDirectFBSurface *primary = badsc.surface;
IDirectFBSurface *bg_sfc = NULL;
unsigned long interval = (1000 / ANIM_IMG_DEFAULT_FPS);
primary->GetSize(primary, &width, &height);
primary->SetColor(primary, 0, 0, 0, 255);
primary->Clear(primary, 0, 0, 0, 255);
primary->Flip(primary, NULL, DSFLIP_WAITFORSYNC);
ANIM_NOTICE("Animation start ...
");
total_msec = 0;
i = 0;
do {
if(i >= ANIM_IMAGES_COUNT) {
i = 0;
}
clock_gettime(CLOCK_MONOTONIC, &before_draw);
fillDFBSurface(primary, imgSfc[i],
(width - ANIM_IMG_DEFAULT_WIDTH) / 2,
(height - ANIM_IMG_DEFAULT_HEIGHT) / 2);
clock_gettime(CLOCK_MONOTONIC, &after_draw);
elapsed_msec = deltaMsecs(&after_draw, &before_draw);
if(elapsed_msec < interval) {
usleep((interval - elapsed_msec) * 1000);
total_msec += interval;
} else {
total_msec += elapsed_msec;
}
ANIM_DEBUG("elapsed %lu ms
",
elapsed_msec < interval ? interval : elapsed_msec);
if(total_msec >= ANIM_MAX_RUNNING_MTIME) {
ANIM_NOTICE("Stopped by Timeout(%lu).
", total_msec);
break;
}
i++;
} while(1);
out:
primary->SetColor(primary, 0, 0, 0, 0);
primary->Clear(primary, 0, 0, 0, 0);
primary->Flip(primary, NULL, DSFLIP_WAITFORSYNC);
ANIM_NOTICE("Animation exit with black screen...
");
return ;
}
static void doAnimation()
{
sem_t *sem_closed = NULL;
if (initImages()) {
ANIM_ERROR("Init images failed!
");
return ;
}
doMovie();
deinitImages();
return ;
}
int main(int argc, char **argv)
{
ANIM_NOTICE("Animation entry.
");
initResources(argc, argv);
doAnimation();
freeResources();
ANIM_NOTICE("Animation exit.
");
return 0;
}
注意:
/home/younger/DFB/animApp/images/default目录下需要存放0.png~11.png等12张图片
Ok!