音视频从入门到精通——FFmpeg之av_image_get_buffer_size函数

Posted 怪我冷i

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了音视频从入门到精通——FFmpeg之av_image_get_buffer_size函数相关的知识,希望对你有一定的参考价值。

文章目录

FFmpeg之av_image_get_buffer_size函数

/**
 * Return the size in bytes of the amount of data required to store an
 * image with the given parameters.
 * 返回使用给定参数存储图像所需数据量的字节大小
 *
 * @param pix_fmt  the pixel format of the image 图像的像素格式
 * @param width    the width of the image in pixels 以像素为单位的图像宽度
 * @param height   the height of the image in pixels 图像的高度(像素)
 * @param align    the assumed linesize alignment 假定的线宽对齐
 * @return the buffer size in bytes, a negative error code in case of failure
 * 缓冲区大小(以字节为单位),出现故障时为负错误代码
 */
int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align);

函数的作用是通过指定像素格式、图像宽、图像高来计算所需的内存大小

重点说明一个参数align:此参数是设定内存对齐的对齐数,也就是按多大的字节进行内存对齐。比如设置为1,表示按1字节对齐,那么得到的结果就是与实际的内存大小一样。再比如设置为4,表示按4字节对齐。也就是内存的起始地址必须是4的整倍数。

ffmpeg的ffmpeg中的align

ffmpeg之所以给了这个参数让⼈设置,应该就是为了兼容各个硬件平台,因为不是所有的硬件平台都能访 问任意地址上的任意数据的, 某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常

以ffmpeg的av_image_get_buffer_size为例,你能准确说出下⾯的结果吗,如果可以,那么证明你确实 理解了ffmpeg中的对⻬了。

值得注意的是yuv的计算,以w*h的yuv420p为例,
他是分三个平⾯存储三个分量的,⽽u和v的计算是⼀致 的,
也就是说计算出了u即可得到v;
对于y来说,它有w⾏h列,因此需要计算w⾏的对⻬后字节数再乘以h;
对于u来说,它有w/2h/2列(这是因为每4个y共享⼀组uv),
因此需要计算w/2⾏的对⻬后字节数再乘以 h/2
v的计算与u的⼀模⼀样,最后将这个三个数相加即可

例如310的图⽚,每个像素点占2个字节,对⻬数align为4,那么⾏数是多少呢,从条件可知,每⾏3 个像素点,每个像素点占2字节,那么每⾏就是6字节,⽽对⻬数是4,6不是4的整数倍,因此6需要补 2个字节凑成8,8就是4的整数倍了,那么我们就知道每⾏在内存中实际占⽤了8个字节,后两个字节是 为了对⻬补上的,总共有10⾏,那么这张图⽚在实际内存中就占⽤了810=80个字节,⽽不是60个字 节了

本来这张图⽚只需要60个字节,为何要⽤80个字节来存储呢,这是因为cpu并不能从任意地址开始读 取数据,如果不对⻬,那么可能需要多次读取才能读到完整数据,因此对⻬主要是为了提升性能,典型的空间换取时间

ffmpeg的linesize

linesize其实就是我们上⽂提及到的⾏字节数,在我们解码出数据后,经常会遇到这个linesize,既然我们知 道了align的概念,就该明⽩这个linesize就是为了让你取出真实的数据的 解码后的数据中可能是经过对⻬的,既然有对⻬,那就是数据⾥加多了⼀些为了对⻬⽽多余的字节,如果 我们想最后显示视频数据,那么这些多余的数据势必要进⾏剔除掉,那么怎么剔除呢,linesize就是来帮你 ⼲这事的,有了它,你就可以一行一行⽐较,然后把每⾏最后为了对⻬⽽补的字节删除,还原出视频的真 实数据

av_image_alloc函数

/**
 * Allocate an image with size w and h and pixel format pix_fmt, and
 * fill pointers and linesizes accordingly.
 * 分配具有大小w和h以及像素格式pix_fmt的图像,并相应地填充指针和线条大小
 * 
 * The allocated image buffer has to be freed by using
 * av_freep(&pointers[0]).
 * 必须释放分配的图像缓冲区使用av_freep
 *
 * @param align the value to use for buffer size alignment 
 * 用于缓冲区大小对齐的值
 * 
 * @return the size in bytes required for the image buffer, a negative
 * error code in case of failure
 * 图像缓冲区所需的字节大小,出现故障时为负错误代码
 */
int av_image_alloc(uint8_t *pointers[4], int linesizes[4],
                   int w, int h, enum AVPixelFormat pix_fmt, int align);

av_image_fill_arrays函数

/**
  Setup the data pointers and linesizes based on the specified image
  parameters and the provided array.
  根据指定的图像参数和提供的数组设置数据指针和行大小
 
  The fields of the given image are filled in by using the src
  address which points to the image data buffer. Depending on the
  specified pixel format, one or multiple image data pointers and
  line sizes will be set.  If a planar format is specified, several
  pointers will be set pointing to the different picture planes and
  the line sizes of the different planes will be stored in the
  lines_sizes array. Call with src == NULL to get the required
  size for the src buffer.

给定图像的字段是使用指向图像数据缓冲区的src地址填充的。
根据指定的像素格式,将设置一个或多个图像数据指针和线条大小。
如果指定了平面格式,将设置多个指向不同图片平面的指针,
不同平面的线条大小将存储在lines_sizes数组中。
使用src==NULL调用以获取src缓冲区所需的大小
 
 
  To allocate the buffer and fill in the dst_data and dst_linesize in
  one call, use av_image_alloc().
要在一次调用中分配缓冲区并填写dst_data和dst_linesize,请使用av_image_alloc
 
  @param dst_data      data pointers to be filled in
  @param dst_linesize  linesizes for the image in dst_data to be filled in
  @param src           buffer which will contain or contains the actual image data, can be NULL
  @param pix_fmt       the pixel format of the image
  @param width         the width of the image in pixels
  @param height        the height of the image in pixels
  @param align         the value used in src for linesize alignment
  @return the size in bytes required for src, a negative error code
  in case of failure
 */
int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4],
                         const uint8_t *src,
                         enum AVPixelFormat pix_fmt, int width, int height, int align);

通过以上实例可以看到,
(a)计算所需内存大小av_image_get_bufferz_size()
(b) 按计算的内存大小申请所需内存 av_malloc()
(c) 对申请的内存进行格式化 av_image_fill_arrays()

参考

av_image_get_buffer_size
FFmpeg简单分析系列----内存对齐简要说明

DAX从入门到精通 5-1 理解calculate

参考技术A 这个章节我们继续学习DAX语言,详细的介绍一个函数:calculate。这里介绍的方法也适用于calculatetable,它返回一个表而不是一个值。为了简化,我们以calculate函数为案例学习。

你可能会好奇,我们为什么要用一整个章节来介绍一个韩少,但是这个是非常有必要的,因为这个函数的应用场景非常广。calculate是目前DAX语言中最重要,最复杂的函数。函数本身很简单,只有几个参数,但是calculate的使用场景之广,写法之复杂,让我们值得使用一整个章节来学习整个函数。

像之前章节介绍的一样,我们强烈建议你熟悉了calculate函数之后,再继续接下去阅读书的剩下部分。然后,只要你对某函数感到奇怪,计算结果和你设想的不同,返回该章节,重新读一遍。你可能就会发现一些你曾经不曾学到的新知识。

学习这个章节,我们需要有一些耐心,如果有的章节你看的很晦涩难以理解,请沉下心,细细的理解,确定你的确是理解了。

之前我们学过,有两种上下文:行上下文和筛选上下文。另外我们也学了我们可以使用迭代函数创建行上下文,还有使用all函数可以忽略筛选上下文。值得注意的是,all函数是忽略了筛选上下文,而不是改变它。因此,下面的函数:

all函数忽略了筛选上下文,并且返回整个表,但是它没有改变函数其他部分的上下文环境。事实上,表达式的最内部,average根据当前的筛选上下文会计算MarginPct列的平均值。DAX中有个函数可以改变筛选上下文——calculate。

学习calculate函数,我们来看一个场景。设想一下我们要建立一个如下的报表,包含了category,subcategory,还有sum_of_sales_amount

整个报表显示了每行相对于总计的百分比。我们可以使用Excel透视表功能轻易的建立这样的报表,但是我们现在要把整个百分比建立为一个度量值,以便使用者可以根据需要直接的使用。

分子是sum of salesamount,分母忽略了筛选上下文,总是返回总计值,无论你选择了什么。这个函数如果你不选择任何切片器,那么这个函数是正确的。但是,如果你在切片器选择了black,然后值就会错误了。百分比是18.76而不是100%,因为计算总的分母是一个更大的值。如下图:

这里的问题很好理解,我们使用了all函数,all函数忽略了筛选上下文,因此,无论你选择什么,分母总是sales表的总计值,如果你想只保留对color的筛选器,只清除category和subcategory的筛选器,all函数和迭代器函数都不是正确的选择,你需要一个更强大功能的函数,也就是calculate函数。

以上是关于音视频从入门到精通——FFmpeg之av_image_get_buffer_size函数的主要内容,如果未能解决你的问题,请参考以下文章

FFmpeg从入门到精通-云享读书会

FFmpeg从入门到精通-云享读书会

FFmpeg从入门到精通——进阶篇,SEI那些事儿

FFmpeg从入门到精通——进阶篇,SEI那些事儿

PowerBI入门到精通之入门

Hadoop从入门到精通33:MapReduce核心原理之Shuffle过程分析