问题
当我将一个aac的音频文件解码为原始的PCM数据后,使用ffplay播放测试是否成功时,需要提供给ffplay 采样率,通道数,PCM的格式类型 3个参数,否则无法播放!
所以使用ffprobe 查看原来的aac文件信息,这里我们可以看到采样率为 44100Hz, 通道为stereo表示双通道,后面跟着一个 fltp,这是个什么格式呢?
我们先看一下ffmpeg支持那些PCM格式,使用下面的命名查看
ffmpeg -formats | findstr PCM
可以看到PCM的格式还是很多,具体我们选择哪一种呢?总不能一个个的试吧!
le --- 小端模式 be --- 大端模式
答案
答案就在ffmpeg源码中,首先我们看下关于采样格式的定义,它定义在FFmpeg/libavutil/samplefmt.h文件中。根据位深度,是否有符号,打包类型,定义了12种类型,AV_SAMPLE_FMT_NONE表示未知类型,最后的AV_SAMPLE_FMT_NB表示样本格式个数为12个。
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_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
};
而我们在命令行看到是fltp跟它有什么关系呢?具体对照表如下,定义在FFmpeg/libavutil/samplefmt.c文件中
typedef struct SampleFmtInfo {
char name[8];
int bits;
int planar;
enum AVSampleFormat altform; ///< planar<->packed alternative form
} SampleFmtInfo;
/** this table gives more information about formats */
static const SampleFmtInfo sample_fmt_info[AV_SAMPLE_FMT_NB] = {
[AV_SAMPLE_FMT_U8] = { .name = "u8", .bits = 8, .planar = 0, .altform = AV_SAMPLE_FMT_U8P },
[AV_SAMPLE_FMT_S16] = { .name = "s16", .bits = 16, .planar = 0, .altform = AV_SAMPLE_FMT_S16P },
[AV_SAMPLE_FMT_S32] = { .name = "s32", .bits = 32, .planar = 0, .altform = AV_SAMPLE_FMT_S32P },
[AV_SAMPLE_FMT_S64] = { .name = "s64", .bits = 64, .planar = 0, .altform = AV_SAMPLE_FMT_S64P },
[AV_SAMPLE_FMT_FLT] = { .name = "flt", .bits = 32, .planar = 0, .altform = AV_SAMPLE_FMT_FLTP },
[AV_SAMPLE_FMT_DBL] = { .name = "dbl", .bits = 64, .planar = 0, .altform = AV_SAMPLE_FMT_DBLP },
[AV_SAMPLE_FMT_U8P] = { .name = "u8p", .bits = 8, .planar = 1, .altform = AV_SAMPLE_FMT_U8 },
[AV_SAMPLE_FMT_S16P] = { .name = "s16p", .bits = 16, .planar = 1, .altform = AV_SAMPLE_FMT_S16 },
[AV_SAMPLE_FMT_S32P] = { .name = "s32p", .bits = 32, .planar = 1, .altform = AV_SAMPLE_FMT_S32 },
[AV_SAMPLE_FMT_S64P] = { .name = "s64p", .bits = 64, .planar = 1, .altform = AV_SAMPLE_FMT_S64 },
[AV_SAMPLE_FMT_FLTP] = { .name = "fltp", .bits = 32, .planar = 1, .altform = AV_SAMPLE_FMT_FLT },
[AV_SAMPLE_FMT_DBLP] = { .name = "dblp", .bits = 64, .planar = 1, .altform = AV_SAMPLE_FMT_DBL },
};
这里我们看到fltp表示的格式是AV_SAMPLE_FMT_FLTP,位深32位,数据存储方式位planar,与之相反的packed格式为AV_SAMPLE_FMT_FLT。
好了我们已经知道fltp表示的是float 32位数据,我们再结合前面的PCM的格式数据,再根据我们的电脑的大小端类型知道,我们需要传递的参数是应该就是 f32le
好了,我们使用ffplay 播放试试看
ffplay -ar 44100 -ac 2 -f f32le -i audio.pcm
结果如下,完美播放:
备注
这里有一个planar,之前有一篇关于视频的采样格式的文章,这里我们需要注意的是音频样本的内存
存储方式。
planar --- 每个音频通道(channel )一个平面,例如双通道data[0] = LLL..., data[1] = RRR...
linesize表示单个plane的buffer size(以字节为单位)
packed --- 不管几个音频通道都只是用一个平面,数据交错存储,data[0] = LRLRLR...
linesize表示单个plane的buffer size(以字节为单位)
其他
查看aac解码器信息
ffmpeg -h decoder=aac