自己在学习h264的路上,欢迎讨论交流。
前段时间研究JM出品的h264编码器,代码实在看不下去,因此换了个角度来研究诸多算法——逆向方式(解码),本系列文章记录一些遇到的东西和思考。
1. JM介绍
JM编解码器,是一个纯软件编解码器,由位于德国的海因里希赫兹研究所(Heinrich Hertz Institute)推出,是h264官方推荐的用于研究avc算法的软件。
2. JM & x264
JM但其未做太多优化,速度较慢,用于科研需求。x264则是JM的升级版,编码速度较快,广泛应用于企业,例如网上下载的视频,(目前的时间节点)毫不夸张地说,50%以上都是由x264压制而来。
抄一段网上的对比:
1,X264简化了JM的代价(或者叫成本)计算方法,去掉了一些代码,进行了估算。
2,JM中是要把编码后的比特数进行加权运算后作为代价的一部分进行比较的,X264把这个部分的代码删除了,即没有把编码后的比特数作为代价的一部分。
3,X264进行了SSE2,MMX的优化。
4,X264对JM的数据结构部分进行了优化,以加快内存的数据读取速度。
5,由于JM不断地升级。JM代码里面有了很多的快速算法,包括快速搜索算法。X264则没有这些快速算法。(网上抄来的,这条明显说颠倒了)
3. 使用哪个版本?
jm8.6版本是最经典的版本,网上资料较齐全,建议下载该版本。
读者可自行去官网下载代码,来编译和运行。该软件同时支持Win和Linux平台下构建,下载的代码中已经建了vc工程,也包括Makefile。
JM目录结构如下:
1 $ tree 2 . 3 |-- CHANGES.TXT 4 |-- Changes_detail.txt 5 |-- Readme.txt 6 |-- bin 7 | |-- decoder.cfg 8 | |-- encoder_baseline.cfg 9 | |-- encoder_extended.cfg 10 | |-- encoder_main.cfg 11 | |-- foreman_part_qcif.yuv 12 | |-- leakybucketrate.cfg 13 | |-- sg0conf.cfg 14 | |-- sg2conf.cfg 15 | `-- sg6conf.cfg 16 |-- copyright.txt 17 |-- disclaimer.txt 18 |-- doc 19 | |-- coding_style.doc 20 | |-- doxygen.txt 21 | |-- foot.html 22 | |-- h26l.css 23 | |-- ldecod.dox 24 | `-- lencod.dox 25 |-- ldecod 26 | |-- Makefile 27 | |-- inc 28 | | |-- annexb.h 29 | | |-- biaridecod.h 30 | | |-- block.h 31 | | |-- cabac.h 32 | | |-- context_ini.h 33 | | |-- contributors.h 34 | | |-- ctx_tables.h 35 | | |-- defines.h 36 | | |-- elements.h 37 | | |-- erc_api.h 38 | | |-- erc_do.h 39 | | |-- erc_globals.h 40 | | |-- errorconcealment.h 41 | | |-- fmo.h 42 | | |-- global.h 43 | | |-- header.h 44 | | |-- image.h 45 | | |-- leaky_bucket.h 46 | | |-- loopfilter.h 47 | | |-- macroblock.h 48 | | |-- mb_access.h 49 | | |-- mbuffer.h 50 | | |-- memalloc.h 51 | | |-- nalu.h 52 | | |-- nalucommon.h 53 | | |-- output.h 54 | | |-- parset.h 55 | | |-- parsetcommon.h 56 | | |-- rtp.h 57 | | |-- sei.h 58 | | `-- vlc.h 59 | `-- src 60 | |-- annexb.c 61 | |-- biaridecod.c 62 | |-- block.c 63 | |-- cabac.c 64 | |-- context_ini.c 65 | |-- erc_api.c 66 | |-- erc_do_i.c 67 | |-- erc_do_p.c 68 | |-- errorconcealment.c 69 | |-- filehandle.c 70 | |-- fmo.c 71 | |-- header.c 72 | |-- image.c 73 | |-- ldecod.c 74 | |-- leaky_bucket.c 75 | |-- loopFilter.c 76 | |-- macroblock.c 77 | |-- mb_access.c 78 | |-- mbuffer.c 79 | |-- memalloc.c 80 | |-- nal.c 81 | |-- nal_part.c 82 | |-- nalu.c 83 | |-- nalucommon.c 84 | |-- output.c 85 | |-- parset.c 86 | |-- parsetcommon.c 87 | |-- rtp.c 88 | |-- sei.c 89 | `-- vlc.c 90 |-- ldecod.dsp 91 |-- ldecod.dsw 92 |-- ldecod.vcproj 93 |-- lencod 94 | |-- Makefile 95 | |-- inc 96 | | |-- annexb.h 97 | | |-- biariencode.h 98 | | |-- block.h 99 | | |-- cabac.h 100 | | |-- configfile.h 101 | | |-- context_ini.h 102 | | |-- contributors.h 103 | | |-- ctx_tables.h 104 | | |-- defines.h 105 | | |-- elements.h 106 | | |-- fast_me.h 107 | | |-- fmo.h 108 | | |-- global.h 109 | | |-- header.h 110 | | |-- image.h 111 | | |-- intrarefresh.h 112 | | |-- leaky_bucket.h 113 | | |-- macroblock.h 114 | | |-- mb_access.h 115 | | |-- mbuffer.h 116 | | |-- memalloc.h 117 | | |-- minmax.h 118 | | |-- mv-search.h 119 | | |-- nalu.h 120 | | |-- nalucommon.h 121 | | |-- output.h 122 | | |-- parset.h 123 | | |-- parsetcommon.h 124 | | |-- ratectl.h 125 | | |-- rdopt_coding_state.h 126 | | |-- refbuf.h 127 | | |-- rtp.h 128 | | |-- sei.h 129 | | `-- vlc.h 130 | `-- src 131 | |-- annexb.c 132 | |-- biariencode.c 133 | |-- block.c 134 | |-- cabac.c 135 | |-- configfile.c 136 | |-- context_ini.c 137 | |-- decoder.c 138 | |-- fast_me.c 139 | |-- filehandle.c 140 | |-- fmo.c 141 | |-- header.c 142 | |-- image.c 143 | |-- intrarefresh.c 144 | |-- leaky_bucket.c 145 | |-- lencod.c 146 | |-- loopFilter.c 147 | |-- macroblock.c 148 | |-- mb_access.c 149 | |-- mbuffer.c 150 | |-- memalloc.c 151 | |-- mv-search.c 152 | |-- nal.c 153 | |-- nalu.c 154 | |-- nalucommon.c 155 | |-- output.c 156 | |-- parset.c 157 | |-- parsetcommon.c 158 | |-- ratectl.c 159 | |-- rdopt.c 160 | |-- rdopt_coding_state.c 161 | |-- refbuf.c 162 | |-- rtp.c 163 | |-- sei.c 164 | |-- slice.c 165 | |-- vlc.c 166 | `-- weighted_prediction.c 167 |-- lencod.dsp 168 |-- lencod.dsw 169 |-- lencod.vcproj 170 |-- rtpdump 171 | |-- ReadMe.txt 172 | |-- StdAfx.cpp 173 | |-- StdAfx.h 174 | |-- rtpdump.cpp 175 | `-- rtpdump.dsp 176 |-- tml.dsw 177 |-- tml.sln 178 `-- unixprep.sh 179 180 9 directories, 167 files
4. 构建、运行流程
本人在Win10+mingw环境做开发验证,此外还需将一些编译工具链(gcc/ld等gcc家族产品)准备好,才能使用Makefile。
1. 进入ldecod目录,执行make,即可编译出解码器,最终会将可执行文件ldecod.exe拷贝到根目录下的bin文件夹中。(可能会遇到几个预处理错误问题,是关于不同平台下最大值的定义)
2.与上面类似,进入lencod目录,构建出编码器。
3.进入bin目录,执行命令:
./ldecod.exe decoder.cfg
其中,decoder.cfg指定了裸码流路径(不能是mp4等带文件容器格式的文件,必须是NALU形式的裸数据——可由ffmpeg提取出来)、解码后yuv文件输出路径等参数。