为修改后的JPEG解码器快速实现8点1d DCT

时间:2016-04-04 23:08:03

标签: javascript video jpeg dct

我一直致力于在网络上使用自定义视频编解码器。自定义编解码器将由javascript和html5 Canvas元素提供支持。

我想要这样做有几个原因,我将在这个问题的底部列出,但首先我想解释一下到目前为止我做了什么以及为什么我要寻找快速DCT变换。

所有视频压缩背后的主要思想是彼此相邻的帧共享大量相似之处。所以我正在做的是将第一帧压缩为jpg。然后我发送另一个Jpeg图像,该图像的宽度是第一帧的8倍,保持第一帧和之后的8帧之间的“差异”。

这个保持“差异”的大型Jpeg图像更容易压缩,因为它只有差异。

我用这个大型jpeg进行了很多实验,我发现当转换为YCbCr颜色空间时,“色度”通道几乎完全是平坦的,有一些突出的例外。换句话说,视频中很少有部分在色度通道中发生很大变化,但是一些确实发生变化的部分非常重要。

凭借这些知识,我查看了JPEG压缩的工作原理,并发现它使用DCT压缩每个8x8块。这真的让我感兴趣,因为我想如果我可以修改它,这样它不仅可以压缩“每个”8x8块,而且还会检查“下一个”8x8块是否与第一块相似。如果它足够接近,那么只需发送第一个块并对两个块使用相同的数据。

这将提高解码速度,并提高比特率传输,因为可以使用更少的数据。

我认为这应该是一项简单的任务。所以我试着建立自己的“修改过的”jpeg编码器/解码器。我建立了RGB到YCbCr转换器,我留下了“gzip”压缩来做霍夫曼编码,现在我剩下的唯一主要部分是进行DCT变换。

然而这让我陷入困境。我找不到快速的8点1d dct变换。我正在寻找这种特定的变换,因为根据许多文章,我已经阅读过2d 8x8 dct变换可以分成几个1x8 id变换。这是许多jpeg实现的方法,因为它处理起来更快。

所以我认为Jpeg是一个古老的知名标准,快速的8点1d dct应该跳出来,但经过数周的搜索,我还没找到一个。

我发现许多使用O(N ^ 2)复杂性方法的算法。然而,这是令人费解的缓慢。我还发现了使用快速傅里叶变换的算法,并且我修改了它们来计算DCT。比如下面这个链接中的那个:

https://www.nayuki.io/page/free-small-fft-in-multiple-languages

理论上这应该具有O(Nlog2(n))的“快速”复杂性,但是当我运行它时,我的i7计算机需要大约12秒来编码/解码“修改过的”jpeg。

我不明白为什么这么慢?还有其他javascript jpeg解码器可以更快地完成它,但是当我尝试查看它们的源代码时,我无法确定哪个部分正在进行DCT / IDCT转换。

https://github.com/notmasteryet/jpgjs

我唯一能想到的可能是DCT背后的数学已经预先计算好并存储在查找表中。但是我在google上看起来很努力,而且我找不到任何(我至少理解的)谈论这个问题。

所以我的问题是我在哪里可以找到/如何为这个“修改过的”jpeg编码器/解码器构建一个快速计算8点1d dct变换的方法。任何有关这方面的帮助将不胜感激。

好的,为什么我要这样做,主要原因是我希望在我的网站上为手机提供“互动”视频。这是无法做到的,因为iOS每次开始播放视频时都会加载它的“原生”快速播放器。此外,如果您对移动设备上的视频呈现方式有如此少的控制,那么转换到视频的另一个时间点变得非常“平滑”也很困难。

非常感谢任何人提供的任何帮助!

3 个答案:

答案 0 :(得分:1)

  
    

所以我的问题是我在哪里可以找到/如何为这个“修改过的”jpeg编码器/解码器构建一个快速计算8点1d dct变换的方法。对此的任何帮助将不胜感激。

  

在那里查看flash-world和JPEG编码器(在它被集成到引擎之前)。
例如:http://www.bytearray.org/?p=1089(提供的源代码)此代码包含一个名为fDCTQuant()的函数,它执行DCT,首先是行,然后是列,然后它量化块(所以基本上你在那里)有你的8x1 DCT)。

  
    

所以我正在做的是将第一帧压缩为jpg。然后我发送另一个Jpeg图像......

  

看一下渐进式JPEG。我认为这样做的一些方法,以及如何构建数据流对于这种描述听起来很熟悉(不一样,但它们都是相关的方向.imo)

  
    

如果我可以修改它以便它不仅压缩“每个”8x8块,而且还检查“下一个”8x8块是否与第一个块类似。如果它足够接近,那么只需发送第一个块并对两个块使用相同的数据。

  

表达“相似”和“足够接近”引起了我的注意。看一下常用的量化表。你知道,根据8x8块中的位置以及所应用的量词,将值的值改变1可以很容易地导致该点的15%亮度(通常更多的色度通道)的值变化。

calculation with quantifier 40
(may be included in the set even at the lowest compression rates
at lower compression rates some quantifier can go up to 100 and beyond)

change the input by 1 changes the output by 40.
since we are working on 1byte value-range it's a change of 40/255
that is about 15% of the total possible range

所以你应该真的深思熟虑,你称之为“足够接近”。

总结一下:基于jpeg的视频编解码器利用帧之间的差异来减少数据量。这对我来说也很熟悉。

知道了:MPEG https://github.com/phoboslab/jsmpeg
*没有与引用代码或编码器的连接

答案 1 :(得分:0)

答案 2 :(得分:0)

我在这里实现了各种大小的可分离整数2D DCT(以及其他变换):https://github.com/flanglet/kanzi/tree/master/java/src/kanzi/transform。代码是用Java编写的,但实际上对于这种算法,它在任何语言中几乎都是一样的。 IMO最有趣的部分是在计算每个方向后进行的重新缩放。根据您的目标(最大精度,16位计算,无缩放......),您可能希望更改每个步骤的缩放因子。在图像非常均匀的区域使用较大的块可以节省比特。