AVFrame关于视音频数据存储

1、概述

这几天用ffmpeg实现简单音频转码,在写程序的过程中发现音频在AVFrame中存储与视频很相似,音频要复杂一些,本人记性不好,所以在这里记录下来,以作备忘。

2、2个数据成员

在AVFrame中有2个很重要的数据成员,一个是data,一个是linesize。data中存储的是未编码的源始数据(不论视音频),linesize中存储的是每行data中数据大小。
data的定义如下:
/**
     * pointer to the picture/channel planes.
     * This might be different from the first allocated byte
     *
     * Some decoders access areas outside 0,0 - width,height, please
     * see avcodec_align_dimensions2(). Some filters and swscale can read
     * up to 16 bytes beyond the planes, if these filters are to be used,
     * then 16 extra bytes must be allocated.
     */
    uint8_t *data[AV_NUM_DATA_POINTERS];
linesize定义如下:
  /**
     * For video, size in bytes of each picture line.
     * For audio, size in bytes of each plane.
     *
     * For audio, only linesize[0] may be set. For planar audio, each channel
     * plane must be the same size.
     *
     * For video the linesizes should be multiplies of the CPUs alignment
     * preference, this is 16 or 32 for modern desktop CPUs.
     * Some code requires such alignment other code can be slower without
     * correct alignment, for yet other it makes no difference.
     *
     * @note The linesize may be larger than the size of usable data -- there
     * may be extra padding present for performance reasons.
     */
    int linesize[AV_NUM_DATA_POINTERS];
注意:当为音频的时候linesize,只有linesize[0]才是有效值,因为左右一样大。

3、存储方式

1、视频
视频相对简单的多,以yuv420为例,图像数据在AVFrame中存储是这样的:
data[0]存储Y
data[1 ]存储U
data[2 ]存储V
而他们相对应的大小为:
linesize[0]为Y的大小
linesize[1]为U的大小
linesize[2]为V的大小

2、音频
音频数据则要复杂一些,在音频中分为平面和非平面数据类型,下面是音频数据类型的定义:
/**
 * Audio Sample Formats
 *
 * @par
 * The data described by the sample format is always in native-endian order.
 * Sample values can be expressed by native C types, hence the lack of a signed
 * 24-bit sample format even though it is a common raw audio data format.
 *
 * @par
 * The floating-point formats are based on full volume being in the range
 * [-1.0, 1.0]. Any values outside this range are beyond full volume level.
 *
 * @par
 * The data layout as used in av_samples_fill_arrays() and elsewhere in FFmpeg
 * (such as AVFrame in libavcodec) is as follows:
 *
 * For planar sample formats, each audio channel is in a separate data plane,
 * and linesize is the buffer size, in bytes, for a single plane. All data
 * planes must be the same size. For packed sample formats, only the first data
 * plane is used, and samples for each channel are interleaved. In this case,
 * linesize is the buffer size, in bytes, for the 1 plane.
 */
enum AVSampleFormat {
    AV_SAMPLE_FMT_NONE = -1,
    AV_SAMPLE_FMT_U8,          ///< unsigned 8 bits
    AV_SAMPLE_FMT_S16,         ///< signed 16 bits
    AV_SAMPLE_FMT_S32,         ///< signed 32 bits
    AV_SAMPLE_FMT_FLT,         ///< float
    AV_SAMPLE_FMT_DBL,         ///< double

    AV_SAMPLE_FMT_U8P,         ///< unsigned 8 bits, planar
    AV_SAMPLE_FMT_S16P,        ///< signed 16 bits, planar
    AV_SAMPLE_FMT_S32P,        ///< signed 32 bits, planar
    AV_SAMPLE_FMT_FLTP,        ///< float, planar
    AV_SAMPLE_FMT_DBLP,        ///< double, planar

    AV_SAMPLE_FMT_NB           ///< Number of sample formats. DO NOT USE if linking dynamically
};
定义中最后带p的为平面数据类型,可以用av_sample_fmt_is_planar来判断此数据类型是否是平面数据类型。
先说非平面数据:
以一个双声道(左右)音频来说,存储格式可能就为LRLRLR.........(左声道在前还是右声道在前没有认真研究过),数据都装在data[0]中,而大小则为linesize[0]。
平面数据:
就有点像视频部分的YUV数据,同样对双声道音频PCM数据,以S16P为例,存储就可能是
plane 0: LLLLLLLLLLLLLLLLLLLLLLLLLL...
plane 1: RRRRRRRRRRRRRRRRRRRR
....
对应的存储则为:
data[0]存储plane 0
data[1]存储plane 1
对应的大小则都为linesize[0],可以用av_get_bytes_per_sample(out_stream->codec->sample_fmt) * out_frame->nb_samples来算出plane的大小。



















  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要将AVFrame中的音频数据保存为PCM格式的音频文件,可以按照以下步骤进行: 1. 打开PCM文件,获取文件指针。 2. 根据AVFrame中的采样格式、采样率和通道数,计算每个样本所占的字节数,以及每个AVFrame包含的样本数。 3. 遍历AVFrame中的每个音频数据指针,将其写入PCM文件中。 4. 关闭PCM文件。 下面是一个简单的示例代码,假设AVFrame中的音频数据已经存储data[0]中,采样格式为AV_SAMPLE_FMT_S16,采样率为44100,通道数为2: ```c // 打开PCM文件 FILE* fp_pcm = fopen("audio.pcm", "wb"); if (fp_pcm == NULL) { printf("Open PCM file failed.\n"); return -1; } // 计算每个样本所占的字节数 int sample_size = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16); // 计算每个AVFrame包含的样本数 int samples_per_frame = av_frame_get_best_effort_samples(frame, 0); // 遍历AVFrame中的音频数据指针,写入PCM文件中 int i; for (i = 0; i < samples_per_frame; i++) { fwrite(frame->data[0] + i * sample_size * 2, 1, sample_size * 2, fp_pcm); } // 关闭PCM文件 fclose(fp_pcm); ``` 这段代码将AVFrame中的音频数据写入到名为audio.pcm的PCM文件中。其中,av_get_bytes_per_sample函数用于计算每个样本所占的字节数,av_frame_get_best_effort_samples函数用于获取每个AVFrame包含的样本数。在遍历AVFrame中的音频数据指针时,需要注意每个样本所占的字节数为sample_size * 2,因为本例中采用了16位的采样格式,即每个样本占用2个字节。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dancing_night

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值