Ffmpeg using C language to achieve the acquisition of the SDK desktop sound

#include <iostream>

extern "C"{
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#include <libavutil/audio_fifo.h>
#include <libavutil/time.h>
#include <stdio.h>
}
using namespace std;


static AVFrame *alloc_audio_frame(enum AVSampleFormat sample_fmt,
        uint64_t channel_layout,
        int chnls,
        int sample_rate,
        int nb_samples)
{
    AVFrame *frame = av_frame_alloc();
    int ret;
    if (!frame){
        fprintf(stderr, "error allocating an audio frame\n");
        exit(1);
    }
    frame->format = sample_fmt;
    // 声道
    frame->channel_layout = channel_layout;
    // 有几个声道
    frame->channels = chnls;
    // 采样率
    frame->sample_rate = sample_rate;
    // 可以装多少个数据
    frame->nb_samples = nb_samples;
    if(nb_samples){
        ret = av_frame_get_buffer(frame, 1);
        if (ret < 0){
            fprintf(stderr, "error allocating an audio frame\n");
            exit(1);
        }
    }
    return frame;
}

// 声音的采集
static int test2(){
    // 创建一个文件管理器
    AVFormatContext *formatCtx = avformat_alloc_context();
    AVInputFormat *ifmt = av_find_input_format("avfoundation");

    // 配置流的参数
    AVDictionary *options = NULL;
//    av_dict_set(&options, "video_size". "1920*1080",0);
//    av_dict_set(&options, "framerate", "15", 0);

    // 打开桌面流
    if (avformat_open_input(&formatCtx, "2", ifmt, &options) != 0){
        printf("open input device fail\n");
        return -1;
    }
    // 查找设个设备里面的媒体信息
    if (avformat_find_stream_info(formatCtx, NULL)<0)
    {
        printf("找不到媒体流信息!\n");
        return -1;
    }
    if(formatCtx->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
    {
        printf("流信息格式错误!");
    }
    // 找到解码器
    AVCodec *codec = avcodec_find_decoder(formatCtx->streams[0]->codecpar->codec_id);
    if (codec ==NULL){
        printf("codec not found.\n");
        return -1;
    }

    AVCodecContext *ctx = avcodec_alloc_context3(codec);
    // 进行解码
    avcodec_parameters_to_context(ctx, formatCtx->streams[0]->codecpar);
    if (avcodec_open2(ctx, codec, NULL)<0){
        printf("不能打开解码器");
        return -1;
    }

    // 初始化声音
    AVFrame *frame = alloc_audio_frame(
            (AVSampleFormat)formatCtx->streams[0]->codecpar->format,
            formatCtx->streams[0]->codecpar->channel_layout,
            formatCtx->streams[0]->codecpar->channels,
            formatCtx->streams[0]->codecpar->sample_rate,
            formatCtx->streams[0]->codecpar->frame_size
            );
    // 开始对声音部分算法优化
    SwrContext *swr = swr_alloc();
    av_opt_set_int(swr, "in_channel_count", ctx->channels, 0);
    av_opt_set_int(swr, "in_channel_layout", ctx->channel_layout, 0);
    av_opt_set_int(swr, "in_sample_rate", ctx->sample_rate, 0);
    av_opt_set_sample_fmt(swr, "in_sample_fmt", ctx->sample_fmt, 0);

    int des_channe_layout=3;
    int des_channel_count=2;
    int des_sample_rate=44100;
    AVSampleFormat  des_sample_fmt = AV_SAMPLE_FMT_S16;

    av_opt_set_int(swr, "out_channel_layout", des_channe_layout, 0);
    av_opt_set_int(swr, "out_channel_count", des_channel_count, 0);
    av_opt_set_int(swr, "out_sample_rate",  des_sample_fmt, 0);
    av_opt_set_sample_fmt(swr, "out_sample_fmt", (AVSampleFormat)des_sample_fmt, 0);
    swr_init(swr);
    printf("声道:%d, 采样率:%d, 数据格式为:%d -----> 声道:%d, 采样率:%d, 数据格式为:%d",
            ctx->channels, ctx->sample_rate, ctx->sample_fmt,
            des_channel_count, des_sample_rate, des_sample_fmt);

    int DES_NB_SAMPLES = 1024;
    AVFrame *outFrame = alloc_audio_frame(des_sample_fmt, des_channe_layout,
            des_channel_count,des_sample_rate, DES_NB_SAMPLES);
    AVFrame *newFrame = alloc_audio_frame(des_sample_fmt, des_channe_layout,des_channel_count,
            des_sample_rate, 0);
    AVFrame *newFrame2 = alloc_audio_frame(des_sample_fmt, des_channe_layout,des_channel_count,
                                          des_sample_rate, 0);


    AVAudioFifo *fifo = av_audio_fifo_alloc(des_sample_fmt, des_channel_count, 10240);

    FILE *file=NULL;
//    fopen_s(&file, "out.pcm", 'wb');
    file = fopen("/Users/fandx/Desktop/out.pcm", "wb");


    int framecout = 100;
    while (framecout--){
        int size = av_audio_fifo_size(fifo);
        if(size >= DES_NB_SAMPLES){
            size = DES_NB_SAMPLES;
            av_audio_fifo_read(fifo, (void**)outFrame, size);
            fwrite(outFrame->data[0], size, des_channel_count*av_get_bytes_per_sample(des_sample_fmt),file);

            // 这里也是完整的数据
//            fwrite(outFrame->data[0], av_get_bytes_per_sample(des_sample_fmt)*des_channel_count,
//                    size, file)
            continue;

        }


        AVPacket packet = {0};
        av_init_packet(&packet);
        if(av_read_frame(formatCtx, &packet) >= 0){

            // 发送包到解码器
            avcodec_send_packet(ctx, &packet);
            if (avcodec_receive_frame(ctx, frame)<0)
            {
                printf("Decode Error\n");
            } else{
                printf("采集到音频\n");
                swr_convert_frame(swr, newFrame, frame);
                av_audio_fifo_write(fifo, (void**)newFrame->data, newFrame->nb_samples);

                int64_t dealy = swr_get_delay(swr, des_sample_rate);
                if (dealy >0){
                    swr_convert_frame(swr, newFrame2, NULL);

                }

                // 在这里可以判断一下fifo里面的数量足够1024
                int size = av_audio_fifo_size(fifo);

                if(size < DES_NB_SAMPLES){
                    // 数据不够
                    av_packet_unref(&packet);
                    continue;
                }

                av_audio_fifo_read(fifo, (void**)newFrame2->data, newFrame2->nb_samples);
                fwrite(outFrame->data[0], size, des_channel_count*av_get_bytes_per_sample(des_sample_fmt),file);

            }
        }
        av_packet_unref(&packet);
    }

    // 资源释放
    av_frame_free(&frame);
    av_frame_free(&newFrame);
    av_frame_free(&newFrame2);

    avcodec_free_context(&ctx);
    avformat_close_input(&formatCtx);

    fclose(file);
    return 0;


}

int main(){
    int ver = avcodec_version();

    avdevice_register_all();

    test2();
}

Guess you like

Origin www.cnblogs.com/fandx/p/12159428.html