> 文章列表 > FFMPEG 关于smaple_fmts的理解及ffplay播放PCM

FFMPEG 关于smaple_fmts的理解及ffplay播放PCM

FFMPEG 关于smaple_fmts的理解及ffplay播放PCM

 问题

当我将一个aac的音频文件解码为原始的PCM数据后,使用ffplay播放测试是否成功时,需要提供给ffplay 采样率,通道数,PCM的格式类型 3个参数,否则无法播放!

所以使用ffprobe 查看原来的aac文件信息,这里我们可以看到采样率为 44100Hz, 通道为stereo表示双通道,后面跟着一个 fltp,这是个什么格式呢?

我们先看一下ffmpeg支持那些PCM格式,使用下面的命名查看

ffmpeg -formats | findstr PCM

可以看到PCM的格式还是很多,具体我们选择哪一种呢?总不能一个个的试吧! 

le --- 小端模式   be --- 大端模式  

答案

我们先在在ffmpeg源码中,首先我们看下在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 bitsAV_SAMPLE_FMT_S16,         ///< signed 16 bitsAV_SAMPLE_FMT_S32,         ///< signed 32 bitsAV_SAMPLE_FMT_FLT,         ///< floatAV_SAMPLE_FMT_DBL,         ///< doubleAV_SAMPLE_FMT_U8P,         ///< unsigned 8 bits, planarAV_SAMPLE_FMT_S16P,        ///< signed 16 bits, planarAV_SAMPLE_FMT_S32P,        ///< signed 32 bits, planarAV_SAMPLE_FMT_FLTP,        ///< float, planarAV_SAMPLE_FMT_DBLP,        ///< double, planarAV_SAMPLE_FMT_S64,         ///< signed 64 bitsAV_SAMPLE_FMT_S64P,        ///< signed 64 bits, planarAV_SAMPLE_FMT_NB           ///< Number of sample formats. DO NOT USE if linking dynamically
};

上面是程序内部使用的,而我们在命令行看到是fltp这种名字跟它有什么关系呢?具体对照表如下,定义在FFmpeg/libavutilsamplefmt.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的格式数据,在根据我们的电脑的大小端类型知道,我们需要传递的参数是 s32le

好了,我们使用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

大连人才网