1. 程式人生 > >ffmpeg4教程2:採集桌面聲音儲存為pcm

ffmpeg4教程2:採集桌面聲音儲存為pcm

基於vs2017 vc++  ffmpeg4.0.2下測試

ffmpeg 環境配置請百度(vs2017 ffmpeg )影象和聲音請安裝dshow便於查詢

部分方法在https://blog.csdn.net/Java_lilin/article/details/85118365中查詢

 標頭檔案參考上篇教程

static int test2() {
    
    AVFormatContext *formatCtx = avformat_alloc_context();
    AVInputFormat *ifmt = av_find_input_format("dshow");//裝置型別
    AVDictionary* options = NULL;
    //av_dict_set(&options, "video_size","1920*1080",0);//大小  預設全部
    av_dict_set(&options, "framerate", "15", 0);//幀lu

    if (avformat_open_input(&formatCtx, "audio=virtual-audio-capturer", ifmt, &options) != 0) {
    /*不通過dshow的裝置查詢
    wchar_t wt[] = L"audio=內建麥克風 (Conexant SmartAudio HD)";
    char * psDevName = dup_wchar_to_utf8(wt);
    if (avformat_open_input(&formatCtx, psDevName, ifmt, &options) != 0) {
    */


        printf("open input device fail\n");
        return -1;
    }
    av_dict_free(&options);

    if (avformat_find_stream_info(formatCtx, NULL) < 0) {
        printf("avformat_find_stream_info faill\n");
        return -1;
    }
    if (formatCtx->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) {
        printf("no find stream info\n");
        return -1;
    }
    //查詢解密器
    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("codec not open\n");
        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);
    //目標
    ctx->channel_layout = av_get_default_channel_layout(ctx->channels); 
    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 desc_channel_layout = 3;
    int desc_channel_count = 2;
    int desc_sample_rate = 44100;
    AVSampleFormat desc_fmt = AV_SAMPLE_FMT_S16;
    av_opt_set_int(swr, "out_channel_count", desc_channel_count, 0);
    av_opt_set_int(swr, "out_channel_layout", desc_channel_layout, 0);
    av_opt_set_int(swr, "out_sample_rate", desc_sample_rate, 0);
    av_opt_set_sample_fmt(swr, "out_sample_fmt", desc_fmt, 0);

    printf("\n聲道%d,取樣率%d格式%d----》聲道%d,取樣率%d格式%d\n",  ctx->channels,ctx->sample_rate,
        ctx->sample_fmt, desc_channel_count, desc_sample_rate, desc_fmt);
    int DES_NB_SAMPLES = 1024;
    AVFrame *outframe = alloc_audio_frame(desc_fmt, desc_channel_layout, desc_channel_count, desc_sample_rate, DES_NB_SAMPLES);
    AVFrame *newframe = alloc_audio_frame(desc_fmt, desc_channel_layout, desc_channel_count, desc_sample_rate, 0);
    AVFrame *newframe2= alloc_audio_frame(desc_fmt, desc_channel_layout, desc_channel_count, desc_sample_rate, 0);

    AVAudioFifo *fifo = av_audio_fifo_alloc(desc_fmt, desc_channel_count,10240);
    
    FILE *file = NULL;
    fopen_s(&file, "C:\\Users\\lilin\\Desktop\\1.pcm","wb");//ffplay -ar 44100 -channels 2 -f s16le -i 1.pcm或用Audacity 播放

    int fnum = 500;
    while (fnum--) {
        int size = av_audio_fifo_size(fifo);
        if (size >= DES_NB_SAMPLES) {//超過
            printf("\n第一次超過\n");
            size = DES_NB_SAMPLES;
            av_audio_fifo_read(fifo, (void**)outframe->data, size);
            //完整
            
            //寫檔案
            fwrite(outframe->data[0],size,desc_channel_count*av_get_bytes_per_sample(desc_fmt),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("audio decode error\n");
            }
            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, desc_sample_rate); 
                if(dealy>0){
                    swr_convert_frame(swr, newframe2,NULL);
                    av_audio_fifo_write(fifo, (void**)newframe2->data, newframe2->nb_samples);
                }
                //這裡可以判斷下fifo裡的數量是否夠1024
                int size = av_audio_fifo_size(fifo);
                if (size < DES_NB_SAMPLES) {
                    //資料不夠
                    av_packet_unref(&packet);
                    continue;
                }
                size = DES_NB_SAMPLES;//夠了
                av_audio_fifo_read(fifo, (void**)outframe->data,size);//固定大小的
                 
                //寫檔案
                fwrite(outframe->data[0], size, desc_channel_count*av_get_bytes_per_sample(desc_fmt), file);

            }

        }
        av_packet_unref(&packet);
    }

    av_frame_free(&frame);
    av_frame_free(&newframe);
    av_frame_free(&newframe2);
    av_frame_free(&outframe);
    av_audio_fifo_free(fifo);
    avcodec_free_context(&ctx);
    avformat_close_input(&formatCtx);

    fclose(file);
    return 0;
}

 

 

int main(){

    printf("ok:%d\n", avcodec_version());
    avdevice_register_all(); 

   test2();

}

討論群261074724