• 使用ffmpeg的C语言的SDK实现对桌面声音的采集


    #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
    ");
            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
    ");
                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
    ");
            return -1;
        }
        // 查找设个设备里面的媒体信息
        if (avformat_find_stream_info(formatCtx, NULL)<0)
        {
            printf("找不到媒体流信息!
    ");
            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.
    ");
            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
    ");
                } else{
                    printf("采集到音频
    ");
                    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();
    }
    
  • 相关阅读:
    开源云平台离普通用户还有多远?
    你的云桌面和阿里的云主机有什么区别?
    容器和虚拟机谁会是未来云计算的方向?
    白话为什么需要虚拟机和云计算有什么关系
    OpenStack是什么?
    Kubernetes是什么?
    第二夜:万圣节,讲一个关于程序员的故事
    万圣节,讲一个关于程序员的故事
    云计算社区新增两枚 .group 社群专属域名
    正式激活 .group 域名:云原生.社群
  • 原文地址:https://www.cnblogs.com/fandx/p/12159428.html
Copyright © 2020-2023  润新知