DirectFB 之 动画播放初步

       在基于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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>

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

#include <semaphore.h>
#include <signal.h>

#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!

posted on 2016-05-24 00:59  YoungerChina  阅读(925)  评论(0编辑  收藏  举报

导航