在基于linux的嵌入式仿真平台开发中,终端的美观和可定制是一个重要的问题。单调的“白纸黑字”型表现方式可谓大煞风景。改造linux控制台使之美观可定制地展示开机信息和logo成为基于嵌入式linux应用的一项重要工作。 在本节主要讲解如何使用DirectFB来实现开机动画
架构
详细设计
DFB资源初始化
主要使用 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\n"); 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!\n", ANIM_LAYERID_USING); goto fail; } else { ANIM_DEBUG("Get layer(%d) independently.\n", 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!\n"); goto fail; } /* 设置透明度 */ ret = badsc.window->SetOpacity(badsc.window, 0xFF); if(ret != (DFBResult)DFB_OK) { ANIM_ERROR("SetOpacity failed!\n"); goto fail; } /* 获取window的surface. */ ret = badsc.window->GetSurface(badsc.window, &(badsc.surface)); if(ret != (DFBResult)DFB_OK) { ANIM_ERROR("SetOpacity failed!\n"); 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.\n", -EINVAL); return -EINVAL; } ANIM_DEBUG("doLoadImg() entry:%s .\n", filename); if(!checkFileExist(filename)) { ANIM_ERROR("file %s does not exist.\n", filename); return -EINVAL; } /* 将要显示的图片及其相关信息保存在一个image provider中 */ ret = dfb->CreateImageProvider(dfb, filename, &provider); if(ret) { ANIM_ERROR("CreateImageProvider() for %s failed %d.\n", filename, ret); return ret; } /* 将保存在provider中的图片信息提取出来,存于surface description中 */ ret = provider->GetSurfaceDescription(provider, &img_dsc); if(ret) { ANIM_ERROR("GetSurfaceDescription() for %s failed %d.\n", 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.\n", filename, ret); provider->Release(provider); return ret; } /* 将图片呈递给刚才建立的logo平面,如果大小不一致,则进行缩放 */ ret = provider->RenderTo(provider, *surface, NULL); if(ret) { ANIM_ERROR("RenderTo() for %s failed %d.\n", 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.\n"); 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 ...\n"); 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 \n", elapsed_msec < interval ? interval : elapsed_msec); if(total_msec >= ANIM_MAX_RUNNING_MTIME) { ANIM_NOTICE("Stopped by Timeout(%lu).\n", 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...\n"); return ;}static void doAnimation(){ sem_t *sem_closed = NULL; if (initImages()) { ANIM_ERROR("Init images failed!\n"); return ; } doMovie(); deinitImages(); return ;}int main(int argc, char **argv){ ANIM_NOTICE("Animation entry.\n"); initResources(argc, argv); doAnimation(); freeResources(); ANIM_NOTICE("Animation exit.\n"); return 0;}
注意:
/home/younger/DFB/animApp/images/default目录下需要存放0.png~11.png等12张图片
Ok!