直播流程
一次直播中主播端采集音视频编码上传数据到服务器,观众端不断的拉取数据,数据解码音视频渲染到手机。
音频数据流格式的变化
音频采集上来的数据格式是pcm,pcm格式的数据非常庞大,不适合在网络上传播,所以我们用编码器把pcm数据格式处理为aac或者mp3格式,编码后的数据再加个壳封装成flv或者mp4多媒体文件。在观众端音频的数据格式走向相反。一般直播过程中不需要再把编码后的aac数据封装成多媒体文件,而是直接在网络中传输aac格式的音频数据。
音频采集三要素
采样大小:一个采样由多少bit存放,一般是16bit。
采样率:采样频率8k、16k、32k、44.1k。
声道数:单声道、双声道、多声道。
采样大小越大,声音的强度越高,采样率越大,声音的还原度越高。
音频编码
有损压缩
人类听觉范围在20Hz~20kHz,低于20Hz的是次声波,高于20Hz的是超声波。
根据频域遮蔽效应,音频中去除人类听不到的音频数据。
根据时域遮蔽效应,去除音频中嘈杂的低音。
无损压缩
对音频数据熵编码,熵编码包括哈夫曼编码、香农编码、算数编码。
音频编码过程
编码的代码
创建编码器
//avcodec_find_encoder(AV_CODEC_ID_AAC);
AVCodec *codec = avcodec_find_encoder_by_name("libfdk_aac");
//创建 codec 上下文
AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
codec_ctx->sample_fmt = AV_SAMPLE_FMT_S16; //输入音频的采样大小
codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO; //输入音频的channel layout
codec_ctx->channels =2; //输入音频 channel 个数
codec_ctx->sample_rate =44100; //输入音频的采样率
codec_ctx->bit_rate =0; //AAC_LC: 128K, AAC HE: 64K, AAC HE V2: 32K
codec_ctx->profile = FF_PROFILE_AAC_HE_V2;//阅读 ffmpeg 代码
//打开编码器
ret = avcodec_open2(codec_ctx, codec,NULL)
//将数据送编码器
ret = avcodec_send_frame(ctx, frame);
//获取编码后的音频数据
ret = avcodec_receive_packet(ctx, pkt);
音频采样和重采样
音频采集命令行:
ffmpeg -f avfoundation -i :0 out.wav
音频播放命令行:
ffplay out.wav
wav是音频原始数据的一种格式,它实质上就是pcm数据包加上一个头部。这个头部包含了很多的信息,包括音频的采样率、采样大小和声道数。如果在音频采集的时候,采集的数据格式为pcm格式
ffmpeg -f avfoundation -i :0 out.pcm
音频播放命令就要指定音频三要素的参数
ffplay -ar 44100 -ac 2 -f s16le out.pcm
ffmpeg代码采集音频流程
打开输入设备
avdevice_register_all(); //register audio device
//ctx
AVFormatContext *fmt_ctx =NULL;
AVDictionary *options =NULL;
//[[video device]:[audio device]]
char*devicename =":0";
//get format
AVInputFormat *iformat = av_find_input_format("avfoundation");
//open device
ret = avformat_open_input(&fmt_ctx, devicename, iformat, &options)
数据包
FILE *outfile = fopen(path,'wb');
AVPacket pkt;
while(ret = av_read_frame(fmt_ctx,&pkt)== 0){
fwrite(pkt.data,pkt.size,1,outfile);
av_packet_unref(&pkt);
}
音频重采样是将音频三元组采样率、采样大小、和通道数的值转成另外一组值。
例如:将441000/16/2转成48000/16/2
为什么需要重新采样
1 从设备采集的音频数据和编码器要求的数据不一致。
2 扬声器要求的音频数据和要播放的音频数据不一致。
采样的代码
SwrContext* swr_ctx =NULL;
swr_ctx = swr_alloc_set_opts(NULL, //ctx
AV_CH_LAYOUT_STEREO,//输出channel布局
AV_SAMPLE_FMT_S16, //输出的采样格式
44100, //采样率
AV_CH_LAYOUT_STEREO,//输入channel布局
AV_SAMPLE_FMT_FLT, //输入的采样格式
44100, //输入的采样率
0,NULL);
//重采样
swr_convert(swr_ctx, //重采样的上下文
dst_data, //输出结果缓冲区
512, //每个通道的采样数
(constuint8_t **)src_data,//输入缓冲区
512); //输入单个通道的采样数
注:本文代码只是简单示范,实际操作中需要注意内存泄漏,设备状态还有api返回值结果做些判断。