1 GIF图简介

  GIF(Graphics Interchange Format)图像格式是Compuserve与1987年开发的一种图像文件格式。该图像本身可以存储静态图和动态图,但如今该图像主要被用来存储动态图,且在大部分系统上都支持。但是相对于webp这些新式的动态图格式,其在颜色质量和压缩率上的表现相对不如人意。
  该图像表达图像和一般的图像直接存储图像内容不同,而是通过一个颜色表映射来表达对应的图像的内容。也就是说图像中存在一张颜色表存储图像中出现的颜色,然后每一帧的图像通过颜色索引来表示颜色。GIF支持的最大颜色表数量为8bit256色,所以一般的动态图能够看到图像中存在明显的颜色梯度变化的效应。另外,GIF用LZW无损压缩算法压缩图像数据。
  GIF图像存在两个版本87a和89a,本文首先就87a熟悉GIF图像的格式随后在说明89a和87a的区别。

2 GIF 图像格式

  spec-gif87

2.1 GIF 87a

  下图是87aGIF图像的基本结构,每一块的具体内容如下:

  • GIF Signature:标识当前图像为GIF;
  • Screen Descriptor:描述图像的尺寸等信息;
  • Global Color Table:全局颜色表;
  • 图像单元:GIF图中存在多帧图像,每一帧就是一个图像单元;
  • GIF Terminator:图像结束块。

  下面每一小节会使用下面这张348x288的87aGIF对比具体每一个单元的值。

2.1.1 GIF Signature

  表明当前图像是一个合法的GIF图像在87a版本中是6个字节的固定值GIF87a

2.1.2 Screen Descriptor

  Screen Descriptor描述一个GIF图像的基本信息比如图像的宽高,颜色表,背景颜色等内容

  Screen Descriptor前四个字节时图像的宽度和高度,分别占两个字节,之后的一个字节时图像的基本信息:

  • [0, 3)bit pixel:pixel + 1图像的颜色表数量所占的位数,即2(pixel+1)2^(pixel + 1)2(pixel+1)为颜色表中颜色的最大数量;
  • [3, 4)bit 是一个固定的0;
  • [4, 7)bit cr:cr + 1表示图像的颜色深度;
  • [7, 7]bit M:等于1时表示全局颜色表紧跟Screen Descriptor,当为0时背景色索引无意义。

  之后的1个字节为背景色的索引,如果M为1则后面紧跟的就是全局颜色表。整个Screen Descriptor占6字节。

  从二进制内容看图像的宽度为0x015c(348),高度为0x0120(288)。标志位为0xF7(11110111),即M=1,cr=7,pixel=7,图像颜色表数量为282^828=256颜色,深度为7+1=8位深度。Screen Descriptor后面256x3(RGB三个字节)=768个字节就是整个颜色表。
  GIF的颜色表有两张:全局和局部的,全局通过上面的字段M决定是否存在,1表示使用全局的即所有图像公用一个颜色表,0表示每个图像自己有一个独立的颜色表。颜色表中每个颜色有三个值RGB,分别占1个字节(即每个颜色的值域为0-255),总共占3个字节。白色为(255,255,255),黑色为(0,0,0)。

  GIF文档中还描述了当机器支持小于8bit的处理方式,但是现在的这种情况很少见不多描述。

2.1.3 Image Descriptor

  Image Descriptor描述了每一帧图像的而具体信息比如图像的位置宽高,局部颜色表等内容。因为有些GIF为了优化图像的大小每一帧存储的是相较于前一帧或者第一帧的差,图像的宽高描述的就是这片子区域在整张图像中的位置。

  每个Image Descriptor的开头是一个字节的固定字符0x2c对应的ASCII码为,,该字段本身没有任何含义,只是作为Image Descriptor开头的标记。
  Image Descriptor中的当前帧图像的位置和高宽是相对于Screen Descriptor中的宽高来说的。而最后一个字节类似于Screen Descriptor中的标志位字段,该字段描述了当前帧图像是否使用局部调色板(即颜色表)(局部调色板是相对于Screen Descriptor中的全局而言的)以及局部调色板的颜色数量。局部调色板和全局调色板的布局方式类似,都是rgb分别占用1个字节顺序存放在描述子之后。

  • M(1bit):表示当前帧是否使用局部调色板;
  • I(1bit):表示当前帧图像数据存储方式,如果为1则为交织顺序存储,0表示顺序存储。
  • pixel(3bit):表示当前局部调色板的颜色数量,只有M为1时有效。

  Image Descriptor之后紧跟的就是图像的数据,这里的颜色数据是当前帧图像使用的颜色表中的索引。
  上面也看到了图像有两种存储方式,顺序存储是按照行优先存储,从左到右,从上到下顺序存储。另一种是角质存储,即I设为1。交织存储分为4个pass,每个pass根据不同的间隔存储数据:

  • pass1:每间隔8行从第0行取数据;
  • pass2:每间隔8行从第4行取数据;
  • pass3:每间隔4行从第2行取数据;
  • pass4:每间隔2行从第1行取数据。

  这个数据并不是直接存储的,为了减小文件大小GIF使用LZW算法对数据进行压缩。

  LZW算法采用了一种先进的串表压缩,将每个第一次出现的串放在一个串表中,用一个数字来表示串,压缩文件只存贮数字,则不存贮串,从而使图象文件的压缩效率得到较大的提高。

  Screen Descriptor的字节数为6字节,加上256x3字节的颜色表,我们从305开始往下找0x2c。然后从下图能够看出第一帧图的的区域为(0,0,348, 288),标志位为0,未使用局部颜色表,并采用顺序存储。

2.1.4 GIF Terminator

  GIF结束块是1个字节的固定值0x3B,ASCII码为;,当解码器读取到该值就明白EOF(End of File),后面的内容就会忽略。

2.1.5 GIF 扩展块

  GIF扩展块为GIF提供了更多的灵活性,让GIF包含更多的额外信息。扩展块的第一个字节为标记符0x21!,跟进的一个字节是扩展块的功能编码号,随后的一个字节是下面数据域的字节数,之后便是功能需要的数据(最大256字节),而byte count和func data bytes组成的块可能重复多次。

2.2 GIF 89a

  spec-gif89a

  89a是针对87a的升级版本,相比于后者增加了一些额外的控制块更加精确的控制GIF播放。现在常见的GIF图都是89a,下面将使用下面这张10x10(小图看数据比较方便)的纯色GIF图像来理解GIF图像的基本格式。该图像包含7帧纯颜色图像(0xff0000,0xffa500,0xffff00,0x00ff00,0x7fff,0x0000ff,0x8b00ff),每两帧之间的间隔为0.5s。小图数据量小更加能够看清楚原图中得到具体内容。

  下面这张图是上面的GIF图的结构,左侧为块结构,右侧为图像的二进制数据(图中的指针指向二进制块的起始位置),89a支持的部分块在该图像中没有。

2.2.1 Block

  GIF中Block的基本结构为block size+data,结构很简单就是一个带长度的数组,其基本结构类似C的结构体定义:

struct gif_block{uint8_t data_size_in_bytes;uint8_t pdata;
}

  当块大小为0时,是没有后面的数据项的。

2.2.2 GIF Header

  前6个字节为GIF Header,其中前三个字节为GIF表示,如果为GIF图像固定为GIF,后面三个字节为版本号,比如87a89a

2.2.3 Screen Descriptor

  89a版本的屏幕描述符和87a差不多,区别是多了一个字节和字段。89a版本的屏幕描述符栈7个字节,多一个字节描述屏幕像素宽高比,以及在屏幕标志位中第四个bit用来表示后面的颜色表是否经过排序,1表示有序,0表示无序。

  • [0, 3)bit pixel:pixel + 1图像的颜色表数量所占的位数,即2(pixel+1)2^(pixel + 1)2(pixel+1)为颜色表中颜色的数量;
  • [3, 4)bit s(Sort Flag):表示后面的颜色表是否有序,一般而言颜色表的排序的依据为颜色表中颜色的使用频率,当需要排序时频率越高的越在前码字越短;
  • [4, 7)bit cr(Color ResoluTion):cr + 1表示图像的颜色深度;
  • [7, 7]bit M(Global Color Table Flag):等于1时表示全局颜色表紧跟Screen Descriptor,当为0时背景色索引无意义。

  图像像素宽高比存储的是一个[0,255]的值,当值为0时表示没有值,不可用,非0时的计算方式如下,也就是说支持最宽的图像比为1:4,最高的为4:1。
AspectRatio=(PixelAspectRatio+15)64Aspect Ratio = \frac{(Pixel Aspect Ratio + 15)}{64} AspectRatio=64(PixelAspectRatio+15)​

  如果有全局调色板,全局调色板的存储方式和87a相同,不再赘述。

  从下面的数据中能够看出宽高都为0x000a即10,标志位为0xF2,即11110010(M=1,cr=7,s=0,pixel=2),pxiel为2表示GIF中颜色至少需要3bit保存,即最多8个颜色,当前的GIF为7个颜色。之后就是全局调色板,每个颜色占3个字节。

2.2.4 Application Extension

  描述应用信息,块标识为0xFF

  • 前两个字节分别为块的起始标记和块标识,起始标记为固定的0x21,当前块标识为0xFF
  • 之后的一个字节为块大小,不包含Application Data部分,当前块该值为固定的11;
  • 之后便是8字节的应用标识,为ASCII码;
  • 之后的3个字节为应用的标识验证。

  这里的应用扩展块的block size为固定的11(0x0B),这里的应用标识为NETSCAPE2.0,应用的标识验证为0103,而Application Data长度为0,即没有Application Data,最后为终结符。

2.2.5 Graphic Control Extension

  图像控制块是在89a中新添加的,主要描述每一帧图像的帧间隔等控制信息。

  • Extension Introducer:图像控制块的起始标记,固定为0x21
  • Graphic Control Lable:图像控制块的标识,固定为0xf9
  • Packet Filed:控制块的标志位:
    • 预留位 3bit:暂时无意义;

    • Disposal Method:

      • 0:不指定。解码器会将整个画布清空用当前帧替换;
      • 1:不处置。当前帧需要绘制的内容区域会覆盖上一帧需要绘制的区域;
      • 2:恢复到背景色。直接将当前帧绘制到已经绘制的画布上,也就是说只会覆盖上一帧基本都被保留除非被当前帧覆盖;
      • 3:恢复到前一帧。需要将非当前帧绘制的区域回复对应的参考帧(一般为首帧),并将需要绘制内容重新绘制;
      • 4-7:预留;
    • 用户输入标记(User Input Flag) 1bit:如果设置GIF播放会根据用户的输入交互,交互的事件由应用程序决定,一般为鼠标单击等。(交互的含义是用户触发了相关的事件GIF就继续播放),如果GIF同时定义了delay Time和用户输入标记为1则无论哪一个事件先到达都会播放下一帧;

    • 透明颜色标志位 1bit:置位表示使用透明颜色;

  • Delay Time:当前帧图像的图像延迟,最小精度为0.01s。

  能够看到每一帧图像前都有一个GCB控制块,Block Size为固定的4个字节,标识Flag全为0,帧延迟为0x003250x0.01s=500ms,透明颜色索引为255



2.2.6 Image Descriptor

  89a的帧描述符和87a的帧描述符基本一致都占用10个字节,只不过标志位稍有区别。89a中添加了1个字段s,表示局部颜色表是否排序:

  • M(1bit):表示当前帧是否使用局部调色板;
  • I(1bit):表示当前帧图像数据存储方式,如果为1则为交织顺序存储,0表示顺序存储。
  • s(1bit):局部颜色表是否有序,排序的原则和全局颜色表类似;
  • r(2bit):预留位;
  • pixel(3bit):表示当前局部调色板的颜色数量,只有M为1时有效。

  下图中将所有每一帧图像的GCB和Image Descriptor都标注出来了,稍微有点儿乱。开头为0x2c,图像的坐标为(0,0,10,10),所有的flag为0,使用全局颜色表因此没有局部颜色表。后面紧跟的就是LZW数据了。

2.2.7 图像数据

  GIF图像数据是基于颜色表的索引,时间存储的数据是经过LZW算法压缩过的,存储的方式和87a相同。数据域每个数据块的的结构如下:

  • LZW Minimum Code Size:LZW算法压缩时采用的最小码字位数。
  • block size:后面的数据大小;
  • data:lzw压缩的数据;
  • 块结束标记,始终为0。

  下图中的数据的LZW最小码字位数为2,数据大小为8byte,之后的8个字节都是实际的图像数据经过LZW压缩后的内容。

2.2.8 Comment Extension

  Comment Extension允许你将 ASCII 文本嵌入到 GIF 文件,有时被用来图像描述、图像信贷或其他人类可读的元数据,如图像捕获的 GPS 定位。Comment Extension是可选的,可以在GIF图像中出现多次,一般会被解码器忽略。

  • Extension Introducer:固定的0x21
  • Comment Label:块标志符0xfe
  • Comment Data:数据域。

2.2.9 Plain Text Extension

  Plain Text Extension包含了希望渲染的文字信息,块中会描绘希望渲染的文字的位置和每个字符的cell信息。

  • Extension Introducer,1个字节:固定的0x21
  • Plain Text Label,1个字节:块标识,0x01
  • 块大小,1个字节:固定的值12,即0xc
  • 下面8个字节分别为坐标即[left, top, width, height]
  • Character Cell Width:每个字符cell的宽度;
  • Character Cell Height:每个字符cell的高度;
  • Text Foreground Color Index:前景颜色索引;
  • Text Background Color Index:背景颜色索引;
  • Plain Text Data:是一个sub-blocks,每一个最多255字节;
  • Terminator。

2.2.10 其他扩展块即信息

  Opt表示可选,Req表示必须。

Block Name                  Required   Label       Ext.   Vers.
Application Extension       Opt. (*)   0xFF (255)  yes    89a
Comment Extension           Opt. (*)   0xFE (254)  yes    89a
Global Color Table          Opt. (1)   none        no     87a
Graphic Control Extension   Opt. (*)   0xF9 (249)  yes    89a
Header                      Req. (1)   none        no     N/A
Image Descriptor            Opt. (*)   0x2C (044)  no     87a (89a)
Local Color Table           Opt. (*)   none        no     87a
Logical Screen Descriptor   Req. (1)   none        no     87a (89a)
Plain Text Extension        Opt. (*)   0x01 (001)  yes    89a
Trailer                     Req. (1)   0x3B (059)  no     87aUnlabeled Blocks
Header                      Req. (1)   none        no     N/A
Logical Screen Descriptor   Req. (1)   none        no     87a (89a)
Global Color Table          Opt. (1)   none        no     87a
Local Color Table           Opt. (*)   none        no     87aGraphic-Rendering Blocks
Plain Text Extension        Opt. (*)   0x01 (001)  yes    89a
Image Descriptor            Opt. (*)   0x2C (044)  no     87a (89a)Control Blocks
Graphic Control Extension   Opt. (*)   0xF9 (249)  yes    89aSpecial Purpose Blocks
Trailer                     Req. (1)   0x3B (059)  no     87a
Comment Extension           Opt. (*)   0xFE (254)  yes    89a
Application Extension       Opt. (*)   0xFF (255)  yes    89a

2.2.11 Trailer

  同87a为固定的0x3B

2.2.12 GIF支持的其他选项

  非官方标准,但是大部分GIF都支持。

  循环次数:GIF图支持设置循环次数,如果该标志设置为0则表示无限循环;
  颜色抖动:GIF可以通过颜色抖动算法来减少GIF中的颜色表来所见文件尺寸,但是颜色都读算法仅仅对于颜色变换比较连续的图像比较友好,对于颜色变换比较平滑的效果较差。

  隔行采样:顾名思义。

3 尝试C语言手写一个GIF图像

  上面简略了解了下GIF图像的存储格式,下面尝试用C写一张包含RGB三个纯色280x280GIF图像,每一帧图像都是纯色图像,每一帧子图像都不等于原图大小,且图像延时间隔分别为0.5ms。

  GIF图像中的数据基本都可以用C的fwrite写入,但是对于lzw压缩需要借助额外的lzw库lzw-compress-lib,该库的使用很简单加入到项目就可以。

  首先是各种结构的定义,结构很简单,按照上面的结构创建就行。部分内容为了方便写入将uint16拆分为两个uint8。

typedef unsigned __int8  uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
typedef uint8_t byte;
extern "C" {typedef struct gif_block {byte size;byte *pdata;}gif_block;typedef struct gif_header {char gif_sig[3];char gif_ver[3];}gif_header;//extension block headertypedef struct gif_ext_header {byte introducer;byte label;}gif_ext_header;//screen descriptor typedef struct gif_screen_decriptor {byte width_l;byte width_h;byte height_l;byte height_h;byte flag_pixel : 3;byte flag_s : 1;byte flag_cr : 3;byte flag_M : 1;byte bk_color_index;byte aspect_ratio;}gif_screen_decriptor;//application extensiontypedef struct gif_app_ext {gif_ext_header header;byte size;char identifier[8];byte authentication_code[3];gif_block app_data;byte terminator;}gif_app_ext;//graphic control extensiontypedef struct gif_gce{gif_ext_header header;byte size;byte transport_used : 1;byte input_flag : 1;byte disposal_method : 3;byte reversed : 3;byte delay_time_l;byte delay_time_h;byte transparent_color_index;byte terminator;}gif_gce;typedef struct gif_image_descriptor {byte introductor;byte left_l;byte left_h;byte right_l;byte right_h;byte width_l;byte width_h;byte height_l;byte height_h;byte flag_pixel : 3;byte flag_r : 2;byte flag_s : 1;byte flag_I : 1;byte flag_M : 1;};typedef struct gif_trailer{byte trailer;}gif_trailer;
}

  实现部分也很简单,基本每一个内容都有注释。

//写入颜色表
static void write_color_table(FILE *fp, uint32_t *color_table, int len) {for (int i = 0; i < len; i++) {uint32_t current_color = color_table[i];uint8_t r = (current_color & 0xFF0000) >> 16;uint8_t g = (current_color & 0x00FF00) >> 8;uint8_t b = (current_color & 0x0000FF);fwrite(&r, sizeof(uint8_t), 1, fp);fwrite(&g, sizeof(uint8_t), 1, fp);fwrite(&b, sizeof(uint8_t), 1, fp);}
}
//将数据压缩并写入文件中
static void write_lzw_data_block(uint8_t bit, unsigned char *pdata, unsigned long len, FILE*fp) {//首先写入LZW Minimum Code Sizefwrite(&bit, sizeof(bit), 1, fp);//中间的lzw数据是多个data block,每个block最多256字节unsigned long writed_size = 0;while (writed_size < len) {if ((0xff + writed_size) > len) {//未写入的数据小于255,不需要额外的块存储uint8_t terminator = 0;unsigned long left_size = len - writed_size;fwrite(&left_size, sizeof(uint8_t), 1, fp);fwrite(pdata + writed_size, left_size, 1, fp);writed_size += left_size;}   else {uint8_t size = 0xff;fwrite(&size, sizeof(size), 1, fp);fwrite(pdata + writed_size, size, 1, fp);writed_size += 0xff;}}//最后需要写入Terminatoruint8_t terminator = 0;fwrite(&terminator, sizeof(terminator), 1, fp);
}static void write_gif_in_hand(const char *filename) {FILE *fp = fopen(filename, "wb");if (nullptr == fp) {fprintf(stderr, "can not open file %s\n", filename);}uint16_t width = 280, height = 280;//header为固定的GIF89agif_header header = { {0x47, 0x49, 0x46}, {0x38, 0x39, 0x61} };fwrite(&header, sizeof(header), 1, fp);//宽高100x100,flag为11110010(0xF2),表示颜色深度为8,采用全局颜色表,颜色数量最多为8,背景色和宽高比不使用gif_screen_decriptor scrn_desc = { width, width >> 8, height, height >> 8, 0x02, 0x00, 0x07, 0x01};fwrite(&scrn_desc, sizeof(scrn_desc), 1, fp);//这里采用的颜色表比较简单,就是rgb三种颜色,额外包含黑色const int color_number = 8;uint32_t color_table[color_number] = {0XFF0000, // 赤0XFFA500, // 橙0XFFFF00, // 黄0X00FF00, // 绿0X007FFF, // 青0X0000FF, // 蓝0X8B00FF, // 紫0X000000  // 黑 };write_color_table(fp, color_table, sizeof(color_table) / sizeof(color_table[0]));//appliction这里用一种比较简单的方式写入,也可以用上面定义的gif_app_ext,但是稍显麻烦uint8_t gif_application_extension[] = { 0x21, 0xFF, 0x0B, 0x4E, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2E, 0x30, 0x03, 0x01, 0x00, 0x00, 0x00 };fwrite(gif_application_extension, sizeof(uint8_t), sizeof(gif_application_extension) / sizeof(gif_application_extension[0]), fp);for (int i = 0; i < color_number - 1; i++) {//每一帧的left和right不同,一直在变化。uint16_t image_width = width / (color_number - 1), image_height = height / (color_number - 1);uint16_t image_left = i * image_width, image_right = i * image_height;gif_gce gce = { 0x21, 0xf9, 0x04, 0, 0, 0, 0, 0x32, 0x32 >> 8, 0xff, 0 };fwrite(&gce, sizeof(gce), 1, fp);gif_image_descriptor img_desc = { 0x2c, image_left, image_left >> 8, image_right, image_right >> 8, image_width, image_width >> 8, image_height, image_height >> 8, 0, 0, 0, 0, 0 };fwrite(&img_desc, sizeof(img_desc), 1, fp);//颜色数据,对应的颜色采用对应的索引即可,比如第一帧为0,第二帧为1uint8_t* pdata = (uint8_t*)malloc(sizeof(uint8_t) * image_height * image_width);memset(pdata, i, sizeof(uint8_t) * image_height * image_width);unsigned char *compressed_data = nullptr;unsigned long compressed_size = 0;lzw_compress_gif(3, image_height * image_width, pdata, &compressed_size, &compressed_data);write_lzw_data_block(0x03, compressed_data, compressed_size, fp);free(pdata);}//写入文件终结符。gif_trailer trailer = { 0x3B };fwrite(&trailer, sizeof(trailer), 1, fp);if (fp != nullptr) {fclose(fp);}
}

参考文档

  • GIF-wiki
  • w3-GIF-87a
  • w3-GIF-89a
  • 手写GIF
  • GIF dispose

GIF图像格式简介(87a和89a)(C语言生成GIF图像)相关推荐

  1. BMP位图图像格式简介

    BMP位图图像格式简介 1. 文件结构 位图文件可看成由4个部分组成:位图文件头(bitmap-fileheader).位图信息头(bitmap-informationheader).彩色表(colo ...

  2. python 图像格式转换_如何用六行Python构建图像类型转换器

    python 图像格式转换 by AMR 通过AMR 如何用六行Python构建图像类型转换器 (How to build an image type convertor in six lines o ...

  3. HSV模型简介以及利用HSV模型随机增强图像

    文章目录 图像HSV模型简介 RGB模型转HSV模型 opencv关于HSV模型实验 随机增强图像HSV 图像HSV模型简介 HSV(Hue, Saturation, Value)是根据颜色的直观特性 ...

  4. c语言生成Bmp图像

    代码如下: // ConsoleApplication1.cpp : 此文件包含 "main" 函数.程序执行将在此处开始并结束. // #define _CRT_SECURE_N ...

  5. 福利 | 抽奖送现金送书《Web前端工程师修炼之道》

    很多关注了我的公众号的粉丝可能都不知道我,趁这次机会简单介绍下. 你好,我是若川.江西人,某不那么知名的陶瓷大学毕业生,目前在杭州从事前端开发工作.常以若川为名混迹于江湖.更详细的可以点击关于我 我历 ...

  6. 【文末抽奖送书】新年礼物《Web前端工程师修炼之道》

    随着多设备.浏览器和Web标准的演变革命,前端正在成为兼顾逻辑.性能.交互.体验的综合性岗位. 前端开发入门又相对容易,必须掌握的HTML+CSS+JS非常容易学习,如果你能再了解一定后端知识,对业务 ...

  7. Web前端开发敲门砖 ——《Web前端工程师修炼之道》

    随着多设备.浏览器和Web标准的演变革命,前端正在成为兼顾逻辑.性能.交互.体验的综合性岗位. 前端开发入门又相对容易,必须掌握的HTML+CSS+JS非常容易学习,如果你能再了解一定后端知识,对业务 ...

  8. 【Android FFMPEG 开发】FFMPEG AVFrame 图像格式转换 YUV - RGBA ( 获取 SwsContext | 初始化图像数据存储内存 | 图像格式转换 )

    文章目录 I . FFMPEG AVFrame 图像数据帧处理 前置操作 II . FFMPEG 解码 AVPacket 数据到 AVFrame 流程 III. FFMPEG 解码前后的图像格式 IV ...

  9. 什么是AVIF?如何在您的网站上使用AV1图像格式

    AV1图像格式或AVIF是地球上最新的图像编解码器.AVIF是一种优化的图像格式,旨在使我们的图像更小,同时保持相同的质量(无损),AVIF的文件扩展名是 .avif. 在本文中,我想谈谈它的功能和好 ...

  10. VPS、SPS、PPS、SS简介

    缩写 全称 GOP group of pictures IDR instantaneous decoding refresh SS slice segment CTU coding tree unit ...

最新文章

  1. python正则表达式模糊匹配_用python正则表达式编译模糊正则表达式
  2. python自动测试u_自动化测试——Selenium+Python之下拉菜单的定位
  3. mysql 英文占几个字符_MySQL 数据库 varchar 到底可以存多少个汉字,多少个英文呢?我们来搞搞清楚...
  4. CVPR 2019审稿排名第一满分论文:让机器人也能「问路」的视觉语言导航新方法...
  5. jsp页面textarea中换行替换问题
  6. 广外计算机考研专业课,【广外考研论坛】 21广外各专业考研问题全解答!纯干货!...
  7. MyBatis之输入与输出(resultType、resultMap)映射
  8. 祁飞机器人_转自祈飞:什么是智能机器人
  9. wireshark网卡权限_设置网卡属性用wireshark抓VLAN包
  10. Discuz!NT 模板机制分析
  11. 传智播客java基础入门pdf
  12. Android实现随意拖动View效果
  13. OllyDBG V1.10聆风听雨汉化版
  14. 政策的组合拳使得九月无法平凡
  15. 解决Chrome无法显示本地的.vtt字幕文件 (如何让本地HTML运行在Server上)
  16. 基于卷积神经网络 CNN 的猫狗识别详细过程
  17. Win7 如何修改hosts文件
  18. Workbook 对象 应用示例
  19. 【基于TCP 在线电子词典】
  20. 群消息已读回执(这个屌),究竟是推还是拉?

热门文章

  1. 【线性系统笔记2】系统框图与模拟结构图
  2. MindManager2022安装使用教程
  3. 全球与中国Epicor渠道合作伙伴市场现状及未来发展趋势
  4. 让我们努力的学习ruby吧
  5. 各种主流浏览器内核引擎的对比分析
  6. c++win32项目 如何显示后再删除一个绘图_以weblogic为中间件,部署一个项目,需如何做?...
  7. 第1章 数学基础和机器学习问题(范数+矩阵迹+矩阵求导+机器学习框架)
  8. 22. 协程与Python中的多任务异步协程
  9. 写在25岁的人生边上
  10. 动态切换 web 报表中的统计图类型