DirectFB 之 分段动画

动画动态配置

       一套素材的目录结构一般如下:


       子目录中的图片名称都是以数字命名,比如,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!\n");
    }
    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 \n",filename);
        ret = -1;
        goto  bail;
    }

    fp = fopen(filename, "r");
    if (NULL == fp) {
        ANIM_ERROR("Open failed: %s\n", 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 width: %d,height:%d,fps:%d\n", 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!\n");
                ret = -1;
                break;
            }
            ANIM_DEBUG("==Path:%s,typy:%s,isPlay:%d\n", path, type, run);
            ANIM_DEBUG("==start:%d, end:%d, maxtime:%d\n", 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\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 ;
}


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;
}

/* 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 ...\n");
    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 \n",
				elapsed_msec < interval ? interval : elapsed_msec);

			if(total_msec >= part->maxTime) {
				ANIM_NOTICE("Stopped by Timeout(%lu).\n", 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...\n");

    return ;
}

static void doAnimation()
{
	int ret = 0;
	
	ret = initConfig();
	if(ret) {
        return ;
	}

	ret = initImages();
	if(ret) {
        ANIM_ERROR("Init images failed!\n");
        goto out;
	}

    doMovie();
    deinitImages();

out:
    freeConfig();
    return ;
}

int main(int argc, char **argv)
{
    ANIM_NOTICE("Animation entry.\n");
    initResources(argc, argv);
    doAnimation();
    freeResources();

    ANIM_NOTICE("Animation exit.\n");
    return 0;
}


作者:Younger Liu,

本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 未本地化版本许可协议进行许可。


posted on 2016-05-24 20:55  YoungerChina  阅读(455)  评论(0编辑  收藏  举报

导航