原文链接
GIF替代方案
维基百科的解释
Video alternative to GIF
已经提出来的替代gif的方案中,通常是用 HTML5 Video,其优点是:
- 可以使文件更小
- 支持超过8-bit 颜色限制
- 通过编解码器实现更好的帧处理和压缩
- HTML5规范中的视频元素的引入,以及H.264和WebM视频文件格式,允许更广泛、更容易的支持和实现视频。
上面提到的webm是一种对gif的替代方案,除了这个还有例如gfycat方案。下面解释一下这两种替代方案的详情:
-
Gfycat(fifty-cat)
Gfy 代表“gif format yoker”,目的是通过提供 快速传送 和 控制选项 弥补gif和html5 video之间的差距,
Gfycat是GIF主机有三个独特的优势:
- 速度 : 传统GIF平均速度提高10倍
- 无限大小 : 大型GIF或视频没有问题
- 功能 : 通过暂停,倒转,减速或加速分析逐帧分析
其他优点:
- 链接。 我们生成的每个链接包括一个GIF文件。 即使通过视频传送,GIF始终在那里。 我们选择浏览器可以查看的最佳格式,但作为用户,您可以选择仅查看GIF,或直接链接到GIF。
- 全球CDN
- 可扩展的服务器系统, 多层负载平衡和缓存,无单点故障。
- RES集成! 如果您使用Reddit增强套件,您可以播放Gfycat,甚至不需要重新编辑。 只需点击链接中的播放按钮。
GIF替代案例
- Twitter将用户上传的GIF动图转换成mp4格式
- imgur将上传到自己网站的所有gif转换成video,并提供以.gifv 为扩展名的真实文件(WebM);
- Telegram将gif保存成video以后,同样质量的内容节省95%的存储空间。
- 9gag
- 看一看实情是怎样的:
例子:
1、twitter
显示gif的图,我们看看实际上是什么:
发现一个以 .mp4结尾的链接
2、gfycat
...
网上都在疯转,这是为什么呢?
问题:
有人说是体积和播放控制,真是这样么?
接下来我们自己实际操作看一下
使用工具:
- gif -> video:
在线转换工具 - 制作gif(可用作运营制作gif):
GIF Brewery by Gfycat - ImageMagick 图像处理命令行工具
- ffmpeg(可批量转换)
多媒体工具:ffmpeg,可以将gif和video相互转换
ffmped更多功能
实践出真知:同样的gif用ffmpeg转换比网页转换工具后体积更小。
//命令
ffmpeg -f gif -i animation.gif animation.mp4
//可以选择输出格式:
ffmpeg -f gif -i animation.gif animation.mpeg
ffmpeg -f gif -i animation.gif animation.webm
GIF
- GIF存储
Gif以块的形式存储图像信息,分别是- 控制块(Control Block)
- 文件头信息:(GIF87a\GIF89a)占用6个字节
- 逻辑屏幕描述块
- 图像控制扩充块
- 文件结尾块
- 图像描述块(Graphic Rendering Block)
- 图像描述块
- 全局调色板
- 局部调色板
- 图像压缩数据
- 图像说明扩充块
- 特殊用途块(Special Purpose Block)
- 图像注释扩充块
-
应用程序扩充块
- 控制块(Control Block)
gif 的版本号和署名在前6个字节
我们可以在三方库的源码中得到验证(GifHeaderParser.java):
/**
* Reads GIF file header information.
*/
private void readHeader() {
String id = "";
for (int i = 0; i < 6; i++) {
id += (char) read();
}
if (!id.startsWith("GIF")) {
header.status = STATUS_FORMAT_ERROR;
return;
}
readLSD();
if (header.gctFlag && !err()) {
header.gct = readColorTable(header.gctSize);
header.bgColor = header.gct[header.bgIndex];
}
}
逻辑屏幕标识符
Packet里是调色盘信息,分别来看:
- Global Color Table Flag为全局颜色表标志,即为1时表明全局颜色表有定义。
- Color Resolution 代表颜色表中每种基色位长(需要+1),为111时,每个颜色用8bit表示,即我们熟悉的RGB表示法,一个颜色三字节。
- Sort Flag 表示是否对颜色表里的颜色进行优先度排序,把常用的排在前面,这个主要是为了适应一些颜色解析度低的早期渲染器,现在已经很少使用了。
- Global Color Table 表示颜色表的长度,计算规则是值+1作为2的幂,得到的数字就是颜色表的项数,取最大值111时,项数=256,也就是说GIF格式最多支持256色的位图,再乘以Color Resolution算出的字节数,就是调色盘的总长度。
这四个字段一起定义了调色盘的信息。
Background color Index 定义了图像透明区域的背景色在调色盘里的索引。
Pixel Aspect Ratio 定义了像素宽高比,一般为0。
从gif的二进制格式中验证上面说的两点:
我们尝试改变自己的gif调色盘的大小,进行重压缩,看看会发生什么:
gifsicle --colors=32 zijizuode.gif > zijizuode-32.gif
gifsicle --colors=16 zijizuode.gif > zijizuode-16.gif
gifsicle --colors=2 zijizuode.gif > zijizuode-2.gif
...
结论是:如果可以接受牺牲图像的部分视觉效果,就可以通过减色来对图像做进一步压缩
参考:
庖丁解牛:GIF
https://www.qcloud.com/community/article/946621001490345387
http://www.jianshu.com/p/38743ef278ac
https://github.com/bumptech/glide
gifsicle
-
256色
每一色光以8位元表示,每个通道各有256(28)种阶调,三色光交互增减,RGB三色光能在一个像素上最高显示1677万种色(256256256=16,777,216),这个数值就是电脑所能表示的最高色彩。普遍认为人眼对色彩的分辨能力大致是一千万色,因此由RGB形成的图像均称做真彩色。
-
LZW 无损数据压缩算法
特点:具有可逆推的逻辑程序
算法:基本思路是,对于原始数据,将每个第一次出现的串放在一个串表中,用索引来表示串,后续遇到同样的串,简化为索引来存储(串表压缩法)。
编码:
原始数据为aabcaac,其字符串编码表为:
解码:
解码依据是将压缩数据与原先字符串编码表对照,并将对应的字符放于一个暂存队列中,依序将压缩数据读入,若为重复数据保存于队列中,若不为重复数据,则扩充一个新的码置于字符串编码表中。
缺点:
那就是原始数据串最好是有大量的子串多次重复出现,重复的越多,压缩效果越好。反之则越差,可能真的不减反增了
Gif压缩算法详解及实现
服务端GIF转换视频技术实现方式:
- python 脚本 movie2gif
- python 中只用ffmpeg
>>> import ffmpy
>>> ff = ffmpy.FFmpeg(
... inputs={'input.gif': None},
... outputs={'output.mp4': None}
... )
>>> ff.run()
- python 中使用MoviePy
import moviepy.editor as mp
clip = mp.VideoFileClip("mygif.gif")
clip.write_videofile("myvideo.mp4")
- 视频加标题QuickTime
- gif2gfy
- 可参考源码以及主意事项 PHP转换gif->video
- ffmpeg 资料:
FFMPEG 使用说明
使用 ffmpeg 实现 MP4 与 GIF 的互转
如何使用ffmpeg将webm转mp4?
ffmpeg 常用命令汇总
FFmpeg实用命令
H.264
h.264是一种视频的编码方式,它的出现提高了视频的压缩比和网络亲和力。先简单了解一下它是如何进行视频压缩的。视频压缩目的是减少和去除冗余视频数据
h.264分层结构
H.264 的功能分为两层
- 视频编码层(VCL, Video Coding Layer)
- 网络提取层(NAL, Network Abstraction Layer)。
一个视频其实是像gif一样,由很多张的图片组成,但是H.264的原始码流(又称为裸流),却是由一个接一个NALU组成的,如下图:
那么视频中的图片是如何跟NALU关联的呢?
一帧图片经过 H.264 编码器之后,就被编码为一个或多个片(slice),而装载着这些片(slice)的载体,就是 NALU
片(slice),是 H.264 中提出的新概念,是通过编码图片后切分通过高效的方式整合出来的概念,一张图片至少有一个或多个片(slice),片的结构:
视频包涵图片,图片包涵片,片包涵宏块,宏块就是存储像素数据的地方。
宏块的解释:
- 宏块是视频信息的主要承载者,因为它包含着每一个像素的亮度和色度信息。视频解码最主要的工作则是提供高效的方式从码流中获得宏块中的像素阵列。
- 组成部分:一个宏块由一个16×16亮度像素和附加的一个8×8 Cb和一个 8×8 Cr 彩色像素块组成。每个图象中,若干宏块被排列成片的形式。
切片和宏块的关系:
I片:只包 I宏块,I 宏块利用从当前片中已解码的像素作为参考进行帧内预测(不能取其它片中的已解码像素作为参考进行帧内预测)。
P片:可包 P和I宏块,P 宏块利用前面已编码图象作为参考图象进行帧内预测,一个帧内编码的宏块可进一步作宏块的分割:即 16×16、16×8、8×16 或 8×8 亮度像素块(以及附带的彩色像素);如果选了 8×8 的子宏块,则可再分成各种子宏块的分割,其尺寸为 8×8、8×4、4×8 或 4×4 亮度像素块(以及附带的彩色像素)。
B片:可包 B和I宏块,B 宏块则利用双向的参考图象(当前和 来的已编码图象帧)进行帧内预测。
SP片(切换P):用于不同编码流之间的切换,包含 P 和/或 I 宏块
SI片:扩展档次中必须具有的切换,它包 了一种特殊类型的编码宏块,叫做 SI 宏块,SI 也是扩展档次中的必备功能。
整体结构
综上所述,数据可以抽象成这样:
或者这样:
问题:
知道了h264以这样的方式组织数据,那么怎么就能压缩呢?或者说为什么这样做呢?
- I帧(帧内编码帧)是一种自带全部信息的独立帧,无需参考其它图像便可独立进行解码。视频序列中的第一个帧始终都是I帧。如果所传输的比特流遭到破坏,则需要将I帧用作新查看器的起始点或重新同步点。I帧可以用来实现快进、快退以及其它随机访问功能。如果新的客户端将参与查看视频流,编码器将以相同的时间间隔或者根据要求自动插入I帧。I帧的缺点在于它们会占用更多的数据位,但从另一方面看,I帧不会产生可觉察的模糊现象。
- P帧(帧间预测编码帧)需要参考前面的I帧和/或P帧的不同部分才能进行编码。与I帧相比,P帧通常占用更少的数据位,但其缺点是,由于P帧对前面的P和I参考帧有着复杂的依赖性,因此对传输错误非常敏感。
- B帧(双向预测编码帧)需要同时以前面的帧和后面的帧作为参考帧。
看完上面的一大堆应该还是一头雾水,先让我们看看它减少数据量的基本方法,此处可以回忆一下gif的压缩实现。。。
减少数据量的基本方法
在一系列的帧内,可以通过差分编码这样的方法来减少视频数据量,包括H.264在内的大多数视频压缩标准都采用这种方法。在差分编码中,会将一个帧与参考帧(即前面的I帧或P帧)进行对比,然后只对那些相对于参考帧来说发生了变化的像素进行编码。通过这种方法,可以降低需要进行编码和发送的像素值。
结论:经过对比gif和h264的压缩,gif中会将重复出现的序列用相同的符号表示,但是在h264中相同的序列直接不发送,而是通过帧间预测,所以h264的压缩效率更高。
参考:
新一代视频压缩编码标准
H.264视频压缩标准
深入浅出理解视频编码H264结构
H.264码流以及H.264编解码的基本概念
深度解析H.264编码原理
雷霄骅(leixiaohua1020)的专栏
作者才疏学浅,欢迎大牛吐槽。