存储格式:packed和planar

存储方式差异

音视频都有packed和planar两种存储方式

  • packed方式为多个声道交错存储,比如双声道data[0] = LRLRLR…

  • planar方式为多个声道独立存储,比如双声道data[0] = LLL… data[1] = RRR…

  • 图示yuv444p与yuv444
    对于planar的YUV格式,先连续存储说有像素点的Y,紧接着存储说用像素点的U,随后是所有像素点的V
    image
    对于packed的YUV格式,每个像素点的Y,U,V是连续交错存储的。
    image

数据所在位置

使用packed和planar存储的额数据位于AVFrame结构中,即解码后的数据和编码前的数据。

  • packed格式:frame.data[0]或frame.extended_data[0]包含说有的音频数据
  • planar格式:frame.data[i]活着frame.extended_data[i]表示第i个声道的数据,AVFrame.data的数组大小固定为8,如果声道超过8需要从frame.extended_data获取声道数据

存储方式差异的影响

planar模式ffmepg内部存储模式,但是实际使用的音频文件都是packed模式存储文件。

Planar或者Packed模式直接影响到保存文件时写文件的操作,操作数据的时候一定要先检测音频采样格式。

FFmpeg对存储方式的支持

ffmpeg内部既支持packed模式存储,同时也支持planar存储,部分编码器使用packed模式存储,比如mp3(AV_SAMPLE_FMT_S16),部分使用planar模式存储,比如aac(AV_SAMPLE_FMT_FLTP)。
本地存储pcm数据均使用packed模式。

ffmpeg源码中支持的存储方式包括

enum AVSampleFormat {
    AV_SAMPLE_FMT_NONE = -1,
    // packed存储方式
    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

    // planar存储方式
    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_S64,         ///< signed 64 bits
    AV_SAMPLE_FMT_S64P,        ///< signed 64 bits, planar

    AV_SAMPLE_FMT_NB           ///< Number of sample formats. DO NOT USE if linking dynamically
};

常见编码器定义

每种编码器对应的默认编码存储格式是不同的

  • aac
AVCodec ff_aac_encoder = {
    .name           = "aac",
    .long_name      = NULL_IF_CONFIG_SMALL("AAC (Advanced Audio Coding)"),
    .type           = AVMEDIA_TYPE_AUDIO,
    .id             = AV_CODEC_ID_AAC,
    .priv_data_size = sizeof(AACEncContext),
    .init           = aac_encode_init,
    .encode2        = aac_encode_frame,
    .close          = aac_encode_end,
    .defaults       = aac_encode_defaults,
    .supported_samplerates = mpeg4audio_sample_rates,
    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
    .capabilities   = AV_CODEC_CAP_SMALL_LAST_FRAME | AV_CODEC_CAP_DELAY,
    .sample_fmts    = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP,
                                                     AV_SAMPLE_FMT_NONE },
    .priv_class     = &aacenc_class,
};

  • fdk_aac
AVCodec ff_libfdk_aac_encoder = {
    .name                  = "libfdk_aac",
    .long_name             = NULL_IF_CONFIG_SMALL("Fraunhofer FDK AAC"),
    .type                  = AVMEDIA_TYPE_AUDIO,
    .id                    = AV_CODEC_ID_AAC,
    .priv_data_size        = sizeof(AACContext),
    .init                  = aac_encode_init,
    .encode2               = aac_encode_frame,
    .close                 = aac_encode_close,
    .capabilities          = AV_CODEC_CAP_SMALL_LAST_FRAME | AV_CODEC_CAP_DELAY,
    .sample_fmts           = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
                                                            AV_SAMPLE_FMT_NONE },
    .priv_class            = &aac_enc_class,
    .defaults              = aac_encode_defaults,
    .profiles              = profiles,
    .supported_samplerates = aac_sample_rates,
    .channel_layouts       = aac_channel_layout,
    .wrapper_name          = "libfdk",
};

  • mp3lamp
AVCodec ff_libmp3lame_encoder = {
    .name                  = "libmp3lame",
    .long_name             = NULL_IF_CONFIG_SMALL("libmp3lame MP3 (MPEG audio layer 3)"),
    .type                  = AVMEDIA_TYPE_AUDIO,
    .id                    = AV_CODEC_ID_MP3,
    .priv_data_size        = sizeof(LAMEContext),
    .init                  = mp3lame_encode_init,
    .encode2               = mp3lame_encode_frame,
    .close                 = mp3lame_encode_close,
    .capabilities          = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SMALL_LAST_FRAME,
    .sample_fmts           = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P,
                                                             AV_SAMPLE_FMT_FLTP,
                                                             AV_SAMPLE_FMT_S16P,
                                                             AV_SAMPLE_FMT_NONE },
    .supported_samplerates = libmp3lame_sample_rates,
    .channel_layouts       = (const uint64_t[]) { AV_CH_LAYOUT_MONO,
                                                  AV_CH_LAYOUT_STEREO,
                                                  0 },
    .priv_class            = &libmp3lame_class,
    .defaults              = libmp3lame_defaults,
    .wrapper_name          = "libmp3lame",
};
  • flac
AVCodec ff_flac_encoder = {
    .name           = "flac",
    .long_name      = NULL_IF_CONFIG_SMALL("FLAC (Free Lossless Audio Codec)"),
    .type           = AVMEDIA_TYPE_AUDIO,
    .id             = AV_CODEC_ID_FLAC,
    .priv_data_size = sizeof(FlacEncodeContext),
    .init           = flac_encode_init,
    .encode2        = flac_encode_frame,
    .close          = flac_encode_close,
    .capabilities   = AV_CODEC_CAP_SMALL_LAST_FRAME | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_LOSSLESS,
    .sample_fmts    = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
                                                     AV_SAMPLE_FMT_S32,
                                                     AV_SAMPLE_FMT_NONE },
    .priv_class     = &flac_encoder_class,
};

posted @ 2021-12-07 23:17  flxx  阅读(1207)  评论(0编辑  收藏  举报