Program 1:在windows上测试。 存在问题,如果频率重采样前后的频率不一样,会导致音频数据丢失。

#define __STDC_CONSTANT_MACROS
#include <string.h>



#include <windows.h>
#include <DShow.h>

extern "C"
{
#include "libavutil/avutil.h"
#include "libavdevice/avdevice.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswresample/swresample.h"
#include "libavdevice/avdevice.h"
}
static char *dup_wchar_to_utf8(wchar_t *w)
{
	char *s = NULL;
	int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
	s = (char *)av_malloc(l);
	if (s)
		WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
	return s;
}
/**
* @brief open audio device
* @return succ: AVFormatContext*, fail: NULL
*/
static
AVFormatContext* open_dev(){

	int ret = 0;
	char errors[1024] = { 0, };

	//ctx
	AVFormatContext *fmt_ctx = NULL;
	AVDictionary *options = NULL;


	av_dict_set(&options, "sample_size", "16", 0);
	av_dict_set(&options, "channels", "1", 0);
	av_dict_set(&options, "sample_rate", "16000", 0);

	char * device_name = dup_wchar_to_utf8(L"audio=麦克风 (Microphone)");

	//get format
	AVInputFormat *iformat = av_find_input_format("dshow");

	//open device
	if ((ret = avformat_open_input(&fmt_ctx, device_name, iformat, &options)) < 0){
		av_strerror(ret, errors, 1024);
		fprintf(stderr, "Failed to open audio device, [%d]%s\n", ret, errors);
		return NULL;
	}

	return fmt_ctx;
}

void rec_audio() {

	//context
	AVFormatContext *fmt_ctx = NULL;
	//set log level
	av_log_set_level(AV_LOG_DEBUG);

	//register audio device
	avdevice_register_all();


	//create file1
	char *out1 = "./16k_mono_s16le.pcm";
	FILE *outfile1 = fopen(out1, "wb+");
	if (!outfile1){
		printf("Error, Failed to open file!\n");
		return;
	}
	//create file2
	char *out2 = "./16k_stereo_s16le.pcm";
	FILE *outfile2 = fopen(out2, "wb+");
	if (!outfile2){
		printf("Error, Failed to open file!\n");
		return;
	}
	//打开设备
	fmt_ctx = open_dev();
	if (!fmt_ctx){
		printf("Error, Failed to open device!\n");
		return;
	}
	AVPacket pkt;
	int ret = -1, count = 1;

	SwrContext *swr = swr_alloc();
	av_opt_set_channel_layout(swr, "in_channel_layout", AV_CH_LAYOUT_MONO, 0);
	av_opt_set_channel_layout(swr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
	av_opt_set_int(swr, "in_sample_rate", 16000, 0);
	av_opt_set_int(swr, "out_sample_rate", 16000, 0);
	av_opt_set_sample_fmt(swr, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
	av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0);//-f f32le
	/* initialize the resampling context */
	if ((ret = swr_init(swr)) < 0) {
		fprintf(stderr, "Failed to initialize the resampling context\n");
	}

	uint8_t **out_data = NULL;
	uint8_t **in_data = NULL;
	int dst_linesize, src_linesize;
	int nbsamples = 44100 / 2;

	av_samples_alloc_array_and_samples(&in_data, &src_linesize, 1, nbsamples, AV_SAMPLE_FMT_S16, 0);

	av_samples_alloc_array_and_samples(&out_data, &dst_linesize, 2, nbsamples, AV_SAMPLE_FMT_FLT, 0);

	while ((ret = av_read_frame(fmt_ctx, &pkt)) == 0 && count++ < 10)
	{
		av_log(NULL, AV_LOG_INFO, "packet size is %d\n", pkt.size);
		memcpy((void *)in_data[0], pkt.data, pkt.size);
		int ret = swr_convert(swr, out_data, nbsamples, (const uint8_t **)in_data, nbsamples);

		int dst_bufsize = av_samples_get_buffer_size(&dst_linesize, 2, ret, AV_SAMPLE_FMT_FLT, 1);

		fwrite(pkt.data, 1, pkt.size, outfile1);
		fwrite(out_data[0], 1, dst_bufsize, outfile2);
		fflush(outfile1);
		fflush(outfile2);

		av_packet_unref(&pkt);//release pkt
	}

	fclose(outfile1);
	fclose(outfile2);
	av_log(NULL, AV_LOG_DEBUG, "finish!\n");

	return;
}


int main(int argc, char *argv[])
{
	rec_audio();
	return 0;
}

program2: 解决program1 的问题,上采样和下采样av_rescale_rnd来就算dst_nb_samples

#define __STDC_CONSTANT_MACROS
#include <string.h>



#include <windows.h>
#include <DShow.h>

extern "C"
{
#include "libavutil/avutil.h"
#include "libavdevice/avdevice.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswresample/swresample.h"
#include "libavdevice/avdevice.h"
}
static char *dup_wchar_to_utf8(wchar_t *w)
{
	char *s = NULL;
	int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
	s = (char *)av_malloc(l);
	if (s)
		WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
	return s;
}
/**
* @brief open audio device
* @return succ: AVFormatContext*, fail: NULL
*/
static
AVFormatContext* open_dev(){

	int ret = 0;
	char errors[1024] = { 0, };

	//ctx
	AVFormatContext *fmt_ctx = NULL;
	AVDictionary *options = NULL;


	av_dict_set(&options, "sample_size", "16", 0);
	av_dict_set(&options, "channels", "1", 0);
	av_dict_set(&options, "sample_rate", "16000", 0);

	char * device_name = dup_wchar_to_utf8(L"audio=麦克风 (Microphone)");

	//get format
	AVInputFormat *iformat = av_find_input_format("dshow");

	//open device
	if ((ret = avformat_open_input(&fmt_ctx, device_name, iformat, &options)) < 0){
		av_strerror(ret, errors, 1024);
		fprintf(stderr, "Failed to open audio device, [%d]%s\n", ret, errors);
		return NULL;
	}

	return fmt_ctx;
}

void rec_audio() {

	//context
	AVFormatContext *fmt_ctx = NULL;
	//set log level
	av_log_set_level(AV_LOG_DEBUG);

	//register audio device
	avdevice_register_all();


	//create file1
	char *out1 = "./16k_mono_s16le.pcm";
	FILE *outfile1 = fopen(out1, "wb+");
	if (!outfile1){
		printf("Error, Failed to open file!\n");
		return;
	}
	//create file2
	char *out2 = "./41k_stereo_f32le.pcm";
	FILE *outfile2 = fopen(out2, "wb+");
	if (!outfile2){
		printf("Error, Failed to open file!\n");
		return;
	}
	//打开设备
	fmt_ctx = open_dev();
	if (!fmt_ctx){
		printf("Error, Failed to open device!\n");
		return;
	}
	AVPacket pkt;
	int ret = -1, count = 1;
	uint64_t src_channel_layout = AV_CH_LAYOUT_MONO;
	uint64_t dst_channel_layout = AV_CH_LAYOUT_STEREO; //定义目标音频参数
	int src_rate = 16000;
	int dst_rate = 44100;
	AVSampleFormat src_fmt = AV_SAMPLE_FMT_S16;
	AVSampleFormat dst_fmt = AV_SAMPLE_FMT_FLT;

	SwrContext *swr = swr_alloc();
	av_opt_set_channel_layout(swr, "in_channel_layout", src_channel_layout, 0);
	av_opt_set_channel_layout(swr, "out_channel_layout", dst_channel_layout, 0);
	av_opt_set_int(swr, "in_sample_rate", src_rate, 0);
	av_opt_set_int(swr, "out_sample_rate", dst_rate, 0);
	av_opt_set_sample_fmt(swr, "in_sample_fmt", src_fmt, 0);
	av_opt_set_sample_fmt(swr, "out_sample_fmt", dst_fmt, 0);//-f f32le
	/* initialize the resampling context */
	if ((ret = swr_init(swr)) < 0) {
		fprintf(stderr, "Failed to initialize the resampling context\n");
	}

	uint8_t **out_data = NULL;
	uint8_t **in_data = NULL;
	int dst_linesize, src_linesize;
	int src_nb_samples = 44100 / av_get_bytes_per_sample(src_fmt);
	int max_dst_nb_samples, dst_nb_samples;

	int src_channels = av_get_channel_layout_nb_channels(src_channel_layout);
	int dst_channels = av_get_channel_layout_nb_channels(dst_channel_layout);
	av_log(NULL, AV_LOG_INFO, "src_channels = %d, dst_channels = %d\n", src_channels, dst_channels);


	max_dst_nb_samples = dst_nb_samples = av_rescale_rnd(src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);

	av_samples_alloc_array_and_samples(&in_data, &src_linesize, src_channels, src_nb_samples, src_fmt, 0);

	av_samples_alloc_array_and_samples(&out_data, &dst_linesize, dst_channels, dst_nb_samples, dst_fmt, 0);

	while ((ret = av_read_frame(fmt_ctx, &pkt)) == 0 && count++ < 10)
	{
		av_log(NULL, AV_LOG_INFO, "packet size is %d\n", pkt.size);
		memcpy((void *)in_data[0], pkt.data, pkt.size);
		
		/* compute destination number of samples */
		dst_nb_samples = av_rescale_rnd(swr_get_delay(swr, src_rate) + src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);

		int ret = swr_convert(swr, out_data, dst_nb_samples, (const uint8_t **)in_data, src_nb_samples);


		int dst_bufsize = av_samples_get_buffer_size(&dst_linesize, dst_channels, ret, dst_fmt, 1);

		fwrite(pkt.data, 1, pkt.size, outfile1);
		fwrite(out_data[0], 1, dst_bufsize, outfile2);//ffplay -ar 44100 -ac 2 -f f32le 41k_stereo_f32le.pcm
		fflush(outfile1);
		fflush(outfile2);

		av_packet_unref(&pkt);//release pkt
	}

	fclose(outfile1);
	fclose(outfile2);
	av_log(NULL, AV_LOG_DEBUG, "finish!\n");

	return;
}


int main(int argc, char *argv[])
{
	rec_audio();
	return 0;
}

Program 3: Ubuntu上测试。 重新计算dst_sample。

#define __STDC_CONSTANT_MACROS
#include <string.h>

extern "C"
{
#include "libavutil/avutil.h"
#include "libavdevice/avdevice.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswresample/swresample.h"
#include "libavdevice/avdevice.h"
}

/**
* @brief open audio device
* @return succ: AVFormatContext*, fail: NULL
*/
static
AVFormatContext* open_dev(){

    int ret = 0;
    char errors[1024] = { 0, };

    //ctx
    AVFormatContext *fmt_ctx = NULL;
    AVDictionary *options = NULL;


    av_dict_set(&options, "sample_size", "16", 0);
    av_dict_set(&options, "channels", "1", 0);
    av_dict_set(&options, "sample_rate", "16000", 0);

    //[[video device]:[audio device]]
    char *device_name = "hw:2,0";

    //get format
    AVInputFormat *iformat = av_find_input_format("alsa");

    //open device
    if ((ret = avformat_open_input(&fmt_ctx, device_name, iformat, &options)) < 0){
        av_strerror(ret, errors, 1024);
        fprintf(stderr, "Failed to open audio device, [%d]%s\n", ret, errors);
        return NULL;
    }

    return fmt_ctx;
}

void rec_audio() {

    //context
    AVFormatContext *fmt_ctx = NULL;
    //set log level
    av_log_set_level(AV_LOG_DEBUG);

    //register audio device
    avdevice_register_all();


    //create file1
    char *out1 = "/home/lili/Videos/16k_mono_s16le.pcm";
    FILE *outfile1 = fopen(out1, "wb+");
    if (!outfile1){
        printf("Error, Failed to open file!\n");
        return;
    }
    //create file2
    char *out2 = "/home/lili/Videos/16k_stereo_s16le.pcm";
    FILE *outfile2 = fopen(out2, "wb+");
    if (!outfile2){
        printf("Error, Failed to open file!\n");
        return;
    }
    //打开设备
    fmt_ctx = open_dev();
    if (!fmt_ctx){
        printf("Error, Failed to open device!\n");
        return;
    }
    AVPacket pkt;
    int ret = -1, count = 1;
    uint64_t src_channel_layout = AV_CH_LAYOUT_MONO;
    uint64_t dst_channel_layout = AV_CH_LAYOUT_STEREO; //定义目标音频参数
    int src_rate = 16000;
    int dst_rate = 44100;
    SwrContext *swr = swr_alloc();
    av_opt_set_channel_layout(swr, "in_channel_layout", src_channel_layout, 0);
    av_opt_set_channel_layout(swr, "out_channel_layout", dst_channel_layout, 0);
    av_opt_set_int(swr, "in_sample_rate", src_rate, 0);
    av_opt_set_int(swr, "out_sample_rate", dst_rate, 0);
    av_opt_set_sample_fmt(swr, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
    av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0);
    /* initialize the resampling context */
    if ((ret = swr_init(swr)) < 0) {
        fprintf(stderr, "Failed to initialize the resampling context\n");
        return;
    }

    uint8_t **out_data = NULL;
    uint8_t **in_data = NULL;

    int dst_linesize, src_linesize;
    int src_nb_samples = 128;
    int max_dst_nb_samples, dst_nb_samples;

    int src_channels = av_get_channel_layout_nb_channels(src_channel_layout);
    int dst_channels = av_get_channel_layout_nb_channels(dst_channel_layout);
    av_log(NULL, AV_LOG_INFO, "src_channels = %d, dst_channels = %d\n", src_channels, dst_channels);


    max_dst_nb_samples = dst_nb_samples = av_rescale_rnd(src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);


    av_samples_alloc_array_and_samples(&in_data, &src_linesize, src_channels, src_nb_samples, AV_SAMPLE_FMT_S16, 0);
    av_samples_alloc_array_and_samples(&out_data, &dst_linesize, dst_channels, dst_nb_samples, AV_SAMPLE_FMT_FLT, 0);
    av_log(NULL, AV_LOG_INFO, "src_linesize = %d, dst_linesize = %d\n", src_linesize, dst_linesize);

    while((ret = av_read_frame(fmt_ctx, &pkt)) == 0 && count++ < 1024)
    {
        av_log(NULL, AV_LOG_INFO, "packet size is %d\n", pkt.size);
        memcpy((void *)in_data[0], pkt.data, pkt.size);

        /* compute destination number of samples */
        dst_nb_samples = av_rescale_rnd(swr_get_delay(swr, src_rate) + src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);

        int ret = swr_convert(swr, out_data, dst_nb_samples, (const uint8_t **)in_data, src_nb_samples);
        int dst_bufsize = av_samples_get_buffer_size(&dst_linesize, 2, ret, AV_SAMPLE_FMT_FLT, 1);

        fwrite(pkt.data, 1, pkt.size, outfile1);
        fwrite(out_data[0], 1, dst_bufsize, outfile2);

        fflush(outfile1);
        fflush(outfile2);

        av_packet_unref(&pkt);//release pkt
    }

    fclose(outfile1);
    fclose(outfile2);

    if (out_data)
        av_freep(&out_data[0]);
    av_freep(&out_data);

    if (in_data)
        av_freep(&in_data[0]);
    av_freep(&in_data);

    swr_free(&swr);//释放重采样上下文资源

    av_log(NULL, AV_LOG_DEBUG, "finish!\n");

    return;
}


int main(int argc, char *argv[])
{
    rec_audio();
    return 0;
}

Program4:

PCM数据的重采样,然后编码

#include <stdio.h>

#define __STDC_CONSTANT_MACROS


extern "C"
{
#include "libavformat/avformat.h"
#include "libavformat/avio.h"
#include "libavdevice/avdevice.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavutil/imgutils.h"
}
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#define ADTS_HEADER_LEN  7;

void adts_header(char *szAdtsHeader, int dataLen){

    int audio_object_type = 2;
    int sampling_frequency_index = 4;//4: 44100 Hz
    int channel_config = 2;

    int adtsLen = dataLen + 7;

    szAdtsHeader[0] = 0xff;         //syncword:0xfff                          高8bits
    szAdtsHeader[1] = 0xf0;         //syncword:0xfff                          低4bits
    szAdtsHeader[1] |= (0 << 3);    //MPEG Version:0 for MPEG-4,1 for MPEG-2  1bit
    szAdtsHeader[1] |= (0 << 1);    //Layer:0                                 2bits
    szAdtsHeader[1] |= 1;           //protection absent:1                     1bit

    szAdtsHeader[2] = (audio_object_type - 1) << 6;            //profile:audio_object_type - 1                      2bits
    szAdtsHeader[2] |= (sampling_frequency_index & 0x0f) << 2; //sampling frequency index:sampling_frequency_index  4bits
    szAdtsHeader[2] |= (0 << 1);                             //private bit:0                                      1bit
    szAdtsHeader[2] |= (channel_config & 0x04) >> 2;           //channel configuration:channel_config               高1bit

    szAdtsHeader[3] = (channel_config & 0x03) << 6;     //channel configuration:channel_config      低2bits
    szAdtsHeader[3] |= (0 << 5);                      //original:0                               1bit
    szAdtsHeader[3] |= (0 << 4);                      //home:0                                   1bit
    szAdtsHeader[3] |= (0 << 3);                      //copyright id bit:0                       1bit
    szAdtsHeader[3] |= (0 << 2);                      //copyright id start:0                     1bit
    szAdtsHeader[3] |= ((adtsLen & 0x1800) >> 11);           //frame length:value   高2bits

    szAdtsHeader[4] = (uint8_t)((adtsLen & 0x7f8) >> 3);     //frame length:value    中间8bits
    szAdtsHeader[5] = (uint8_t)((adtsLen & 0x7) << 5);       //frame length:value    低3bits
    szAdtsHeader[5] |= 0x1f;                                 //buffer fullness:0x7ff 高5bits
    szAdtsHeader[6] = 0xfc;
}

static void encode(AVCodecContext *cdc_ctx, AVFrame *frame, AVPacket *pkt, FILE *fp_out)
{
    int ret = 0;

    if ((ret = avcodec_send_frame(cdc_ctx, frame)) < 0)
    {
        fprintf(stderr, "avcodec_send_frame failed.\n");
        exit(1);
    }

    while ((ret = avcodec_receive_packet(cdc_ctx, pkt)) >= 0)
    {
        char adts_header_buf[7];
        adts_header(adts_header_buf, pkt->size);
        fwrite(adts_header_buf, 1, 7, fp_out);

        printf("Write (size=%d) packet.\n", pkt->size);
        fwrite(pkt->data, 1, pkt->size, fp_out);
        av_packet_unref(pkt);
    }

    if ((ret != AVERROR(EAGAIN)) && (ret != AVERROR_EOF))
    {
        fprintf(stderr, "avcodec_receive_packet failed.\n");
        exit(1);
    }
}

const char *fifo_name = "/home/lili/Audio/myfifo";
int create_pipe()
{
    if(mkfifo("./fifo",0777) != 0 ) //在当前路径下(运行程序所在的路径)创建有名管道,有名管道权限读写执行
    {
        if(errno == EEXIST) //当该有名管道存在时,提示下
        {
            printf("File exists\n");
        }
        else
        {
            perror("mkfifo fail ");
            exit(1);
        }
    }
    int pipe_fd;
    pipe_fd = open(fifo_name,O_RDWR);//读写方式打开,使用文件IO 操作有名管道
    if(pipe_fd < 0)
    {
        perror("open fifo fail: ");
        exit(1);
    }
    return pipe_fd;
}


AVFrame *frame = NULL;
AVCodecContext *codec_ctx = NULL;
AVPacket *pkt = NULL;
FILE *fp_aacout = NULL;
int pipefd[2];


void *thr_fn(void *arg){
    printf("new thread \n");

    int pipe_fd = open(fifo_name, O_RDONLY);

    int readn = 0;
    if(frame == NULL || codec_ctx == NULL || pkt == NULL)
    {
        printf("pointer is NULL!\n");
        return NULL;
    }
    while((readn = read(pipe_fd, frame->data[0], frame->linesize[0])) > 0)
    {
        printf("read %d data\n", readn);
        encode(codec_ctx, frame, pkt, fp_aacout);
        usleep(100);
    }
    encode(codec_ctx, NULL, pkt, fp_aacout);

    close(pipe_fd);
    printf("exit thread!\n");
    return ((void *)0);
}

int main(int argc, char *argv[])
{
    int64_t src_ch_layout = AV_CH_LAYOUT_MONO;
    int64_t dst_ch_layout = AV_CH_LAYOUT_MONO;
    int src_rate = 16000;
    int dst_rate = 44100;
    AVSampleFormat src_fmt = AV_SAMPLE_FMT_S16;
    AVSampleFormat dst_fmt = AV_SAMPLE_FMT_FLTP;
    const char *input_file = "/home/lili/Audio/QLED_16000_mono_s16le.pcm";
    const char *output_file = "/home/lili/Audio/QLED_44100_mono_f32le.pcm";
    const char *output_aacfile = "/home/lili/Audio/QLED.aac";
    avdevice_register_all();
    //查找编码器
    AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
    if (!codec)
    {
        printf("can't find encoder\n");
        return -1;
    }

    if ((codec_ctx = avcodec_alloc_context3(codec)) == NULL)
    {
        fprintf(stderr, "avcodec_alloc_context3 failed.\n");
    }

    codec_ctx->bit_rate = 64000;
    codec_ctx->sample_fmt = dst_fmt;
    codec_ctx->sample_rate = dst_rate;
    codec_ctx->channel_layout = dst_ch_layout;
    codec_ctx->channels = av_get_channel_layout_nb_channels(codec_ctx->channel_layout);

    //打开编码器
    if (avcodec_open2(codec_ctx, codec, NULL) < 0)
    {
        printf("can't open encoder\n");
    }

    if ((pkt = av_packet_alloc()) == NULL)
    {
        fprintf(stderr, "av_packet_alloc failed.\n");
    }

    frame = av_frame_alloc();
    if (!frame)
    {
        printf("can't alloc frame\n");
        return -1;
    }

    frame->nb_samples = codec_ctx->frame_size;
    frame->format = dst_fmt;
    frame->channel_layout = dst_ch_layout;

    int ret = -1;
    if ((ret = av_frame_get_buffer(frame, 0)) < 0)
    {
        fprintf(stderr, "av_frame_get_buffer failed.\n");
    }


    FILE *fp_in = NULL;
    if ((fp_in = fopen(input_file, "rb")) == NULL)
    {
        fprintf(stderr, "fopen %s failed.\n", input_file);
        return -1;
    }
    FILE *fp_out = NULL;
    if ((fp_out = fopen(output_file, "wb")) == NULL)
    {
        fprintf(stderr, "fopen %s failed.\n", output_file);
        return -1;
    }
    int data_size = av_get_bytes_per_sample(src_fmt);

    SwrContext *swr = swr_alloc();

    av_opt_set_channel_layout(swr, "in_channel_layout", src_ch_layout, 0);
    av_opt_set_channel_layout(swr, "out_channel_layout", dst_ch_layout, 0);
    av_opt_set_int(swr, "in_sample_rate", src_rate, 0);
    av_opt_set_int(swr, "out_sample_rate", dst_rate, 0);
    av_opt_set_sample_fmt(swr, "in_sample_fmt", src_fmt, 0);
    av_opt_set_sample_fmt(swr, "out_sample_fmt", dst_fmt, 0);
    /* initialize the resampling context */
    if ((ret = swr_init(swr)) < 0) {
        fprintf(stderr, "Failed to initialize the resampling context\n");
    }

    uint8_t **out_data = NULL;
    uint8_t **in_data = NULL;
    int dst_linesize, src_linesize;
    int src_nb_samples = frame->nb_samples;
    int max_dst_nb_samples, dst_nb_samples;

    int src_channels = av_get_channel_layout_nb_channels(src_ch_layout);
    int dst_channels = av_get_channel_layout_nb_channels(dst_ch_layout);
    av_log(NULL, AV_LOG_INFO, "src_channels = %d, dst_channels = %d\n", src_channels, dst_channels);
    max_dst_nb_samples = dst_nb_samples = av_rescale_rnd(src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);

    av_samples_alloc_array_and_samples(&in_data, &src_linesize, src_channels, src_nb_samples, src_fmt, 0);
    av_samples_alloc_array_and_samples(&out_data, &dst_linesize, dst_channels, dst_nb_samples, dst_fmt, 0);

    if ((fp_aacout = fopen(output_aacfile, "wb")) == NULL)
    {
        fprintf(stderr, "fopen %s failed.\n", output_aacfile);
        return -1;
    }
    if (pipe(pipefd) == -1) {
       perror("pipe");
       exit(EXIT_FAILURE);
    }

    pid_t cpid = fork();
    if (cpid == -1) {
       perror("fork");
       exit(EXIT_FAILURE);
    }

    if (cpid == 0) {    /* Child reads from pipe */
       close(pipefd[1]);          /* Close unused write end */
       int readn = 0;
       while((readn = read(pipefd[0], frame->data[0], frame->linesize[0])) > 0)
       {
           printf("read %d data\n", readn);
           encode(codec_ctx, frame, pkt, fp_aacout);
           usleep(100);
       }
       encode(codec_ctx, NULL, pkt, fp_aacout);
       close(pipefd[0]);
       _exit(EXIT_SUCCESS);
    } else
    {   /* Parent writes argv[1] to pipe */
        close(pipefd[0]);          /* Close unused read end */
        while (feof(fp_in) == 0)
        {
            //输入一帧数据的长度
            int length = src_nb_samples * av_get_bytes_per_sample(src_fmt) * src_channels;
            fread(frame->data[0], 1, length, fp_in);
            memcpy((void *)in_data[0], frame->data[0], length);

            /* compute destination number of samples */
            dst_nb_samples = av_rescale_rnd(swr_get_delay(swr, src_rate) + src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);

            int ret = swr_convert(swr, out_data, dst_nb_samples, (const uint8_t **)in_data, src_nb_samples);
            int dst_bufsize = av_samples_get_buffer_size(NULL, dst_channels, ret, dst_fmt, 1);

            fprintf(stderr, "writing %d data\n",dst_bufsize);
            fwrite(out_data[0], 1, dst_bufsize, fp_out);//ffplay -ar 44100 -ac 1 -f f32le 41k_stereo_f32le.pcm
            write(pipefd[1], out_data[0], dst_bufsize); //子进程写数据给管道
            fflush(fp_out);
        }
        close(pipefd[1]);          /* Reader will see EOF */

        fclose(fp_out);
        fclose(fp_aacout);
        fclose(fp_in);
        av_frame_free(&frame);
        av_packet_free(&pkt);

        wait(NULL);                /* Wait for child */
        exit(EXIT_SUCCESS);
    }

    return 0;
}

上述程序存在两个问题,如果swr_convert转换成双通道,Program4没有考虑到。如果是自己实现,需要将转换后的数据按照编码器要求的格式,nb_samples,存放到frame中。

int convert_samples = swr_convert(swr, out_data, dst_nb_samples, (const uint8_t **)in_data, src_nb_samples);

convert_samples大于src_nb_samples,需要对数据重新分配,还要考虑PCM的模式是packet,planner模式,并存储到frame的data中,以及是几个声道的一堆事情。

好在有av_audio_fifo_write,av_audio_fifo_read来帮我们做这件事情。

Program5: 用av_audio_fifo替换pipe。不用从底层的字节层面去做转换,效率更高。

#include <stdio.h>

#define __STDC_CONSTANT_MACROS


extern "C"
{
#include "libavformat/avformat.h"
#include "libavformat/avio.h"
#include "libavdevice/avdevice.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavutil/audio_fifo.h"

}
#include <stdio.h>
#define ADTS_HEADER_LEN  7;

static void adts_header(char *szAdtsHeader, int dataLen){

	int audio_object_type = 2;
	int sampling_frequency_index = 4;//4: 44100 Hz
	int channel_config = 2;

	int adtsLen = dataLen + 7;

	szAdtsHeader[0] = 0xff;         //syncword:0xfff                          高8bits
	szAdtsHeader[1] = 0xf0;         //syncword:0xfff                          低4bits
	szAdtsHeader[1] |= (0 << 3);    //MPEG Version:0 for MPEG-4,1 for MPEG-2  1bit
	szAdtsHeader[1] |= (0 << 1);    //Layer:0                                 2bits
	szAdtsHeader[1] |= 1;           //protection absent:1                     1bit

	szAdtsHeader[2] = (audio_object_type - 1) << 6;            //profile:audio_object_type - 1                      2bits
	szAdtsHeader[2] |= (sampling_frequency_index & 0x0f) << 2; //sampling frequency index:sampling_frequency_index  4bits
	szAdtsHeader[2] |= (0 << 1);                             //private bit:0                                      1bit
	szAdtsHeader[2] |= (channel_config & 0x04) >> 2;           //channel configuration:channel_config               高1bit

	szAdtsHeader[3] = (channel_config & 0x03) << 6;     //channel configuration:channel_config      低2bits
	szAdtsHeader[3] |= (0 << 5);                      //original:0                               1bit
	szAdtsHeader[3] |= (0 << 4);                      //home:0                                   1bit
	szAdtsHeader[3] |= (0 << 3);                      //copyright id bit:0                       1bit
	szAdtsHeader[3] |= (0 << 2);                      //copyright id start:0                     1bit
	szAdtsHeader[3] |= ((adtsLen & 0x1800) >> 11);           //frame length:value   高2bits

	szAdtsHeader[4] = (uint8_t)((adtsLen & 0x7f8) >> 3);     //frame length:value    中间8bits
	szAdtsHeader[5] = (uint8_t)((adtsLen & 0x7) << 5);       //frame length:value    低3bits
	szAdtsHeader[5] |= 0x1f;                                 //buffer fullness:0x7ff 高5bits
	szAdtsHeader[6] = 0xfc;
}

static void encode(AVCodecContext *cdc_ctx, AVFrame *frame, AVPacket *pkt, FILE *fp_out)
{
	int ret = 0;

	if ((ret = avcodec_send_frame(cdc_ctx, frame)) < 0)
	{
		fprintf(stderr, "avcodec_send_frame failed.\n");
		exit(1);
	}

	while ((ret = avcodec_receive_packet(cdc_ctx, pkt)) >= 0)
	{
		char adts_header_buf[7];
		adts_header(adts_header_buf, pkt->size);
		fwrite(adts_header_buf, 1, 7, fp_out);

		printf("Write (size=%d) packet.\n", pkt->size);
		fwrite(pkt->data, 1, pkt->size, fp_out);
		av_packet_unref(pkt);
	}

	if ((ret != AVERROR(EAGAIN)) && (ret != AVERROR_EOF))
	{
		fprintf(stderr, "avcodec_receive_packet failed.\n");
		exit(1);
	}
}


static AVFrame *frame = NULL;
static AVCodecContext *codec_ctx = NULL;
static AVPacket *pkt = NULL;
static FILE *fp_aacout = NULL;

int main(int argc, char *argv[])
{
	int64_t src_ch_layout = AV_CH_LAYOUT_MONO;
	int64_t dst_ch_layout = AV_CH_LAYOUT_STEREO;
	int src_rate = 8000;
	int dst_rate = 44100;
	AVSampleFormat src_fmt = AV_SAMPLE_FMT_S16;
	AVSampleFormat dst_fmt = AV_SAMPLE_FMT_FLTP;
	const char *input_file = "./beijingbeijing_8000_mono_s16le.pcm";
	const char *output_file = "./beijingbeijing_44100_stereo_f32le.pcm";
	const char *output_aacfile = "./beijingbeijing.aac";
	avdevice_register_all();
	//查找编码器
	AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
	if (!codec)
	{
		printf("can't find encoder\n");
		return -1;
	}

	if ((codec_ctx = avcodec_alloc_context3(codec)) == NULL)
	{
		fprintf(stderr, "avcodec_alloc_context3 failed.\n");
		return -1;
	}

	codec_ctx->bit_rate = 64000;
	codec_ctx->sample_fmt = dst_fmt;
	codec_ctx->sample_rate = dst_rate;
	codec_ctx->channel_layout = dst_ch_layout;
	codec_ctx->channels = av_get_channel_layout_nb_channels(codec_ctx->channel_layout);

	//打开编码器
	if (avcodec_open2(codec_ctx, codec, NULL) < 0)
	{
		printf("can't open encoder\n");
		return -1;
	}

	if ((pkt = av_packet_alloc()) == NULL)
	{
		fprintf(stderr, "av_packet_alloc failed.\n");
		return -1;
	}

	frame = av_frame_alloc();
	if (!frame)
	{
		printf("can't alloc frame\n");
		return -1;
	}

	frame->nb_samples = codec_ctx->frame_size;
	frame->format = dst_fmt;
	frame->channel_layout = dst_ch_layout;

	int ret = -1;
	if ((ret = av_frame_get_buffer(frame, 0)) < 0)
	{
		fprintf(stderr, "av_frame_get_buffer failed.\n");
		return -1;
	}


	FILE *fp_in = NULL;
	if ((fp_in = fopen(input_file, "rb")) == NULL)
	{
		fprintf(stderr, "fopen %s failed.\n", input_file);
		return -1;
	}
	FILE *fp_out = NULL;
	if ((fp_out = fopen(output_file, "wb")) == NULL)
	{
		fprintf(stderr, "fopen %s failed.\n", output_file);
		return -1;
	}

	SwrContext *swr = swr_alloc();

	av_opt_set_channel_layout(swr, "in_channel_layout", src_ch_layout, 0);
	av_opt_set_channel_layout(swr, "out_channel_layout", dst_ch_layout, 0);
	av_opt_set_int(swr, "in_sample_rate", src_rate, 0);
	av_opt_set_int(swr, "out_sample_rate", dst_rate, 0);
	av_opt_set_sample_fmt(swr, "in_sample_fmt", src_fmt, 0);
	av_opt_set_sample_fmt(swr, "out_sample_fmt", dst_fmt, 0);
	/* initialize the resampling context */
	if ((ret = swr_init(swr)) < 0) {
		fprintf(stderr, "Failed to initialize the resampling context\n");
		return -1;
	}

	uint8_t **out_data = NULL;
	uint8_t **in_data = NULL;
	int dst_linesize, src_linesize;
	int src_nb_samples = frame->nb_samples;
	int max_dst_nb_samples, dst_nb_samples;

	int src_channels = av_get_channel_layout_nb_channels(src_ch_layout);
	int dst_channels = av_get_channel_layout_nb_channels(dst_ch_layout);
	av_log(NULL, AV_LOG_INFO, "src_channels = %d, dst_channels = %d\n", src_channels, dst_channels);
	max_dst_nb_samples = dst_nb_samples = av_rescale_rnd(src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);

	av_samples_alloc_array_and_samples(&in_data, &src_linesize, src_channels, src_nb_samples, src_fmt, 0);
	av_samples_alloc_array_and_samples(&out_data, &dst_linesize, dst_channels, dst_nb_samples, dst_fmt, 0);

	if ((fp_aacout = fopen(output_aacfile, "wb")) == NULL)
	{
		fprintf(stderr, "fopen %s failed.\n", output_aacfile);
		return -1;
	}


	AVAudioFifo *fifo = av_audio_fifo_alloc(dst_fmt, dst_channels, frame->nb_samples);
	if ((ret = av_audio_fifo_realloc(fifo, frame->nb_samples)) < 0) {
		fprintf(stderr, "Could not reallocate FIFO\n");
		return ret;
	}

	while (feof(fp_in) == 0)
	{
		//输入一帧数据的长度
		int length = src_nb_samples * av_get_bytes_per_sample(src_fmt) * src_channels;
		fread((void *)in_data[0], 1, length, fp_in);

		/* compute destination number of samples */
		dst_nb_samples = av_rescale_rnd(swr_get_delay(swr, src_rate) + src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);

		int convert_samples = swr_convert(swr, out_data, dst_nb_samples, (const uint8_t **)in_data, src_nb_samples);
		int dst_bufsize = av_samples_get_buffer_size(NULL, dst_channels, convert_samples, dst_fmt, 1);

		int ret = av_audio_fifo_write(fifo, (void **)out_data, convert_samples);
		if ((ret = av_audio_fifo_read(fifo, (void **)frame->data, frame->nb_samples)) < frame->nb_samples) {
			fprintf(stderr, "Could not read data from FIFO\n");
			return AVERROR_EXIT;
		}		
		encode(codec_ctx, frame, pkt, fp_aacout);

		if (av_sample_fmt_is_planar(dst_fmt))
		{
			//fprintf(stderr, "%s is planar\n", av_get_sample_fmt_name(dst_fmt));
			//change planar data into packet data, do "ffplay -ar 44100 -ac 2 -f f32le beijingbeijing_44100_stereo_f32le.pcm"
			int dst_fmt_size = av_get_bytes_per_sample(dst_fmt);
			for (int i = 0; i < convert_samples; i++)
			{
				for (int ch = 0; ch < dst_channels; ch++)
				{
					fwrite(out_data[ch] + dst_fmt_size * i, 1, dst_fmt_size, fp_out);
				}
			}
		}
		else
		{
			fwrite(out_data[0], 1, dst_bufsize, fp_out);
		}
		fflush(fp_out);
	}


	while (av_audio_fifo_size(fifo) >= frame->nb_samples)
	{
		if (av_audio_fifo_read(fifo, (void **)frame->data, frame->nb_samples) < frame->nb_samples) 
		{
			av_log(NULL, AV_LOG_ERROR, "Could not read data from FIFO\n");
			return AVERROR_EXIT;
		}
		encode(codec_ctx, frame, pkt, fp_aacout);
	}

	encode(codec_ctx, NULL, pkt, fp_aacout);


	fclose(fp_out);
	fclose(fp_aacout);
	fclose(fp_in);
	av_frame_free(&frame);
	av_packet_free(&pkt);

	return 0;
}

AVAudioFifo是一个缓冲区,它以一次音频采样为基本单位,是一个先进先出的队列。有了它,对音频的采样数据做缓冲就会变得非常简单,

其优势有两点:

一,它让我们在采样层面做操作,而不是更底层的字节层面;

二,它支持多种格式的单次采样,如支持planar或packed的采样格式,支持不同的通道数等等。


//分配一个AVAudioFifo。
//sample_fmt和channels指定单次采样的参数
//nb_samples则指定AVAudioFifo的缓冲区大小。
AVAudioFifo *av_audio_fifo_alloc(enum AVSampleFormat sample_fmt, int channels,int nb_samples);
 
//重新分配缓冲区大小
//成功返回0,失败返回负的错误值
int av_audio_fifo_realloc(AVAudioFifo *af, int nb_samples);
 
//释放AVAudioFifo
void av_audio_fifo_free(AVAudioFifo *af);

//将采样写入到AVAudioFifo
//成功则返回实际写入的采样数(实际上如果写入成功,返回值必定等于nb_samples),失败返回负的错误值
int av_audio_fifo_write(AVAudioFifo *af, void **data, int nb_samples);
 
//peek:读取数据,但读到的数据并不会从fifo中删除
int av_audio_fifo_peek(AVAudioFifo *af, void **data, int nb_samples);
 
//从指定的偏移位置peek数据
int av_audio_fifo_peek_at(AVAudioFifo *af, void **data, int nb_samples, int offset);
 
//读取数据,读到的数据会从fifo中删除
int av_audio_fifo_read(AVAudioFifo *af, void **data, int nb_samples);
 
//从fifo中删除nb_samples个采样
int av_audio_fifo_drain(AVAudioFifo *af, int nb_samples);
 
//删除fifo中的所有采样,清空
void av_audio_fifo_reset(AVAudioFifo *af);


//返回fifo中当前存储的采样数量
int av_audio_fifo_size(AVAudioFifo *af);
 
//返回fifo中当前可写的采样数量,即尚未使用的空间数量
int av_audio_fifo_space(AVAudioFifo *af);
 
//同一时刻,以上两个函数的返回值之和等于fifo的缓冲区大小