x264代码剖析(二):如何编译运行x264以及x264代码基本框架

x264工程在x265出现之前一直在更新,但是自x264-20091007(含)不再支持VC++平台,也就是说支持VC++平台的x264的最新版本是x264-20091006。接下来就以该版本为例简单介绍如何编译运行x264以及x264代码的基本框架。

首先下载x264-20091006,地址为:http://ftp.videolan.org/pub/videolan/x264/snapshots/,找到对应版本下载后直接解压缩就可以了。

1、编译运行x264

平台:win7 32bit、VS2010;

直接用VS打开“...\x264-091006\build\win32”文件夹下面的对应工程项目即可,由于VS版本与x264版本不一样,所以会自动兼容,全部采用默认兼容即可。编译过程中可能会出现一系列的问题,关于这部分将在后续进行分析解决。

已经解决:见网址:http://blog.csdn.net/frd2009041510/article/details/50822847

2、x264代码基本框架(从源码结构方面)

下面以x264-160228版本为例从源码结构方面分析其代码基本框架。

X264源码文件夹内包括的内容如下图所示:

2.1、encoder

Encoder文件夹内主要包括的内容如下图:

2.2、filters

filters文件夹内主要包括的内容如下图:

其中,video中包括:

2.3、input

input文件夹内主要包括的内容如下图:

2.4、output

output文件夹内主要包括的内容如下图:

2.5、extras

extras文件夹内主要包括的内容如下图:

2.6、doc

doc文件夹内主要包括的内容如下图:

2.7、tools和common

tools和common文件夹内包含内容较多,common文件夹内包含了一些共用的函数,如下图所示:

而tools则包含了常用的工具(个人尚未使用过),如下图所示:

3、x264代码基本框架(从编码结构方面)

下面以x264-160228版本为例从编码结构方面分析其代码基本框架。

主要参考:http://blog.csdn.net/leixiaohua1020/article/details/45536607

3.1、x264命令行程序

x264命令行程序指的是x264项目提供的控制台程序,通过这个程序可以调用libx264编码YUV为H.264码流。x264命令行工具的源码调用关系图如下图所示:

这个流程中最关键的API包括:

x264_param_default():设置参数集结构体x264_param_t的缺省值。

x264_encoder_open():打开编码器。

x264_encoder_headers():输出SPS,PPS,SEI等信息。

x264_encoder_encode():编码输出一帧图像。

x264_encoder_close():关闭编码器。

具体分析如下:

该程序的入口函数为main()。main()函数首先调用parse()解析输入的参数,然后调用encode()编码YUV数据。parse()首先调用x264_param_default()为保存参数的x264_param_t结构体赋默认值;然后在一个大循环中通过getopt_long()解析通过命令行传递来的存储在argv[]中的参数,并作相应的设置工作;最后调用select_input()和select_output()完成输入文件格式(yuv,y4m等)和输出文件格式(裸流,mp4,mkv,FLV等)的设置。encode()首先调用x264_encoder_open()打开编码器;接着在一个循环中反复调用encode_frame()一帧一帧地进行编码;最后在编码完成后调用x264_encoder_close()关闭编码器。encode_frame()则调用x264_encoder_encode()将存储YUV数据的x264_picture_t编码为存储H.264数据的x264_nal_t。

3.2、libx264类库的接口

在一个x264编码流程中,至少需要调用如下API函数:

x264_param_default():设置参数集结构体x264_param_t的缺省值。

x264_picture_alloc():为图像结构体x264_picture_t分配内存。

x264_encoder_open():打开编码器。

x264_encoder_encode():编码一帧图像。

x264_encoder_close():关闭编码器。

x264_picture_clean():释放x264_picture_alloc()申请的资源。

3.3、libx264主干函数

libx264主干函数指的是编码API之后,x264_slice_write()之前的函数,如下图所示。

从图中可以看出,x264主干部分最复杂的函数就是x264_encoder_encode(),该函数完成了编码一帧YUV为H.264码流的工作。与之配合的还有打开编码器的函数x264_encoder_open(),关闭编码器的函数x264_encoder_close(),以及输出SPS/PPS/SEI这样的头信息的x264_encoder_headers()。这一部分函数较多,暂时不详细分析,仅仅举几个例子列一下它们的功能。

3.3.1、x264_encoder_open()

x264_encoder_open()用于打开编码器,其中初始化了libx264编码所需要的各种变量。它调用了下面的函数:

x264_validate_parameters():检查输入参数(例如输入图像的宽高是否为正数)。

x264_predict_16x16_init():初始化Intra16x16帧内预测汇编函数。

x264_predict_4x4_init():初始化Intra4x4帧内预测汇编函数。

x264_pixel_init():初始化像素值计算相关的汇编函数(包括SAD、SATD、SSD等)。

x264_dct_init():初始化DCT变换和DCT反变换相关的汇编函数。

x264_mc_init():初始化运动补偿相关的汇编函数。

x264_quant_init():初始化量化和反量化相关的汇编函数。

x264_deblock_init():初始化去块效应滤波器相关的汇编函数。

x264_lookahead_init():初始化Lookahead相关的变量。

x264_ratecontrol_new():初始化码率控制模块。

3.3.2、x264_encoder_headers()

x264_encoder_headers()输出SPS/PPS/SEI这些H.264码流的头信息。它调用了下面的函数:

x264_sps_write():输出SPS

x264_pps_write():输出PPS

x264_sei_version_write():输出SEI

如下图所示:

3.3.3、x264_encoder_encode()

x264_encoder_encode()编码一帧YUV为H.264码流。它调用了下面的函数:

x264_frame_pop_unused():获取1个x264_frame_t类型结构体fenc。如果frames.unused[]队列不为空,就调用x264_frame_pop()从unused[]队列取1个现成的;否则就调用x264_frame_new()创建一个新的。

x264_frame_copy_picture():将输入的图像数据拷贝至fenc。

x264_lookahead_put_frame():将fenc放入lookahead.next.list[]队列,等待确定帧类型。

x264_lookahead_get_frames():通过lookahead分析帧类型。该函数调用了x264_slicetype_decide(),x264_slicetype_analyse()和x264_slicetype_frame_cost()等函数。经过一些列分析之后,最终确定了帧类型信息,并且将帧放入frames.current[]队列。

x264_frame_shift():从frames.current[]队列取出一帧用于编码。

x264_reference_update():更新参考帧列表。

x264_reference_reset():如果为IDR帧,调用该函数清空参考帧列表。

x264_reference_hierarchy_reset():如果是I(非IDR帧)、P帧、B帧(可做为参考帧),调用该函数。

x264_reference_build_list():创建参考帧列表list0和list1。

x264_ratecontrol_start():开启码率控制。

x264_slice_init():创建 Slice Header。

x264_slices_write():编码数据(最关键的步骤)。其中调用了x264_slice_write()完成了编码的工作(注意“x264_slices_write()”和“x264_slice_write()”名字差了一个“s”)。

x264_encoder_frame_end():编码结束后做一些后续处理,例如释放一些中间变量以及打印输出一些统计信息。其中调用了x264_frame_push_unused()将fenc重新放回frames.unused[]队列,并且调用x264_ratecontrol_end()关闭码率控制。

3.3.4、x264_encoder_close()

x264_encoder_close()用于关闭解码器,同时输出一些统计信息。它调用了下面的函数:

x264_lookahead_delete():释放Lookahead相关的变量。

x264_ratecontrol_summary():汇总码率控制信息。

x264_ratecontrol_delete():关闭码率控制。

3.4、x264_slice_write()

x264_slice_write()是x264项目的核心,它完成了编码了一个Slice的工作。根据功能的不同,该函数可以分为滤波(Filter),分析(Analysis),宏块编码(Encode)和熵编码(Entropy Encoding)几个子模块,如下图所示。

x264_slice_write()用于编码Slice。该函数中包含了一个很长的for()循环。该循环每执行一遍编码一个宏块。x264_slice_write()中以下几个函数比较重要:

x264_nal_start():开始写一个NALU。

x264_macroblock_thread_init():初始化存储宏块的重建数据缓存fdec_buf[]和编码数据缓存fenc_buf[]。

x264_slice_header_write():输出 Slice Header。

x264_fdec_filter_row():滤波模块。该模块包含了环路滤波,半像素插值,SSIM/PSNR的计算。

x264_macroblock_cache_load():将要编码的宏块的周围的宏块的信息读进来。

x264_macroblock_analyse():分析模块。该模块包含了帧内预测模式分析以及帧间运动估计等。

x264_macroblock_encode():宏块编码模块。该模块通过对残差的DCT变换、量化等方式对宏块进行编码。

x264_macroblock_write_cabac():CABAC熵编码模块。

x264_macroblock_write_cavlc():CAVLC熵编码模块。

x264_macroblock_cache_save():保存当前宏块的信息。

x264_ratecontrol_mb():码率控制。

x264_nal_end():结束写一个NALU。

3.5、滤波模块

滤波模块对应的函数是x264_fdec_filter_row()。该函数完成了环路滤波,半像素插值,SSIM/PSNR的计算的功能,如下图所示。

该函数调用了以下几个比较重要的函数:

x264_frame_deblock_row():去块效应滤波器。

x264_frame_filter():半像素插值。

x264_pixel_ssd_wxh():PSNR计算。

x264_pixel_ssim_wxh():SSIM计算。

3.6、分析模块

分析模块对应的函数是x264_macroblock_analyse()。该函数包含了帧内预测模式分析以及帧间运动估计等,如下图所示。

该函数调用了以下比较重要的函数(只列举了几个有代表性的函数):

x264_mb_analyse_init():Analysis模块初始化。

x264_mb_analyse_intra():I宏块帧内预测模式分析。

x264_macroblock_probe_pskip():分析是否是skip模式。

x264_mb_analyse_inter_p16x16():P16x16宏块帧间预测模式分析。

x264_mb_analyse_inter_p8x8():P8x8宏块帧间预测模式分析。

x264_mb_analyse_inter_p16x8():P16x8宏块帧间预测模式分析。

x264_mb_analyse_inter_b16x16():B16x16宏块帧间预测模式分析。

x264_mb_analyse_inter_b8x8():B8x8宏块帧间预测模式分析。

x264_mb_analyse_inter_b16x8():B16x8宏块帧间预测模式分析。

3.7、宏块编码模块

宏块编码模块对应的函数是x264_macroblock_encode()。该模块通过对残差的DCT变换、量化等方式对宏块进行编码。对于Intra16x16宏块,调用x264_mb_encode_i16x16()进行编码,对于Intra4x4,调用x264_mb_encode_i4x4()进行编码。对于Inter类型的宏块则直接在函数体里面编码。

从图中可以看出,宏块编码模块的x264_macroblock_encode()调用了x264_macroblock_encode_internal(),而x264_macroblock_encode_internal()完成了如下功能:

x264_macroblock_encode_skip():编码Skip类型宏块。

x264_mb_encode_i16x16():编码Intra16x16类型的宏块。该函数除了进行DCT变换之外,还对16个小块的DC系数进行了Hadamard变换。

x264_mb_encode_i4x4():编码Intra4x4类型的宏块。

帧间宏块编码:这一部分代码直接写在了函数体里面。

x264_mb_encode_chroma():编码色度块。

3.8、熵编码模块

CABAC熵编码对应的函数是x264_macroblock_write_cabac()。CAVLC熵编码对应的函数是x264_macroblock_write_cavlc(),如下图所示。

x264_macroblock_write_cavlc()调用了以下几个比较重要的函数:

x264_cavlc_mb_header_i():写入I宏块MB Header数据。包含帧内预测模式等。

x264_cavlc_mb_header_p():写入P宏块MB Header数据。包含MVD、参考帧序号等。

x264_cavlc_mb_header_b():写入B宏块MB Header数据。包含MVD、参考帧序号等。

x264_cavlc_qp_delta():写入QP。

x264_cavlc_block_residual():写入残差数据。

3.9、码率控制模块

码率控制模块函数分布在x264源代码不同的地方,包含了以下几个比较重要的函数:

x264_encoder_open()中的x264_ratecontrol_new():创建码率控制。

x264_encoder_encode()中的x264_ratecontrol_start():开始码率控制。

x264_slice_write()中的x264_ratecontrol_mb():码率控制算法。

x264_encoder_encode()中的x264_ratecontrol_end():结束码率控制。

x264_encoder_close()中的x264_ratecontrol_summary():码率控制信息。

x264_encoder_close()中的x264_ratecontrol_delete():释放码率控制。

截止到这儿,x264的基本框架就差不多完全介绍完了,具体的细节性问题以及代码分析将在后续进行不断更新。

(此处要多谢雷神提供众多的资料)

x264代码剖析(二):如何编译运行x264以及x264代码基本框架相关推荐

  1. as 怎么将多个cpp文件代码编译成so_一段C代码,是如何编译运行的?

    想一下, 我们想把源文件放到内存中执行,应该怎么做? 直觉上我们需要将源代码翻译成机器语言,以某种结构组织代码和数据.再让CPU去按这种结构读取指令.如果是多个源文件, 我们可能还需要按某种方式将它们 ...

  2. 下载的c语言程序代码怎么运行,CFree怎么运行程序 编译运行C语言程序代码的方法...

    CFree是一款C语言编译软件,用户可以利用这款软件编译C/C++程序 ,如果你想要运行已经编写好的C语言代码,只需要几个简单的操作即可实现,如果你还不知道怎么运行,就赶快来看看下面的教程吧! 1.首 ...

  3. c语言程序如何运行程序,CFree怎么运行程序 编译运行C语言程序代码的方法

    CFree是一款C语言编译软件,用户可以利用这款软件编译C/C++程序 ,如果你想要运行已经编写好的C语言代码,只需要几个简单的操作即可实现,如果你还不知道怎么运行,就赶快来看看下面的教程吧! 1.首 ...

  4. python代码写好了怎么运行不了-python代码可以直接运行吗 Python写了代码如何运行...

    先下载python,然后打开命令行,输入 python 你的代码文件名. 有python代码怎么编成可执行的exe程序? 如果可以能否帮小编做成可执行的exe程序儿女情长什么的,真的很影响小编行走江湖 ...

  5. vrml行走和静止的人代码_CAE二次开发的核心不是代码

    作者:朱淑强来源:误入CAE的程序员微信公众号(itincae)文末试看<轮胎建模仿真与模态轮胎的生成>课程 所谓的有限元软件的二次开发工作,绝大部分指的是前后处理的二次开发,基本不涉及求 ...

  6. idea(水槽)代码左边栏显示代码行数、方法运行图标、折叠代码块,代码块缩进提示线,idea小技巧

    找了很久才发现的.没问别摸索出来的,搜索不到帖子就自己写一个了. 单独方法块运行挺好用的. 1:代码块折叠:Idea小技巧 之 折叠代码块_我是一个小石头的博客-CSDN博客 2:代码行数显示: 显示 ...

  7. JypyterLab学习之二(JypyterLab编译运行)

    一.git clone代码 git clone XXX 创建环境 conda创建python环境 conda create -n jupyterlab python=3.8 conda activat ...

  8. 硬实时RTLinux安装配置详解 (二):编译运行RTLinux

    硬实时RTlinux系统配置 4. 配置RTLinux 4.1 配置Patch 4.2 配置RTLinux内核 4.3. 编译Rtlinux内核 4.4 制作initramfs启动引导: 5. 大功告 ...

  9. vscode修改c 项目_windows 10上使用vscode编译运行和调试C/C++

    更新于2020/6/30 不值得观看的v1.x版本链接:链接 请不要转载,欢迎点赞,收藏,分享 主要讲如何在vscode上实现编译/运行/调试C以及C++,如果是初学者,就请完全按照文章的步骤进行,如 ...

  10. linux用gcc编译完怎么运行,linux下使用gcc编译运行C/C++程序

    编译C 首先,程序编译过程有: 1.预处理(展开宏,头文件,检查代码是否有误) 2.编译(将.c转为汇编代码.s) 3.汇编(将汇编代码.s转为机器代码.o) 4.链接(将所有机器代码.o和库文件链接 ...

最新文章

  1. Linux守护进程简介
  2. 构建虚拟主机以及访问控制
  3. LogMiner Tool
  4. 数字的空洞 水 南邮NOJ 1071
  5. java sql 联表查询系统_Spring Hibernate JPA 联表查询 复杂查询(转)
  6. kafka数据可靠传输
  7. mipi 屏 通过寄存器调背光
  8. 客户网站被黑导致CDN加速后打开域名就提示域名纠错
  9. 学生信息系统求助_学生管理信息系统_示例
  10. html微博分享功能,js页面文字选中后分享到新浪微博实现
  11. PDFCreator(pdf转换器电脑版免费版)官方繁体中文版V4.3.0 | PDF生成器下载 | pdf转换器哪个好用?
  12. 与矩阵的秩有关的结论
  13. js获取IP地址方法总结
  14. 用友软件用友二次开发用友单据导入用友凭证导入工具用友EXCEL导入工具EXCEL导入凭证
  15. camtasia2018-2019-2020下载安装激活码教程,永久免费版
  16. 高中计算机兴趣班一般学什么内容,高中主要学什么课程 有哪些科目
  17. 令人垂涎的武汉八大名吃
  18. 谷歌云开大会,李飞飞等高管公布多款AI新产品
  19. 美容行业竞争分析:2022年大型美容院成为市场主流
  20. CentOS7救援模式重置root密码

热门文章

  1. IP地址扫描程序/扫描工具
  2. k8s(kubernetes)通过jenkins从harbor拉取镜像,包括yaml传参(史诗级,保姆级)
  3. 【KnewOne Talk】5key:不仅是 Apps 和新奇酷
  4. JavaScript实现的颜色选择器
  5. 北大青鸟深圳嘉华学校分享Hibernate查询
  6. 数据分析中的异常值处理
  7. 滑动拼图验证码 免费 java_js+canvas实现滑动拼图验证码功能
  8. 域前置Cobalt Strike逃避IDS审计
  9. python图片转换成文字_Python输出汉字字库及将文字转换为图片的方法
  10. 如何使计算机理解中医药知识,计算机技术在中医药信息学应用概