精华内容
下载资源
问答
  • 为什么需要编码?原始视频数据很庞大,比如一个150分钟,30FPS,分辨率为720✖480的彩色电影需要占用280GB。无论物理存储还是网络传输,这都难以负担的。...熵编码压缩有限的,但是得益于人类的视觉...

    b2caf487c6416246078c71f7b3ce79b3.png

    为什么需要编码?

    原始视频数据很庞大,比如一个150分钟,30FPS,分辨率为720✖480的彩色电影需要占用280GB。无论是物理存储还是网络传输,这都是难以负担的。所以需要编码进行压缩。

    编码方式

    一般有两种编码方式:熵编码(entropy coding,以无损的方式将视频压缩到香农极限)和有损编码(lossy coding,删除冗余数据和不重要的数据)。熵编码的压缩率是有限的,但是得益于人类的视觉系统可以容忍细节丢失,有损压缩通常很有效。

    典型的编解码码流程

    下图展示了编解码的整体流程。

    摄像头采集到数据,进行编码,传输或者保存编码后的数据,终端拿到数据后进行解码并显示。

    027f839bdf10c0e9edd137b7873854d1.png

    下图展示了一个典型的编码流程:

    f460bd70a058d61ef299781cbcb26233.png

    一个典型的视频编码一般由三个模块组成:

    1. 预测性编码(Predictive coding)
    2. 转换编码(Transform coding)
    3. 熵编码(Entropy coding)

    通常编码一个视频会产生若干完整的帧数据(I帧)和增量帧数据(P帧)。 完整帧只需要通过转换编码和熵编码进行压缩。本文主要考虑增量帧的编解码。

    预测性编码

    预测性编码通过利用时间(帧间预测)和空间冗余(帧内预测)来减少视频的冗余度。 通常预测性编码有两步:运动估计(Motion estimation, ME)和运动补偿(Motion compensation, MC)

    运动估计为当前帧的某个区域(A)在参考帧中寻找一个合适的匹配区域(B)。(参考帧可以是之前的帧,也可以是后面的帧)

    9f56ed6d58f976b0a8643e80c8935308.png

    运动补偿找到区域A和区域B的不同

    33e821a7fe5e4d97f9cb7b9aa6865882.png

    通过ME和MC预测性编码会产生一些运动矢量和残差。运动矢量就是某些区域针对参考帧的运动轨迹,而残差就是这些区域运动后产生的预测帧和当前帧之间的不同。

    举个不太恰当的例子:(不恰当的地方在于真实的编码中运动矢量涉及的区域不会这么大,比如H.264编码的最大区域为16✖16)

    下象棋时,开局时为参考帧,炮二平五后为当前帧,如图:

    e02106ab0b925abf79babc0a88e9ae40.png

    这时运动矢量就是炮二的区域移动到炮五的区域,移动后产生一个预测帧。预测帧和当前帧并不完全一样,他们的区别就是残差。 此时的残差则是炮二位置的棋格,以及炮五边框的颜色变化。

    预测性编码的产出就是这些运动矢量和残差,通过这个例子我们能看到这些产出数据是远远小于一个完整帧的数据量的。

    转换编码(有损压缩)

    转换编码模块的产出是一组系数,每个系数是标准基础图案的权重。 通过量化器之后,可获得降低精度但节省位的量化系数。
    反过来标准基础图案使用这些量化系数可以得到量化前的图案。

    例如,1974年开发的离散余弦变换(DCT)是一种广泛使用的变换编码技术。 H.264编码就是将残差通过转换编码转换为DCT系数。


    详细流程就不赘(知)述(道)了。。。
    基本原理利用了傅里叶变换思想(使用一些正余弦公式表示图像)
    下面的公式中y为编码前的图案,x为标准基础图案数据,f(x)是一个公式,里面会涉及一组系数k,这一组k就是转换编码的输出。

    一个16✖16的图案,大概需要80个系数就足够了,这时的压缩率为31.25%

    熵编码(无损压缩)

    将前面得到的所有数据进行压缩,包括运动矢量、残差的量化系数、还有预测性编码的一些参数。 常见的熵编码方法包括可变长度编码(VLC),算术编码和霍夫曼编码。 以大家最熟悉的霍夫曼编码为例,它根据数据出现的频率对数据进行编码,频率高的编码后的长度短,频率低的编码后的长度长。

    解码

    编码流程的逆序就是解码流程。

    解码器拿到编码后的数据后:

    • 根据熵编码的类型,将压缩的数据展开,得到转换编码数据(运动矢量、残差的量化系数、还有预测性编码的一些参数)
    • 根据残差的量化系数,得到残差数据
    • 在参考帧的基础上,实施这些运动矢量,产生预测帧
    • 在预测帧的基础上,叠加残差数据,得到当前帧

    以上就是本文的全部内容,有疑问,或者文章有什么问题,请留言,谢谢!

    参考文献: AN OVERVIEW OF EMERGING VIDEO CODING STANDARDS

    展开全文
  • 想想一下,当你需要处理500TB的数据的时候,你最先要做的是存储下来。你是选择源文件存储呢?还是处理压缩再存储?...hadoop面临的情况也是一样的,大量的数据需要存储在磁盘或者内存中,进行压缩是一种经
    想想一下,当你需要处理500TB的数据的时候,你最先要做的是存储下来。你是选择源文件存储呢?还是处理压缩再存储?很显然,压缩编码处理是必须的。一段刚刚捕获的60分钟原始视屏可能达到2G,经过压缩处理可以减至500MB左右,一张单反照片可能有5MB,经过压缩之后只有400KB,而质量不会发生明显的损失。
     
    hadoop面临的情况也是一样的,大量的数据需要存储在磁盘或者内存中,进行压缩是一种经济的方法。对数据文件进行压缩,可以有效减少存储文件所需的空间,并加快数据在网络上或者到磁盘上的传输速度。在Hadoop中,压缩应用于文件存储、Map阶段到Reduce阶段的数据交换(需要打开相关的选项)等情景。

    数据压缩的方式非常多,不同特点的数据有不同的数据压缩方式:如对声音和图像等特殊数据的压缩,就可以采用有损的压缩方法,允许压缩过程中损失一定的信 息,换取比较大的压缩比;而对音乐数据的压缩,由于数据有自己比较特殊的编码方式,因此也可以采用一些针对这些特殊编码的专用数据压缩算法。

     

    hadoop使用的压缩工具主要有:

     
    压缩格式 工具 算法 扩展名 多文件 可分割性
    DEFLATE DEFLATE .deflate
    GZIP gzip DEFLATE .gzp
    ZIP zip DEFLATE .zip 是,在文件范围内
    BZIP2 bzip2 BZIP2 .bz2
    LZO lzop LZO .lzo
     
     
    hadoop使用的编码器:
     
     
    考察压缩工具的性能,主要从时间和空间考虑,一个压缩工具,压缩同样的文件,花费的时间越短,空间越少,压缩率越大,我们就会越喜欢他。另外还要考虑的就是可不可以分割文件,在hadoop中不能够分割文件是个不好的消息。因为hadoop处理数据进行计算的时候,需要将大量的大文件拆分,分割就很重要了。
     
    哪个性能好呢?(下面表格数据引自IBM
     
    压缩算法 原始文件大小 压缩文件大小 压缩速度 解压速度
    gzip 8.3GB 1.8GB 17.5MB/s 58MB/s
    bzip2 8.3GB 1.1GB 2.4MB/s 9.5MB/s
    LZO-bset 8.3GB 2GB 4MB/s 60.6MB/s
    LZO 8.3GB 2.9GB 49.3MB/s 74.6MB/s

    这还不是全部,hadoop通过压缩流,也就是将文件写进压缩流里面进行数据读写,性能如何呢?
     
     
        以下引自xuxm2007
    CompressionCodec对流进行压缩和解压缩
    CompressionCodec有两个方法可以用于轻松地压缩或解压缩数据。要想对正在被写入一个输出流的数据进行压缩,我们可以使用 createOutputStream(OutputStreamout)方法创建一个CompressionOutputStream(未压缩的数据将 被写到此),将其以压缩格式写入底层的流。相反,要想对从输入流读取而来的数据进行解压缩,则调用 createInputStream(InputStreamin)函数,从而获得一个CompressionInputStream,,从而从底层的流 读取未压缩的数据。CompressionOutputStream和CompressionInputStream类似干 java.util.zip.DeflaterOutputStream和java.util.zip.DeflaterInputStream,前两者 还可以提供重置其底层压缩和解压缩功能,当把数据流中的section压缩为单独的块时,这比较重要。比如SequenceFile。

    下例中说明了如何使用API来压缩从标谁输入读取的数据及如何将它写到标准输出:

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class StreamCompressor 
    {
         public static void main(String[] args) throws Exception 
         {
              String codecClassname = args[0];
              Class<?> codecClass = Class.forName(codecClassname); // 通过名称找对应的编码/解码器
              Configuration conf = new Configuration();
    CompressionCodec codec = (CompressionCodec) ReflectionUtils.newInstance(codecClass, conf);
     // 通过编码/解码器创建对应的输出流
              CompressionOutputStream out = codec.createOutputStream(System.out);
     // 压缩
              IOUtils.copyBytes(System.in, out, 4096, false);
              out.finish();
         }
     
     
    用CompressionCodecFactory方法来推断CompressionCodecs

        

    在阅读一个压缩文件时,我们通常可以从其扩展名来推断出它的编码/解码器。以.gz结尾的文件可以用GzipCodec来阅读,如此类推。每个压缩格式的扩展名如第一个表格;

    CompressionCodecFactory提供了getCodec()方法,从而将文件扩展名映射到相应的CompressionCodec。此方法接受一个Path对象。下面的例子显示了一个应用程序,此程序便使用这个功能来解压缩文件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    public class FileDecompressor {
        public static void main(String[] args) throws Exception {
           String uri = args[0];
           Configuration conf = new Configuration();
           FileSystem fs = FileSystem.get(URI.create(uri), conf);
           Path inputPath = new Path(uri);
           CompressionCodecFactory factory = new CompressionCodecFactory(conf);
           CompressionCodec codec = factory.getCodec(inputPath);
           if (codec == null) {
               System.err.println("No codec found for " + uri);
               System.exit(1);
           }
           String outputUri =
           CompressionCodecFactory.removeSuffix(uri, codec.getDefaultExtension());
           InputStream in null;
           OutputStream out = null;
           try {
               in = codec.createInputStream(fs.open(inputPath));
               out = fs.create(new Path(outputUri));
               IOUtils.copyBytes(in, out, conf);
           } finally {
               IOUtils.closeStream(in);
               IOUtils.closeStream(out);
           }
        }
    }
    编码/解码器一旦找到,就会被用来去掉文件名后缀生成输出文件名(通过CompressionCodecFactory的静态方法removeSuffix()来实现)。这样,如下调用程序便把一个名为file.gz的文件解压缩为file文件:
    % hadoop FileDecompressor file.gz
    CompressionCodecFactory 从io.compression.codecs配置属性定义的列表中找到编码/解码器。默认情况下,这个列表列出了Hadoop提供的所有编码/解码器 (见表4-3),如果你有一个希望要注册的编码/解码器(如外部托管的LZO编码/解码器)你可以改变这个列表。每个编码/解码器知道它的默认文件扩展 名,从而使CompressionCodecFactory可以通过搜索这个列表来找到一个给定的扩展名相匹配的编码/解码器(如果有的话)。
     属性名  类型  默认值  描述
    io.compression.codecs 逗号分隔的类名 org.apache.hadoop.io.compress.DefaultCodec,
    org.apache.hadoop.io.compress.GzipCodec,
    org.apache.hadoop.io.compress.Bzip2Codec
    用于压缩/解压的CompressionCodec列表

     

     
    本地库

    考虑到性能,最好使用一个本地库(native library)来压缩和解压。例如,在一个测试中,使用本地gzip压缩库减少了解压时间50%,压缩时间大约减少了10%(与内置的Java实现相比 较)。表4-4展示了Java和本地提供的每个压缩格式的实现。井不是所有的格式都有本地实现(例如bzip2压缩),而另一些则仅有本地实现(例如 LZO)。

     

    压缩格式 Java实现 本地实现
    DEFLATE
    gzip
    bzip2
    LZO

     

    Hadoop带有预置的32位和64位Linux的本地压缩库,位于库/本地目录。对于其他平台,需要自己编译库,具体请参见Hadoop的维基百科http://wiki.apache.org/hadoop/NativeHadoop。

    本地库通过Java系统属性java.library.path来使用。Hadoop的脚本在bin目录中已经设置好这个属性,但如果不使用该脚本,则需要在应用中设置属性。

    默认情况下,Hadoop会在它运行的平台上查找本地库,如果发现就自动加载。这意味着不必更改任何配置设置就可以使用本地库。在某些情况下,可能 希望禁用本地库,比如在调试压缩相关问题的时候。为此,将属性hadoop.native.lib设置为false,即可确保内置的Java等同内置实现 被使用(如果它们可用的话)。

    CodecPool(压缩解码池)

    如果要用本地库在应用中大量执行压缩解压任务,可以考虑使用CodecPool,从而重用压缩程序和解压缩程序,节约创建这些对象的开销。

    下例所用的API只创建了一个很简单的压缩程序,因此不必使用这个池。此应用程序使用一个压缩池程序来压缩从标准输入读入然后将其写入标准愉出的数据:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class PooledStreamCompressor 
     {
        public static void main(String[] args) throws Exception 
        {
            String codecClassname = args[0];
            Class<?> codecClass = Class.forName(codecClassname);
            Configuration conf = new Configuration();
    CompressionCodec codec = (CompressionCodec) ReflectionUtils.newInstance(codecClass, conf);
            Compressor compressor = null;
            try {
    compressor = CodecPool.getCompressor(codec);//从缓冲池中为指定的CompressionCodec检索到一个Compressor实例
    CompressionOutputStream out = codec.createOutputStream(System.out, compressor);
                IOUtils.copyBytes(System.in, out, 4096, false);
                out.finish();
            } finally
            {
                CodecPool.returnCompressor(compressor);
            }
          }
     
    我 们从缓冲池中为指定的CompressionCodec检索到一个Compressor实例,codec的重载方法 createOutputStream()中使用的便是它。通过使用finally块,我们便可确保此压缩程序会被返回缓冲池,即使在复制数据流之间的字 节期间抛出了一个IOException。
    压缩和输入分割
    在考虑如何压缩那些将由MapReduce处理的数据时,考虑压缩格式是否支持分割是很重要的。考虑存储在HDFS中的未压缩的文件,其大小为1GB. HDFS块的大小为64MB ,所以文件将被存储为16块,将此文件用作输入的MapReduce会创建16个输入分片(split,也称为"分块"),每个分片都被作为一个独立map任务的输入单独进行处理。
     
    现在假设,该文件是一个gzip格式的压缩文件,压缩后的大小为1GB。和前面一样,HDFS将此文件存储为 16块。然而,针对每一块创建一个分块是没有用的因为不可能从gzip数据流中的任意点开始读取,map任务也不可能独立于其分块只读取一个分块中的数据。gZlp格式使用DEFLATE来存储压缩过的数据,DEFLATE 将数据作为一系列压缩过的块进行存储。问题是,每块的开始没有指定用户在数据流中任意点定位到下一个块的起始位置,而是其自身与数据流同步。因此,gzip不支持分割(块)机制。在这种情况下,MapReduce不分割gzip格式的文件,因为它知道输入的是gzip格式(通过文件扩展名得知),而gzip压缩机制不支持分割机制。这样是以牺牲本地化为代价:一个map任务将处理16个HDFS块,大都不是map的本地数据。与此同时,因为map任务少,所以作业分割的粒度不够细,从而导致运行时间变长。
     
    在我们假设的例子中,如果是一个LZO格式的文件,我们会碰到同样的问题,因为基本压缩格式不为reader 提供方法使其与流同步。但是,bzip2格式的压缩文件确实提供了块与块之间的同步标记(一个48位的π近似值) 因此它支持分割机制。对于文件的收集,这些问题会稍有不同。ZIP是存档格式,因此t可以将多个文件合并为一个ZIP文件。每个文单独压缩,所有文档的存储位置存储在ZIP文件的尾部。这个属性表明Z l P 文件支持文件边界处分割,每个分片中包括ZIP压缩文件中的一个或多个文件。
     
    ZIP格式文件的结构如下图:ZIP文件结构请查看wiki
     
     
    在MapReduce 中使用压缩
     
    如前所述,如果输入的文件是压缩过的.那么在被MapReduce 读取时,它们会被自动解压,根据文件扩展名来决定应该使用哪一个压缩解码器。如果要压缩MapReduce作业的输出.请在作业配置文件中将mapred.output.compress属性设置为true,将mapred.output.compression.codec属性设置为自己打算使用的压缩编码/解码器的类名。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
        public class MaxTemperatureWithCompression {
     
            public static void main(String[] args) throws Exception {
                if (args.length != 2) {
                    System.err.println("Usage: MaxTemperatureWithCompression <input path> "
                            "<output path>");
                    System.exit(-1);
                }
                Job job = new Job();
                job.setJarByClass(MaxTemperature.class);
                FileInputFormat.addInputPath(job, new Path(args[0]));
                FileOutputFormat.setOutputPath(job, new Path(args[1]));
                job.setOutputKeyClass(Text.class);
                job.setOutputValueClass(IntWritable.class);
                FileOutputFormat.setCompressOutput(job, true);
                FileOutputFormat.setOutputCompressorClass(job, GzipCodec.class);
                job.setMapperClass(MaxTemperatureMapper.class);
                job.setCombinerClass(MaxTemperatureReducer.class);
                job.setReducerClass(MaxTemperatureReducer.class);
                System.exit(job.waitForCompletion(true) ? 0 1);
            }
        }
     
    我们使用压缩过的输入来运行此应用程序(其实不必像它一样使用和输入相同的格式压缩输出),如下所示:
    % hadoop MaxTemperatur eWithCompression input/ ncdc/sample.txt.gz
    output
    量生终输出的每部分都是压缩过的.在本例中,只有一部分:
    % gunzip -c output/part-OOOOO.gz
    1949 111
    1950 22
    如果为输出使用了一系列文件, 可以设置mapred.output.compresson.type 属性来控制压缩类型。默认为RECORD,它压缩单独的记录。将它改为BLOCK,可以压缩一组记录,由于有更好的压缩比,所以推荐使用。
     
    map 作业输出结果的压缩
    即使MapReduce 应用使用非压缩的数据来读取和写入,我们也可以受益于压缩map阶段的中阔输出。因为map作业的输出会被写入磁盘并通过网络传输到reducer节点,所以如果使用LZO之类的快速压缩,能得到更好的性能,因为传输的数据量大大减少了.表4-5显示了启用map输出压缩和设置压缩格式的配置属性.
    下面几行代码用于在map 作业中启用gzi p 格式来压缩输出结果:
    1
    2
    3
    4
    5
    Configuration conf = new Configuration();
    conf.setBoolean("mapred.compress.map.output"true);
    conf.setClass("mapred.map.output.compression.codec", GzipCodec.class,
    CompressionCodec.class);
    Job job = new Job(conf);
     

    旧的API要这样配置

    1
    2
    conf.setCompressMapOutput(true);
    conf.setMapOutputCompressorClass(GzipCodec.class);


    压缩就到此为止了。总之编码和解码在hadoop有着关键的作用。

     

     

     

     

     

    Charles 于P.P 

     

     

     

     

     

     

    版权说明:
    本文由Charles Dong原创,本人支持开源以及免费有益的传播,反对商业化谋利。
    CSDN博客:http://blog.csdn.net/mrcharles
    个人站:http://blog.xingbod.cn
    EMAIL:charles@xingbod.cn
    展开全文
  • 非常显然,压缩编码处理必须的。一段刚刚捕获的60分钟原始视屏可能达到2G,经过压缩处理能够减至500MB左右。一张单反照片可能有5MB。经过压缩之后仅仅有400KB,而质量不会发生明显的损失。 hadoop面临的情况...
    想想一下,当你须要处理500TB的数据的时候,你最先要做的是存储下来。

    你是选择源文件存储呢?还是处理压缩再存储?非常显然,压缩编码处理是必须的。一段刚刚捕获的60分钟原始视屏可能达到2G,经过压缩处理能够减至500MB左右。一张单反照片可能有5MB。经过压缩之后仅仅有400KB,而质量不会发生明显的损失。


    hadoop面临的情况也是一样的,大量的数据须要存储在磁盘或者内存中,进行压缩是一种经济的方法。对数据文件进行压缩,能够有效降低存储文件所需的空间,并加快数据在网络上或者到磁盘上的传输速度。

    在Hadoop中。压缩应用于文件存储、Map阶段到Reduce阶段的数据交换(须要打开相关的选项)等情景。

    数据压缩的方式许多。不同特点的数据有不同的数据压缩方式:如对声音和图像等特殊数据的压缩,就能够採用有损的压缩方法,同意压缩过程中损失一定的信 息,换取比較大的压缩比。而对音乐数据的压缩,因为数据有自己比較特殊的编码方式,因此也能够採用一些针对这些特殊编码的专用数据压缩算法。


    hadoop使用的压缩工具主要有:


    压缩格式 工具 算法 扩展名 多文件 可切割性
    DEFLATE DEFLATE .deflate
    GZIP gzip DEFLATE .gzp
    ZIP zip DEFLATE .zip 是,在文件范围内
    BZIP2 bzip2 BZIP2 .bz2
    LZO lzop LZO .lzo


    hadoop使用的编码器:



    考察压缩工具的性能,主要从时间和空间考虑。一个压缩工具,压缩相同的文件。花费的时间越短。空间越少。压缩率越大,我们就会越喜欢他。

    另外还要考虑的就是可不可以切割文件。在hadoop中不可以切割文件是个不好的消息。

    由于hadoop处理数据进行计算的时候,须要将大量的大文件拆分,切割就非常重要了。


    哪个性能好呢?(以下表格数据引自IBM

    压缩算法 原始文件大小 压缩文件大小 压缩速度 解压速度
    gzip 8.3GB 1.8GB 17.5MB/s 58MB/s
    bzip2 8.3GB 1.1GB 2.4MB/s 9.5MB/s
    LZO-bset 8.3GB 2GB 4MB/s 60.6MB/s
    LZO 8.3GB 2.9GB 49.3MB/s 74.6MB/s

    这还不是所有。hadoop通过压缩流,也就是将文件写进压缩流里面进行数据读写,性能怎样呢?



        下面引自xuxm2007
    CompressionCodec对流进行压缩和解压缩
    CompressionCodec有两个方法能够用于轻松地压缩或解压缩数据。

    要想对正在被写入一个输出流的数据进行压缩。我们能够使用 createOutputStream(OutputStreamout)方法创建一个CompressionOutputStream(未压缩的数据将 被写到此),将其以压缩格式写入底层的流。相反。要想对从输入流读取而来的数据进行解压缩,则调用 createInputStream(InputStreamin)函数,从而获得一个CompressionInputStream,。从而从底层的流 读取未压缩的数据。CompressionOutputStream和CompressionInputStream类似干 java.util.zip.DeflaterOutputStream和java.util.zip.DeflaterInputStream,前两者 还能够提供重置其底层压缩和解压缩功能,当把数据流中的section压缩为单独的块时,这比較重要。比方SequenceFile。

    下例中说明了怎样使用API来压缩从标谁输入读取的数据及怎样将它写到标准输出:


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class StreamCompressor 
    {
         public static void main(String[] args) throws Exception 
         {
              String codecClassname = args[0];
              Class<?> codecClass = Class.forName(codecClassname); // 通过名称找相应的编码/解码器
              Configuration conf = new Configuration();
    CompressionCodec codec = (CompressionCodec) ReflectionUtils.newInstance(codecClass, conf);
     // 通过编码/解码器创建相应的输出流
              CompressionOutputStream out = codec.createOutputStream(System.out);
     // 压缩
              IOUtils.copyBytes(System.in, out, 4096, false);
              out.finish();
         }


    用CompressionCodecFactory方法来判断CompressionCodecs

        

    在阅读一个压缩文件时,我们通常能够从其扩展名来判断出它的编码/解码器。以.gz结尾的文件能够用GzipCodec来阅读。如此类推。每一个压缩格式的扩展名如第一个表格;

    CompressionCodecFactory提供了getCodec()方法。从而将文件扩展名映射到对应的CompressionCodec。

    此方法接受一个Path对象。以下的样例显示了一个应用程序,此程序便使用这个功能来解压缩文件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    public class FileDecompressor {
        public static void main(String[] args) throws Exception {
           String uri = args[0];
           Configuration conf = new Configuration();
           FileSystem fs = FileSystem.get(URI.create(uri), conf);
           Path inputPath = new Path(uri);
           CompressionCodecFactory factory = new CompressionCodecFactory(conf);
           CompressionCodec codec = factory.getCodec(inputPath);
           if (codec == null) {
               System.err.println("No codec found for " + uri);
               System.exit(1);
           }
           String outputUri =
           CompressionCodecFactory.removeSuffix(uri, codec.getDefaultExtension());
           InputStream in null;
           OutputStream out = null;
           try {
               in = codec.createInputStream(fs.open(inputPath));
               out = fs.create(new Path(outputUri));
               IOUtils.copyBytes(in, out, conf);
           } finally {
               IOUtils.closeStream(in);
               IOUtils.closeStream(out);
           }
        }
    }

    编码/解码器一旦找到,就会被用来去掉文件名称后缀生成输出文件名称(通过CompressionCodecFactory的静态方法removeSuffix()来实现)。这样,例如以下调用程序便把一个名为file.gz的文件解压缩为file文件:
    % hadoop FileDecompressor file.gz
    CompressionCodecFactory 从io.compression.codecs配置属性定义的列表中找到编码/解码器。默认情况下。这个列表列出了Hadoop提供的全部编码/解码器 (见表4-3),假设你有一个希望要注冊的编码/解码器(如外部托管的LZO编码/解码器)你能够改变这个列表。每一个编码/解码器知道它的默认文件扩展 名,从而使CompressionCodecFactory能够通过搜索这个列表来找到一个给定的扩展名相匹配的编码/解码器(假设有的话)。
     属性名  类型  默认值  描写叙述
    io.compression.codecs 逗号分隔的类名 org.apache.hadoop.io.compress.DefaultCodec,
    org.apache.hadoop.io.compress.GzipCodec,
    org.apache.hadoop.io.compress.Bzip2Codec
    用于压缩/解压的CompressionCodec列表

     


    本地库

    考虑到性能,最好使用一个本地库(native library)来压缩和解压。

    比如,在一个測试中,使用本地gzip压缩库降低了解压时间50%,压缩时间大约降低了10%(与内置的Java实现相比 较)。表4-4展示了Java和本地提供的每一个压缩格式的实现。井不是全部的格式都有本地实现(比如bzip2压缩)。而还有一些则仅有本地实现(比如 LZO)。

     

    压缩格式 Java实现 本地实现
    DEFLATE
    gzip
    bzip2
    LZO

     

    Hadoop带有预置的32位和64位Linux的本地压缩库,位于库/本地文件夹。对于其它平台,须要自己编译库,详细请參见Hadoop的维基百科http://wiki.apache.org/hadoop/NativeHadoop。

    本地库通过Java系统属性java.library.path来使用。Hadoop的脚本在bin文件夹中已经设置好这个属性。但假设不使用该脚本,则须要在应用中设置属性。

    默认情况下,Hadoop会在它执行的平台上查找本地库,假设发现就自己主动载入。这意味着不必更改不论什么配置设置就能够使用本地库。在某些情况下,可能 希望禁用本地库,比方在调试压缩相关问题的时候。为此。将属性hadoop.native.lib设置为false,就可以确保内置的Java等同内置实现 被使用(假设它们可用的话)。

    CodecPool(压缩解码池)

    假设要用本地库在应用中大量运行压缩解压任务。能够考虑使用CodecPool,从而重用压缩程序和解压缩程序,节约创建这些对象的开销。

    下例所用的API仅仅创建了一个非常easy的压缩程序。因此不必使用这个池。此应用程序使用一个压缩池程序来压缩从标准输入读入然后将其写入标准愉出的数据:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class PooledStreamCompressor 
     {
        public static void main(String[] args) throws Exception 
        {
            String codecClassname = args[0];
            Class<?

    > codecClass = Class.forName(codecClassname);

            Configuration conf = new Configuration();
    CompressionCodec codec = (CompressionCodec) ReflectionUtils.newInstance(codecClass, conf);
            Compressor compressor = null;
            try {
    compressor = CodecPool.getCompressor(codec);//从缓冲池中为指定的CompressionCodec检索到一个Compressor实例
    CompressionOutputStream out = codec.createOutputStream(System.out, compressor);
                IOUtils.copyBytes(System.in, out, 4096, false);
                out.finish();
            } finally
            {
                CodecPool.returnCompressor(compressor);
            }
          }

    我 们从缓冲池中为指定的CompressionCodec检索到一个Compressor实例,codec的重载方法 createOutputStream()中使用的便是它。通过使用finally块,我们便可确保此压缩程序会被返回缓冲池,即使在复制数据流之间的字 节期间抛出了一个IOException。
    压缩和输入切割

    在考虑怎样压缩那些将由MapReduce处理的数据时,考虑压缩格式是否支持切割是非常重要的。考虑存储在HDFS中的未压缩的文件,其大小为1GB. HDFS块的大小为64MB ,所以文件将被存储为16块,将此文件用作输入的MapReduce会创建16个输入分片(split。也称为"分块"),每一个分片都被作为一个独立map任务的输入单独进行处理。

    如今如果,该文件是一个gzip格式的压缩文件,压缩后的大小为1GB。和前面一样。HDFS将此文件存储为 16块。然而,针对每一块创建一个分块是没实用的由于不可能从gzip数据流中的随意点開始读取,map任务也不可能独立于其分块仅仅读取一个分块中的数据。gZlp格式使用DEFLATE来存储压缩过的数据。DEFLATE 将数据作为一系列压缩过的块进行存储。问题是,每块的開始没有指定用户在数据流中随意点定位到下一个块的起始位置,而是其自身与数据流同步。

    因此,gzip

    不支持切割(块)机制。在这样的情况下,MapReduce不切割gzip格式的文件,由于它知道输入的是gzip格式(通过文件扩展名得知),而gzip压缩机制不支持切割机制。这样是以牺牲本地化为代价:一个map任务将处理16个HDFS块,大都不是map的本地数据。与此同一时候,由于map任务少,所以作业切割的粒度不够细,从而导致执行时间变长。


    在我们如果的样例中,如果是一个LZO格式的文件,我们会碰到相同的问题,因为基本压缩格式不为reader 提供方法使其与流同步。

    可是,bzip2格式的压缩文件

    确实提供了块与块之间的同步标记(一个48位的π近似值) 因此它支持切割机制。

    对于文件的收集。这些问题会稍有不同。ZIP是存档格式,因此t能够将多个文件合并为一个ZIP文件。每一个文单独压缩。全部文档的存储位置存储在ZIP文件的尾部。这个属性表明Z l P 文件支持文件边界处切割,每一个分片中包含ZIP压缩文件中的一个或多个文件。

    ZIP格式文件的结构例如以下图:ZIP文件结构请查看wiki



    在MapReduce 中使用压缩

    如前所述,假设输入的文件是压缩过的.那么在被MapReduce 读取时,它们会被自己主动解压。依据文件扩展名来决定应该使用哪一个压缩解码器。假设要压缩MapReduce作业的输出.请在作业配置文件里将mapred.output.compress属性设置为true,将mapred.output.compression.codec属性设置为自己打算使用的压缩编码/解码器的类名。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
        public class MaxTemperatureWithCompression {
     
            public static void main(String[] args) throws Exception {
                if (args.length != 2) {
                    System.err.println("Usage: MaxTemperatureWithCompression <input path> "
                            "<output path>");
                    System.exit(-1);
                }
                Job job = new Job();
                job.setJarByClass(MaxTemperature.class);
                FileInputFormat.addInputPath(job, new Path(args[0]));
                FileOutputFormat.setOutputPath(job, new Path(args[1]));
                job.setOutputKeyClass(Text.class);
                job.setOutputValueClass(IntWritable.class);
                FileOutputFormat.setCompressOutput(job, true);
                FileOutputFormat.setOutputCompressorClass(job, GzipCodec.class);
                job.setMapperClass(MaxTemperatureMapper.class);
                job.setCombinerClass(MaxTemperatureReducer.class);
                job.setReducerClass(MaxTemperatureReducer.class);
                System.exit(job.waitForCompletion(true) ? 0 1);
            }
        }

    我们使用压缩过的输入来执行此应用程序(事实上不必像它一样使用和输入同样的格式压缩输出),例如以下所看到的:
    % hadoop MaxTemperatur eWithCompression input/ ncdc/sample.txt.gz
    output
    量生终输出的每部分都是压缩过的.在本例中。仅仅有一部分:
    % gunzip -c output/part-OOOOO.gz
    1949 111
    1950 22
    假设为输出使用了一系列文件, 能够设置mapred.output.compresson.type 属性来控制压缩类型。默觉得RECORD,它压缩单独的记录。将它改为BLOCK,可以压缩一组记录,因为有更好的压缩比。所以推荐使用。

    map 作业输出结果的压缩
    即使MapReduce 应用使用非压缩的数据来读取和写入,我们也能够受益于压缩map阶段的中阔输出。由于map作业的输出会被写入磁盘并通过网络传输到reducer节点,所以假设使用LZO之类的高速压缩,能得到更好的性能,由于传输的数据量大大降低了.表4-5显示了启用map输出压缩和设置压缩格式的配置属性.

    以下几行代码用于在map 作业中启用gzi p 格式来压缩输出结果:
    1
    2
    3
    4
    5
    Configuration conf = new Configuration();
    conf.setBoolean("mapred.compress.map.output"true);
    conf.setClass("mapred.map.output.compression.codec", GzipCodec.class,
    CompressionCodec.class);
    Job job = new Job(conf);
    旧的API要这样配置
    1
    2
    conf.setCompressMapOutput(true);
    conf.setMapOutputCompressorClass(GzipCodec.class);

    压缩就到此为止了。总之编码和解码在hadoop有着关键的作用。




    Charles 于P.P 



    版权说明:
    本文由Charles Dong原创,本人支持开源以及免费故意的传播。反对商业化谋利。
    CSDN博客:http://blog.csdn.net/mrcharles
    个人站:http://blog.xingbod.cn
    EMAIL:charles@xingbod.cn

    转载于:https://www.cnblogs.com/wzzkaifa/p/7233553.html

    展开全文
  • 经网友反映,还是有些中文会出现解码成乱码,而有些又可以,估计还是guessEncoding方法猜测编码出现了偏差,直接将guessEncoding方法写成返回UTF8就行了。 4.实现图片解码,即把条形码或二维码图片解码成其真实内容...
  • 经网友反映,还是有些中文会出现解码成乱码,而有些又可以,估计还是guessEncoding方法猜测编码出现了偏差,直接将guessEncoding方法写成返回UTF8就行了。 4.实现图片解码,即把条形码或二维码图片解码成其真实内容...
  • 编码方式典型的编解码码流程预测性编码转换编码(有损压缩)熵编码(无损压缩解码 为什么需要编码? 原始视频数据很庞大,比如一个150分钟,30FPS,分辨率为720✖480的彩色电影需要占用280GB。无论物理存储还是...

    视频编解码原理

    为什么需要编码?

    原始视频数据很庞大,比如一个150分钟,30FPS,分辨率为720✖480的彩色电影需要占用280GB。无论是物理存储还是网络传输,这都是难以负担的。所以需要编码进行压缩。

    编码方式

    一般有两种编码方式:熵编码(entropy coding,以无损的方式将视频压缩到香农极限)和有损编码(lossy coding,删除冗余数据和不重要的数据)。熵编码的压缩率是有限的,但是得益于人类的视觉系统可以容忍细节丢失,有损压缩通常很有效。

    典型的编解码码流程

    下图展示了编解码的整体流程。
    摄像头采集到数据,进行编码,传输或者保存编码后的数据,终端拿到数据后进行解码并显示。
    在这里插入图片描述

    下图展示了一个典型的编码流程:
    在这里插入图片描述
    一个典型的视频编码一般由三个模块组成:

    1. 预测性编码(Predictive coding)
    2. 转换编码(Transform coding)
    3. 熵编码(Entropy coding)

    通常编码一个视频会产生若干完整的帧数据和增量帧数据。
    完整帧只需要通过转换编码和熵编码进行压缩。本文主要考虑增量帧的编解码。

    预测性编码

    预测性编码通过利用时间(帧间预测)和空间冗余(帧内预测)来减少视频的冗余度。
    通常预测性编码有两步:运动估计(Motion estimation, ME)和运动补偿(Motion compensation, MC)

    • 运动估计为当前帧的某个区域(A)在参考帧中寻找一个合适的匹配区域(B)。(参考帧可以是之前的帧,也可以是后面的帧)
      在这里插入图片描述
    • 运动补偿找到区域A和区域B的不同
      在这里插入图片描述
      通过ME和MC预测性编码会产生一些运动矢量和残差。运动矢量就是某些区域针对参考帧的运动轨迹,而残差就是这些区域运动后产生的预测帧和当前帧之间的不同。举个不太恰当的例子:(不恰当的地方在于真实的编码中运动矢量涉及的区域不会这么大,比如H.264编码的最大区域为16✖16)
      下象棋时,开局时为参考帧,炮二平五后为当前帧,如图:
      在这里插入图片描述
      这时运动矢量就是炮二的区域移动到炮五的区域,移动后产生一个预测帧。预测帧和当前帧并不完全一样,他们的区别就是残差
      此时的残差则是炮二位置的棋格,以及炮五边框的颜色变化。

    预测性编码的产出就是这些运动矢量和残差,通过这个例子我们能看到这些产出数据是远远小于一个完整帧的数据量的。

    转换编码(有损压缩)

    转换编码模块的产出是一组系数,每个系数是标准基础图案的权重。 通过量化器之后,可获得降低精度但节省位的量化系数。
    反过来标准基础图案使用这些量化系数可以得到量化前的图案。
    例如,1974年开发的离散余弦变换(DCT)是一种广泛使用的变换编码技术。 H.264编码就是将残差通过转换编码转换为DCT系数。
    详细流程就不赘(知)述(道)了。。
    基本原理利用了傅里叶变换思想(使用一些正余弦公式表示图像)
    下面的公式中,y为编码前的图案,x为标准基础图案数据,f(x)是一个公式里面会涉及一组系数k,这一组k就是转换编码的输出。
    yf(x)=k1f1(x)+k2f2(x)+...+knfn(x) y ≈ f(x) = k_1f_1(x) + k_2f_2(x) + ... + k_nf_n(x)
    一个16✖16的图案,大概需要80个系数就足够了,这时的压缩率为31.25%

    熵编码(无损压缩)

    将前面得到的所有数据进行压缩,包括运动矢量、残差的量化系数、还有预测性编码的一些参数。
    常见的熵编码方法包括可变长度编码(VLC),算术编码和霍夫曼编码。
    以大家最熟悉的霍夫曼编码为例,它根据数据出现的频率对数据进行编码,频率高的编码后的长度短,频率低的编码后的长度长。

    解码

    编码流程的逆序就是解码流程。

    解码器拿到编码后的数据后:

    • 根据熵编码的类型,将压缩的数据展开,得到转换编码数据(运动矢量、残差的量化系数、还有预测性编码的一些参数)
    • 根据残差的量化系数,得到残差数据
    • 在参考帧的基础上,实施这些运动矢量,产生预测帧
    • 在预测帧的基础上,叠加残差数据,得到当前帧

    Ref:
    AN OVERVIEW OF EMERGING VIDEO CODING STANDARDS

    展开全文
  • 为什么需要编码? 原始视频数据很庞大,比如一个150分钟,30FPS...熵编码压缩有限的,但是得益于人类的视觉系统可以容忍细节丢失,有损压缩通常很有效。 典型的编解码码流程 下图展示了编解码的整体流程。 摄
  • H.264,同时也MPEG-4第十部分,由ITU-T视频编码专家组(VCEG)和ISO/IEC动态图像专家组(MPEG)联合组成的联合视频组(JVT,Joint Video Team)提出的高度压缩数字视频编解码器标准。 H.264基本概况...
  • 不管 PC 还是移动端,图片一直流量大头,如何保证在图片的精细度不降低的前提下缩小图片体积,成为了一个有价值且值得探索的事情。但如今对于 JPEG、PNG 和 GIF 这些图片格式的优化几乎已经达到了极致,为了...
  • 3.28日:单词的压缩编码 注意:若是图片失效了,并不失效了,因为我用的阿里对象存储,不知道为什么有时候会打不开,但图片还是存在的,你可以右击图片下载下来看。 给定一个单词列表,我们将这个列表编码成一个...
  • 关于AIS编码解码的两个小问题

    千次阅读 2012-06-20 19:26:33
    看了happyparrot的一篇关于AIS解码的文章...1、博文说“编码格式的目的一为了压缩信息内容”不正确的。 这个编码是将原始的每6比特映射到一个特定集合中的某个字符,即变为8了比特,数据
  • H264 无疑目前应用最广泛的编码技术。一些比较优秀的开源库x264/openh264, ffmpeg等让人们处理h264编解码变得相对容易。为了能更好地理解和处理h264问题,还是有必要了解相关的原理 H264压缩技术主要采用了以下几...
  • ambe1000 音频芯片解码压缩分析

    千次阅读 2017-12-29 17:02:30
    帧格式和非帧格式帧格式既适用于串口也适用于并口,...信道接口,表示压缩的数据从编码器出来通过一个接口转到解码器,串口帧格式可以配置时钟信号为输入还是输出,串行输入时钟:在 CHS_I_STRB 有效后,CHS_DI 在 CHS_
  • MPEG在2020年FDIS(标准准备的最后一步...这两个编解码为同一个目的而相互竞争,还是为不同应用场景而设计的? 简单来说,V-PCC和G-PCC针对不同类型的点云设计的:V-PCC用于稠密点云,例如代表自然对象(从一组
  • 哈夫曼树一个二叉树,它通过遍历树的叶子节点实现对相应...当然要解码这些串还是需要一个哈夫曼编码与字符一一对应的表,当我们在一个整体的系统里使用这种技术的时候,我们通过提前建立好一个包括接近全部可能...
  • 网络上还有部分老歌采用Layer2压缩的,但Layer1编码方式的就很难找到了,手头的编码器没有Layer1编码方式,所以这些代码没有经过测试,不详细讲解解码过程了。作为一个完整的MPEG Audio解码器,我还是加入了这部分...
  • protobuf编解码研究

    2020-11-25 17:17:48
    背景 一.优势 1、json: 一般的web项目中,最流行的主要还是json。因为浏览器对于json数据支持非常好,有很多内建的函数支持。...因为profobuf二进制数据格式,需要编码解码。数据本身不具有可读
  • 作者:Rio ... 来源:知乎 著作权归作者所有,转载请联系作者获得授权。 ...先弄清一下基本概念: ...其中「编码」这个概念其实又包含两个方面:编码解码。「视频编码」作为动词指的将动态的图像信息转
  • 从技术上来讲,该编解码的优点还是十分明显的,无损压缩,策略灵活,解码快速,硬件支持等特点都在实际运用中招 招制敌,直击用户的痛点。从开发者的角度来讲,它只支持定点处理--为了确保音质不会在代码解压缩...
  • MPlayer编解码开发指导

    千次阅读 2010-01-05 19:51:00
    一、介绍 不论音频数据还是视频数据,我都为MPlayer项目开发过一些开源的解码器。因此我个人认为我有资格写... 术语介绍:“Codec"表示编码器/解码器(如果你愿意,也可以称为压缩器/解压缩器),它表示一个模块既
  • LZW编解码前言LZW编码1、简介2、原理3、两个问题一、实验内容二、代码实现与分析1、编写函数,获得赫夫曼编码表2、根据赫夫曼编码,将像素数据用编码表示3、将编码后的图片数据写入文件4、读取压缩后的图像文件和...
  • Real9 压缩器 v3.0

    2019-10-29 20:18:58
    Producer Preview v10.0.0.742、有很多兼容问题都出在编码器问题上注意:如果采用只编码音频的方式,程序会自动采用Real10的编码格式,目前的Realone都不支持升级到最新的解码器,如果正常的压缩电影还是采用的...
  • 压缩感知通俗解释

    2017-01-09 15:28:11
    经典的数据压缩技术,无论音频压缩(例如 mp3),图像压缩(例如 jpeg),视频压缩(mpeg),还是一般的编码压缩(zip),都从数据本身的特性出发,寻找并剔除数据中隐含的冗余度,从而达到压缩的目的。...
  • 深度学习之自编码

    2018-07-12 22:15:00
     自编码一种数据的压缩算法,属于无监督学习,以自身X作为输出值,但输出值X‘ 和自身X之间还是有一些差异的。自编码器也一种有损压缩,可以通过使得损失函数最小,来实现X’ 近似于X的值。简单的自编码...
  • G711/G726编解码示例

    千次阅读 2019-12-11 16:37:25
    g711本质还是pcm,不过将16位带符号pcm数据压缩为8位pcm数据。g711a取s16le格式的高13位;g711u则取s16le格式的高14位。实际压缩2:1,具体压缩算法可参考如下博客:...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 137
精华内容 54
关键字:

压缩是编码还是解码