imx6 内核启动后使用giflib播放gif开机动画流程

1、giflib交叉编译

  首先要下载giflib的源码:https://sourceforge.net/projects/giflib/files/

  使用交叉编译器编译出arm端可执行文件,

  

source /opt/fsl-imx-fb/4.1.15-2.0.0/environment-setup-cortexa9hf-neon-poky-linux-gnueabi 
make
make PREFIX=$PWD/_install install

完成后在会在源码路径下的_install目录里安装编译后程序。

llixx@linux:~/workspace/lgmg_gif/giflib-5.2.2/_install$ tree
.
├── bin
│   ├── gif2rgb
│   ├── gifbuild
│   ├── gifclrmp
│   ├── giffix
│   ├── giftext
│   └── giftool
├── include
│   └── gif_lib.h
├── lib
│   ├── libgif.a
│   ├── libgif.so -> libgif.so.7
│   ├── libgif.so.7 -> libgif.so.7.2.0
│   └── libgif.so.7.2.0
└── share
└── man
└── man1
├── gif2rgb.xml
├── gifbuild.xml
├── gifclrmp.xml
├── giffix.xml
├── giflib.xml
├── giftext.xml
└── giftool.xml

 2、编写播放gif图代码

新建源码文件夹boot_animation,将上步骤生成的libgif.a静态库和gif_lib.h头文件拷贝到此目录,并新建一个boot_animation.c源文件,内容如下:

#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gif_lib.h"

struct fb_var_screeninfo vinfo;
int fb = -1;
unsigned int* framebuffer = NULL;

// 清空 framebuffer 并填充为背景色
void clear_framebuffer(unsigned int bg_color) {
    int total_pixels = vinfo.yres_virtual * vinfo.xres_virtual;
    for (int i = 0; i < total_pixels; i++) {
        framebuffer[i] = bg_color;
    }
}

// 打开 framebuffer 设备
int open_framebuffer(const char* fb_device) {
    fb = open(fb_device, O_RDWR);
    if (fb == -1) {
        perror("Error opening framebuffer device");
        return -1;
    }

    if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo)) {
        perror("Error reading variable information");
        close(fb);
        return -1;
    }

    framebuffer = mmap(NULL, vinfo.yres_virtual * vinfo.xres_virtual * vinfo.bits_per_pixel / 8,
                       PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0);
    if (framebuffer == MAP_FAILED) {
        perror("Error mapping framebuffer to memory");
        close(fb);
        return -1;
    }

    return 0;
}

// 关闭 framebuffer 设备
void close_framebuffer() {
    if (framebuffer) {
        munmap(framebuffer, vinfo.yres_virtual * vinfo.xres_virtual * vinfo.bits_per_pixel / 8);
    }
    if (fb != -1) {
        close(fb);
    }
}

// 显示单个帧到 framebuffer
void display_frame(GifFileType* gif, int frame_index) {
    SavedImage* frame = &gif->SavedImages[frame_index];
    ColorMapObject* cmap = frame->ImageDesc.ColorMap ? frame->ImageDesc.ColorMap : gif->SColorMap;

    if (!cmap) {
        fprintf(stderr, "No color map found\n");
        return;
    }

    // 获取透明色索引
    int transparent_index = -1;
    for (int ext = 0; ext < frame->ExtensionBlockCount; ext++) {
        if (frame->ExtensionBlocks[ext].Function == GRAPHICS_EXT_FUNC_CODE) {
            GraphicsControlBlock gcb;
            DGifExtensionToGCB(frame->ExtensionBlocks[ext].ByteCount, frame->ExtensionBlocks[ext].Bytes, &gcb);
            transparent_index = gcb.TransparentColor;
            break;
        }
    }

    int width = frame->ImageDesc.Width;
    int height = frame->ImageDesc.Height;
    int x_offset = frame->ImageDesc.Left;
    int y_offset = frame->ImageDesc.Top;
    unsigned char* raster = frame->RasterBits;

    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            unsigned char color_index = raster[y * width + x];
            if (color_index == transparent_index || color_index >= cmap->ColorCount) {
                continue;
            }
            GifColorType color = cmap->Colors[color_index];
            unsigned int pixel = (color.Red << 16) | (color.Green << 8) | color.Blue;

            int fb_x = x + x_offset;
            int fb_y = y + y_offset;

            if (fb_x < vinfo.xres_virtual && fb_y < vinfo.yres_virtual) {
                framebuffer[fb_y * vinfo.xres_virtual + fb_x] = pixel;
            }
        }
    }
}


// 播放 GIF 动画
void play_gif(const char* gif_file) {
    int error;
    GifFileType* gif = DGifOpenFileName(gif_file, &error);
    if (gif == NULL) {
        fprintf(stderr, "Error opening GIF file: %d\n", error);
        return;
    }

    if (DGifSlurp(gif) == GIF_ERROR) {
        fprintf(stderr, "Error reading GIF file: %d\n", gif->Error);
        DGifCloseFile(gif, &error);
        return;
    }

    int num_frames = gif->ImageCount;
    int delay_time = 41; // 默认延迟时间,单位为 1/100 秒

    // 清空 framebuffer 为背景色(如黑色)
    clear_framebuffer(0x000000);  // 黑色背景

    while (1) {
        for (int i = 0; i < num_frames; i++) {
            display_frame(gif, i);
            usleep(delay_time * 1000);  // 延时,单位为微秒
        }
    }

    DGifCloseFile(gif, &error);
}

// 主程序
int main(int argc, char *argv[]) {
    // 确保提供了 GIF 文件路径作为命令行参数
    if (argc < 2) {
        fprintf(stderr, "Usage: %s <path_to_gif_file>\n", argv[0]);
        return -1;
    }

    const char* gif_file = argv[1];  // 获取传入的 GIF 文件路径

    // 打开 framebuffer 设备
    if (open_framebuffer("/dev/fb0") == -1) {
        return -1;
    }

    // 播放 GIF 动画
    play_gif(gif_file);

    // 关闭 framebuffer 设备
    close_framebuffer();
    return 0;
}

 

编写Makefile文件,内容如下:

# 编译器和链接器设置
# CC = gcc
CFLAGS = -Wall -g  # 启用调试信息,可以去掉 -g 如果不需要调试符号
LDFLAGS = -L.       # 指定静态库所在目录,这里是当前目录
LIBS = -lgif        # 指定链接的库名,这里是 giflib

# 源文件和目标文件
SRC = boot_animation.c
OBJ = $(SRC:.c=.o)
EXEC = boot_animation

# 默认目标
all: $(EXEC)

# 编译目标
$(EXEC): $(OBJ)
    $(CC) $(OBJ) -o $(EXEC) $(LDFLAGS) $(LIBS)

# 编译源文件为目标文件
%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

# 清理目标
clean:
    rm -f $(OBJ) $(EXEC)

完成后make编译,生成boot_animation可执行程序,拷贝到目标版中运行可显示gif图片了。

posted @ 2025-05-27 13:50  yu_chun_de_ren_lei  阅读(53)  评论(0)    收藏  举报