存储方式差异
音视频都有packed和planar两种存储方式
- packed方式为多个声道交错存储,比如双声道data[0] = LRLRLR…
- planar方式为多个声道独立存储,比如双声道data[0] = LLL… data[1] = RRR…
数据所在位置
使用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支持的存储方式包括
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,
};