动画动态配置
一套素材的目录结构一般如下:
子目录中的图片名称都是以数字命名,比如,1,2, 3, 4,……
而配置文件animation.cfg的格式如下:
#width height fps 960 540 10 #type isPlay startIndex endIndex maxTime partChildPath png 1 1 1 4000 part0 png 1 1 12 25000 part1上述配置文件中,有两类参数:
第一类参数,表示整个开机动画的参数
width height fps
width:图片的宽度;
height:图片的宽度,这里图片尺寸为960*540,宽为960,高为540;
fps:图片的切换速率,比如参数10,表示每一秒切换10张图片
第二类参数,表示该子目录下的图片的运行模式:
type isPlay startIndex endIndex maxTime partChildPath
type:图片格式,比如png,jpg
isPlay:动画是否播放该子目录,0-不包括,1-不包括
startIndex:第一个显示的图片
endIndex:最后一个显示的图片
maxTime:最大运行时间
partChildPath:子目录的名称
数据结构 HeadNode
标识:head
类型:struct HeadNode
含义:用于标识动画所需图片的宽与高及其刷新频率。
Data Type |
Data Item Definition |
Data Item Description |
int |
fps |
动画刷新频率 |
int |
imgWidth |
动画所用图片的宽 |
int |
imgHeight |
动画所用图片的高 |
struct Node * |
next |
动画是可以分段的,该节点标识一段动画的相关参数 |
标识数据结构Node
标识:Node
类型:struct Node
含义:标记一段开机动画的相关参数。
Data Type |
Data Item Definition |
Data Item Description |
int |
isPlay |
动画是否播放该子目录,0-不包括,1-不包括 |
int |
maxTime |
该段动画最大运行时间 |
int |
startIndex |
第一个显示的图片 |
int |
endIndex |
最后一个显示的图片 |
char |
type |
图片格式,比如png,jpg;包含BA_IMGFORMAT_MAX_SIZE个字符; |
char |
path |
存放该段动画图片的子目录 |
IDirectFBSurface * |
imgSfc |
BA_IMG_MAX_COUNT个surface描述符,在图片初始化时使用 |
struct Node * |
next |
动画是可以分段的,该节点标识一段动画的相关参数 |
动画组织结构图
框架
代码
/********************************************** * Author: younger.liucn@hotmail.com * File name: animation.c * Description: animation * Version, Desc * 1.1 Created * 1.2 add config **********************************************/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <string.h> #include <time.h> #include <sys/time.h> #include <directfb.h> #include "animation.h" /* config information */ #define ANIM_LINE_MAX_SIZE 128 #define ANIM_FILENAME_MAX_SIZE 128 #define ANIM_IMAGE_FORMAT_SIZE 8 #define ANIM_PARTNAME_MAX_SIZE 8 #define ANIM_IMAGES_MAX_COUNT 32 #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_DIR "/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) /********************************************************* * log flags and func of debug and error infor.[End] ********************************************************/ /********************************************************* * Data structure and Global variants [Begin] ********************************************************/ /* 使用directFB画图所需的四个DFB资源 */ struct AnimationDsc { IDirectFB *dfb; IDirectFBDisplayLayer *layer; IDirectFBWindow *window; IDirectFBSurface *surface; }; static struct AnimationDsc badsc; /* 定义Animation part */ typedef struct HeadNode{ int fps; int imgWidth; int imgHeight; struct Node *next; }HeadNode; typedef struct Node{ int isPlay; int maxTime; int startIndex; int endIndex; char type[ANIM_IMAGE_FORMAT_SIZE]; char path[ANIM_PARTNAME_MAX_SIZE]; IDirectFBSurface *imgSfc[ANIM_IMAGES_MAX_COUNT]; struct Node *next; }Node; static struct HeadNode head; /********************************************************* * Data structure and Global variants [End] ********************************************************/ /********************************************************* * Some functions help animation [Begin] ********************************************************/ struct HeadNode *listAddNodeT( struct HeadNode *pheadnode, struct Node *node) { struct Node *L = NULL, *H = NULL; if(NULL == node) { ANIM_ERROR("Node is NULL! "); } if (NULL == pheadnode->next) { pheadnode->next = node; return pheadnode; } L = pheadnode->next; H = L; while(NULL != L->next) { L = L->next; } L->next = node; pheadnode->next = H; return pheadnode; } static void listFreeNode(struct Node *phead) { struct Node *L = NULL; L = phead; while (NULL != phead) { L = phead->next; free(phead); phead = L; } return ; } /* 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] ********************************************************/ static int initConfig() { int ret = 0; FILE *fp = NULL; struct Node *node; char strline[ANIM_LINE_MAX_SIZE]; char filename[ANIM_FILENAME_MAX_SIZE]; char type[ANIM_IMAGE_FORMAT_SIZE], path[ANIM_PARTNAME_MAX_SIZE]; int run = 0, fps = 0, maxtime = 0; int startindex = 0, endindex = 0, width = 0, height = 0; head.fps = ANIM_IMG_DEFAULT_FPS; head.imgWidth= ANIM_IMG_DEFAULT_WIDTH; head.imgHeight = ANIM_IMG_DEFAULT_HEIGHT; head.next = NULL; memset(strline, 0x0, sizeof(strline)); memset(filename, 0x0, sizeof(filename)); snprintf(filename, ANIM_FILENAME_MAX_SIZE, "%s/%s", ANIM_DEFAULT_LOGO_DIR, "animation.cfg"); if(!checkFileExist(filename)) { ANIM_ERROR("Can't find %s ",filename); ret = -1; goto bail; } fp = fopen(filename, "r"); if (NULL == fp) { ANIM_ERROR("Open failed: %s ", filename); ret = -1; goto bail; } while(!feof(fp)) { memset(type, 0x0, sizeof(type)); memset(path, 0x0, sizeof(path)); ANIM_DEBUG("Line: %s", strline); if (sscanf(strline, "%d %d %d", &width, &height, &fps) == 3) { head.fps = fps; head.imgWidth = width; head.imgHeight = height; ANIM_DEBUG("Animation %d,height:%d,fps:%d ", width, height, fps); } else if ((sscanf(strline, "%s %d %d %d %d %s", type, &run, &startindex, &endindex, &maxtime, path) == 6) && (0 != run)) { node = (struct Node *)malloc(sizeof(struct Node)); if (NULL == node) { ANIM_ERROR("Node malloc failed! "); ret = -1; break; } ANIM_DEBUG("==Path:%s,typy:%s,isPlay:%d ", path, type, run); ANIM_DEBUG("==start:%d, end:%d, maxtime:%d ", startindex, endindex, maxtime); node->isPlay = run; node->startIndex = startindex; node->endIndex = endindex; node->maxTime = maxtime; strncpy(node->path, path, (strlen(path) + 1) > ANIM_PARTNAME_MAX_SIZE ? (strlen(path) + 1) : ANIM_PARTNAME_MAX_SIZE); strncpy(node->type, type, (strlen(type) + 1) > ANIM_IMAGE_FORMAT_SIZE ? (strlen(type) + 1) : ANIM_IMAGE_FORMAT_SIZE); node->next = NULL; listAddNodeT(&head, node); node = NULL; } fgets(strline, ANIM_LINE_MAX_SIZE, fp); } fclose(fp); bail: return ret; } static void freeConfig() { listFreeNode(head.next); return ; } 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 ; } 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; } /* free images */ static void deinitImages() { int i = 0; struct Node *part = NULL; part = head.next; while(part) { for (i = 0; i <= ANIM_IMAGES_MAX_COUNT; i++) { if (part->imgSfc[i]) { part->imgSfc[i]->Release(part->imgSfc[i]); } else { break; } } part = part->next; } return ; } static int initImages() { int ret = 0, i = 0; char filename[ANIM_FILENAME_MAX_SIZE]; IDirectFBSurface *tmp_sfc = NULL; struct Node *part = NULL; part = head.next; while(part) { for (i = 0; i < ANIM_IMAGES_MAX_COUNT; i++) { part->imgSfc[i] = NULL; } for (i = part->startIndex; i <= part->endIndex; i++) { tmp_sfc = NULL; memset(filename, 0x0, sizeof(filename)); snprintf(filename, ANIM_FILENAME_MAX_SIZE, "%s/%s/%d.%s", ANIM_DEFAULT_LOGO_DIR, part->path, i, part->type); ret = doLoadImg(filename, &tmp_sfc, NULL, NULL); if (ret != 0) { goto bail; } part->imgSfc[i - part->startIndex] = tmp_sfc; } part = part->next; } 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 = 0, i = 0; int width = 0, height = 0; struct timespec before_draw, after_draw; unsigned long elapsed_msec = 0, total_msec = 0; IDirectFBSurface *primary = badsc.surface; IDirectFBSurface *bg_sfc = NULL; unsigned long interval = (1000 / head.fps); struct Node *part = NULL; 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 ... "); part = head.next; while(part) { i = part->startIndex; do { if(i >= part->endIndex) { i = 0; } clock_gettime(CLOCK_MONOTONIC, &before_draw); fillDFBSurface(primary, part->imgSfc[i], (width - head.imgWidth) / 2,(height - head.imgHeight) / 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 >= part->maxTime) { ANIM_NOTICE("Stopped by Timeout(%lu). ", total_msec); break; } i++; } while(1); part = part->next; } 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() { int ret = 0; ret = initConfig(); if(ret) { return ; } ret = initImages(); if(ret) { ANIM_ERROR("Init images failed! "); goto out; } doMovie(); deinitImages(); out: freeConfig(); return ; } int main(int argc, char **argv) { ANIM_NOTICE("Animation entry. "); initResources(argc, argv); doAnimation(); freeResources(); ANIM_NOTICE("Animation exit. "); return 0; }
作者:Younger Liu,
本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 未本地化版本许可协议进行许可。