最近研究这一部分,试图配合自创的压缩方式,形成自有的视频格式,试验总结如下。(以前没接触过这一块,都是在网上临时学习的,边学边试验,得出初步的结果)
1. 当前大部分视频经过DCT(离散余弦变换)处理后压缩,视频处理过程(编码过程)如下:
视频帧 -> 分解成YUV色差 -> UV色差偏移+128 -> 分区块DCT处理 -> 量化 -> 压缩 -> 压缩帧打包。视频解压是反过来的,(解码过程)如下:
视频帧 <- YUV色差合成RGB <- UV色差偏移-128 <- 反向DCT还原YUV区块 <- 反向量化 <- 解压 <- 压缩帧解包。
2. DCT理论是无损的,得到的是浮点数,再用浮点反向DCT变换,回复原数(是浮点都会有损失,取决于浮点精度)。因压缩需要整形数,所以转成整形数,这一过程称“量化”,造成一定损失,如果DCT后将浮点数“放大”(乘以某数,提高精度),恢复质量有所提高,但压缩率下降。一般称这一数为量化质量,为10时,压缩率为20%,图像质量尚可,不“放大”,显示效果极差,无法接受。
3. DCT输入范围:测试过字节和字输入,特性一样。有符号数和无符号数特性基本一样。
4. 传统视频(几乎当前所有视频)需要转成YUV色差方式再DCT变换压缩,是因为以下三个原因:
(1)最早期是黑白电视机,也就是黑白灰度信号,当彩色电视机出现后,为了兼容黑白电视机,选择了色差信号,其中Y是三个基色合成的信号,可以针对彩色和黑白电视机。
(2)压缩需要,由于对颜色细节不敏感,单独减少颜色细节,具有一定压缩作用。
(3)因最早是由黑白电视机、摄像机、录像机、演播传播系统等发展而来,选择的是兼容方式,当今虽然有RGB摄像及录像原始信号,但未压缩,无法正常使用,所以需要转色差方式压缩。
5. 作为一款自研多媒体软件,视频是不可少的,现有视频播放器都是调用别人的视频播放库,没有任何自主权,虽然有免费的库,但考虑到完全自控,简洁,还是要走创新的路,思路如下:
(1)视频分解成色差方式,其一是为了“兼容”传统黑白系统,作为独立软件不需要考虑“兼容”,采用自有格式,自己的播放器。
(2)视频压缩不同于传统压缩,要求速度,还要兼顾压缩率,看了当今几乎所以的压缩原理,通过融合自我想法,尝试新压缩方法。
(3)转换成色差,压缩颜色,充分利用视觉特点也是很好的方案,相对基于RGB的压缩方式,是否有优势,还需更多的思考。目前可以确定 YUV4:2:0 效果不好,YUV4:1:1 有改善,但很少用,YUV4:2:2 效果和压缩均衡,相对较好。YUV的不足是需要分离视频,需要运算,耗用一定时间,另一个问题是三个基色相互依赖,对还原色纯度不利。
(4)如果分别压缩RGB三个基色变量,因相互无牵连,当压缩率不同时,可能造成色彩混乱。所以RGB作为一个变量压缩,使用最多的RGB888也就是RGB24原始彩色格式,作为一个24位无符号变量,但没有相关量化表,出现困局。
(5)自己造量化表有点悬了,量化表是根据心里因素,对去除图像中的高频分量(也就是清晰度),做了权衡,是相关专家组经过大量实践得出的,经试验,确实如此。
(6)转了一圈,还是回到了色差方式,不是为了兼容,而是为了压缩色彩,利用现有资源,先做到自主,完全掌握,迈出第一步。
6. 相关参考:
//YUV转换宏 #define MY(R, G, B) ( R * 0.2989 + G * 0.5866 + B * 0.1145) #define MU(R, G, B) ((R * (-0.1688) + G * (-0.3312) + B * 0.5000 + 128)) #define MV(R, G, B) ((R * 0.5000 + G * (-0.4184) + B * (-0.0816) + 128)) const BYTE bzYQTable[8][8] = { //亮度Y量化表 {16,11,10,16,24,40,51,61}, {12,12,14,19,26,58,60,55}, {14,13,16,24,40,57,69,56}, {14,17,22,29,51,87,80,62}, {18,22,37,56,68,109,103,77}, {24,35,55,64,81,104,113,92}, {49,64,78,87,103,121,120,101}, {72,92,95,98,112,100,103,99}}; const BYTE bzUVQTable[8][8] = { //色度UV量化表 {17,18,24,47,99,99,99,99}, {18,21,26,66,99,99,99,99}, {24,26,56,99,99,99,99,99}, {47,66,99,99,99,99,99,99}, {99,99,99,99,99,99,99,99}, {99,99,99,99,99,99,99,99}, {99,99,99,99,99,99,99,99}, {99,99,99,99,99,99,99,99}}; void __fastcall CDCT::DCT(float fOutPut[][8], char czInPut[][8])//离散余玄变换 { float ALPHA, BETA, tmp; int u,v,i,j; for(u = 0; u < 8; u++) { for(v = 0; v < 8; v++) { if(u == 0) ALPHA = sqrt(1.0 / 8.0); else ALPHA = sqrt(2.0 / 8.0); if(v == 0) BETA = sqrt(1.0 / 8.0); else BETA = sqrt(2.0 / 8.0); tmp = 0.0; for(i = 0; i < 8; i++) for(j = 0; j < 8; j++) { tmp += czInPut[i][j] * cos((2 * i + 1) * u * PI / (2 * 8)) * cos((2 * j + 1) * v * PI / (2 * 8)); } fOutPut[u][v] = ALPHA * BETA * tmp; } } } void __fastcall CDCT::Quant(int czOutPut[][8], float InMatrix[][8], const BYTE bzQTable[][8])//量化 { int x,y; float fQuant; for(x = 0; x < 8; x++) for(y = 0; y < 8; y++) { fQuant = InMatrix[x][y] / bzQTable[x][y];//量化 fQuant = fQuant * byQuantizationQuality;//量化质量 czOutPut[x][y] = (int)fQuant;//截尾 } }