<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      FFmpeg開發筆記(十二):ffmpeg音頻處理、采集麥克風音頻錄音為WAV - 指南

      若該文為原創文章,轉載請注明原文出處
      本文章博客地址:https://blog.csdn.net/qq21497936/article/details/152651085
      各位讀者,知識無窮而人力有窮,要么改需求,要么找專業人士,要么自己研究

      長沙紅胖子Qt(長沙創微智科)博文大全:開發技術集合(包含Qt實用技術、樹莓派、三維、OpenCV、OpenGL、ffmpeg、OSG、單片機、軟硬結合等等)持續更新中…

      FFmpeg和SDL開發專欄(點擊傳送門)

      上一篇:《FFmpeg開發筆記(十一):ffmpeg移植到海思HI35xx平臺之將ffmpeg庫引入到sample的demo中
      下一篇:敬請期待…

      前言

      ??ffmpeg采集音頻是一塊很重要也復雜的,本篇描述了錄音麥克風為pcm封裝成wav。


      使用ffmpeg命令行獲取設備列表

      ??ffmpeg 會列出所有可用的視頻和音頻設備。其中音頻設備會在 “DirectShow audio devices"”標題下顯示

      ffmpeg -list_devices true -f dshow -i dummy

      在這里插入圖片描述

      ??發現輸出的是亂碼(中文在cmd上的輸出),

      chcp 56001

      ??65001 是 UTF-8 編碼的代碼頁
      在這里插入圖片描述

      在這里插入圖片描述

      ??以上2個沒有麥(系統自己的,沒插入麥),使用usb的:
      在這里插入圖片描述

      在這里插入圖片描述


      音頻

      音頻源(Audio Source)

      ??音頻源指FFmpeg獲取聲音數據的來源,是錄制的 “起點”。常見的音頻源主要分為兩類:

      • 硬件音頻源:直接從計算機硬件設備采集聲音,如麥克風(通過聲卡輸入接口)、線路輸入(Line-In,用于連接外部設備如錄音機、吉他等)。在不同操作系統中,硬件音頻源的標識方式不同,例如 Windows 下通過 “麥克風陣列”“線路輸入” 等設備名識別,Linux 下通過 ALSA(Advanced Linux Sound Architecture)或 PulseAudio 的設備節點(如hw:0,0)標識,macOS 則依賴 Core Audio 架構的設備 ID。
      • 軟件音頻源:從系統內部或其他軟件中捕獲音頻,如錄制瀏覽器播放的音樂、視頻會議的聲音等。這種場景需要依賴 “虛擬音頻設備”(如 Windows 的 “立體聲混音”、macOS 的 Soundflower、Linux 的 PulseAudio Loopback),將系統輸出的音頻重新作為輸入源提供給 FFmpeg。

      音頻編解碼器(Audio Codec)

      ??編解碼器(Codec,即 Coder-Decoder)是處理音頻數據的核心組件,負責將原始音頻采樣數據壓縮(編碼)為特定格式的文件,或解壓(解碼)為可播放的原始數據。在錄制場景中,我們主要關注 “編碼器”,它直接影響錄制文件的體積、音質與兼容性。
      ??FFmpeg 支持幾乎所有主流音頻編碼器,常見的包括:

      • PCM(脈沖編碼調制):無壓縮編碼,直接存儲原始音頻采樣數據,音質最佳但文件體積極大(例如 44.1kHz、16 位、立體聲的 PCM 音頻,每分鐘約 10MB),常見于 WAV 格式文件。
      • MP3(MPEG-1 Audio Layer III):有損壓縮編碼,通過舍棄人耳不敏感的音頻頻段實現高壓縮比,是目前最普及的音頻格式之一,比特率通常在 128-320kbps 之間(320kbps 接近無損音質)。
      • AAC(Advanced Audio Coding):有損壓縮編碼,性能優于 MP3,在相同比特率下音質更優,廣泛用于 MP4、MOV 等視頻文件及流媒體場景(如 YouTube、抖音)。
      • FLAC(Free Lossless Audio Codec):無損壓縮編碼,在保留原始音質的前提下壓縮文件體積(壓縮比約 1:2),適合對音質要求極高的場景(如音樂制作、無損音樂收藏)。

      音頻采樣參數

      ??采樣參數決定了音頻的 “精度” 與 “范圍”,是影響音質的核心指標,主要包括以下三個:

      • 采樣率(Sample Rate):單位時間內對音頻信號的采樣次數,單位為赫茲(Hz)。采樣率越高,越能還原高頻聲音,音質越細膩。常見的采樣率有: 44.1kHz:CD 音質的標準采樣率,能覆蓋人耳可聽范圍(20Hz-20kHz); 48kHz:專業音頻制作與視頻配套音頻的常用采樣率; 96kHz/192kHz:高解析度音頻(Hi-Res)的采樣率,適合高端音頻設備。
      • 采樣位深(Sample Bit Depth):每個采樣點用多少位二進制數表示,決定了音頻的動態范圍(即最大音量與最小音量的差值)。位深越大,動態范圍越廣,聲音的層次感越強。常見的位深有 16 位(CD 標準,動態范圍約 96dB)、24 位(專業制作標準,動態范圍約 144dB)。
      • 聲道數(Channels):音頻信號的通道數量,決定了聲音的空間感。常見的聲道模式有: 單聲道(Mono,1 聲道):適合語音錄制(如 podcasts、語音備忘錄); 立體聲(Stereo,2 聲道):左右聲道分別傳輸不同信號,營造空間感,適合音樂、影視音頻; 多聲道(如 5.1、7.1 聲道):用于環繞聲系統,常見于電影音頻。

      容器格式(Container Format)

      ??容器格式(也稱封裝格式)是用于存儲音頻、視頻、字幕等多種數據流的文件格式,它不負責數據壓縮,僅規定數據的存儲結構。在音頻錄制中,容器格式需與編碼器匹配,常見的組合如下:

      • WAV + PCM:無壓縮音頻的標準組合,兼容性強但體積大;
      • MP3 + MP3:有損音頻的主流組合,僅支持 MP3 編碼;
      • MP4 + AAC:視頻配套音頻或純音頻的常用組合,兼容性好且體積小;
      • FLAC + FLAC:無損音頻的主流組合,保留音質的同時壓縮體積。

      錄音流程

      ??FFmpeg 通過 “輸入設備→采集原始壓縮數據包AVPacket→封裝Wav”三個步驟,將音頻源的信號轉化為目標音頻文件,具體流程如下:

      步驟一:設備探測與選擇

      ??FFmpeg 首先通過操作系統的音頻接口(如 Windows 的 DirectSound、Linux 的 ALSA、macOS 的 Core Audio)探測可用的音頻輸入設備,用戶通過命令行參數指定要使用的設備(如-f dshow -i audio=“麥克風陣列”)。

      步驟二:音頻采集與原始壓縮數據獲取AVPacket

      ??選定設備后,FFmpeg 按照指定的采樣參數(采樣率、位深、聲道數)從設備中讀取原始 PCM 壓縮數據。這一步是 “無損” 的,數據直接來自硬件或虛擬設備的輸出。

      步驟三:pcm壓縮數據支持.wav格式封裝,直接存為目標文件

      ??編碼后的音頻數據流會被寫入指定的容器格式(如 MP3、MP4)中,同時生成文件頭、索引等元數據,最終形成可播放的音頻文件。
      ??注意:本篇沒有重采樣和壓縮,直接存儲的WAV+PCM。


      Demo源碼

      void FFmpegManager::testCaptureAudio()
      {
      // 命令行,查看本地可用的音頻設備列表
      // linux  :  ffmpeg -list_devices true -f alsa -i dummy
      //
      // windows:  ffmpeg -list_devices true -f dshow -i dummy
      //           Windows 系統下通過 DirectShow 接口訪問音頻設備的場景。
      //  "麥克風 (Realtek(R) Audio)"
      //  "麥克風 (USB Audio Device)" 使用本設備
      //  "立體聲混音 (Realtek(R) Audio)"
      //
      // windows錄制音頻測試: ffmpeg -f dshow -i audio="麥克風 (USB Audio Device)" output.wav
      //
      // ffmpeg相關變量預先定義與分配
      AVFormatContext *pAVFormatContext = 0;          // ffmpeg的全局上下文,所有ffmpeg操作都需要
      AVInputFormat * pAVInputFormat = 0;             // ffmpeg輸入類型格式
      AVStream *pAVStream = 0;                        // ffmpeg流信息
      AVCodecParameters *pAVCodecParameters;          // ffmpeg解碼器參數
      AVCodecContext *pAVCodecContext = 0;            // ffmpeg編碼上下文
      AVCodec *pAVCodec = 0;                          // ffmpeg編碼器
      AVPacket *pAVPacket = 0;                        // ffmpag單幀數據包
      int ret = 0;                                    // 函數執行結果
      int audioIndex = -1;                            // 音頻流所在的序號
      // 步驟一: 注冊ffmpeg所有組件
      av_register_all();                              // 初始化所有組件(只使用這個,找不到dshow)
      avdevice_register_all();                        // 顯示注冊所有設備
      avcodec_register_all();                         // 顯式注冊所有編解碼器
      // 步驟二:設置設備輸入格式未dshow
      pAVInputFormat = av_find_input_format("dshow");
      if(!pAVInputFormat)
      {
      LOG << "Failed to av_find_input_format(\"dshow\")";
      return;
      }
      {
      #if 0
      // 探測輸入設備代碼: 使用代碼探測所有設備并輸出
      //        AVInputFormat * pAVInputFormat = av_find_input_format("dshow");
      AVDeviceInfoList * pAVDeviceInfoList = 0;
      ret = avdevice_list_input_sources(pAVInputFormat, 0, 0, &pAVDeviceInfoList);
      if(ret < 0)
      {
      char err_buf[1024];
      av_strerror(ret, err_buf, sizeof(err_buf));
      LOG << QSTRING("無法列出設備: ") << QSTRING(err_buf) << QSTRING("(錯誤代碼:") << ret << ")";
      return;
      }
      for(int index = 0; index < pAVDeviceInfoList->nb_devices; index++)
        {
        std::string deviceName = pAVDeviceInfoList->devices[index]->device_name;
        LOG << QString(deviceName.data());
        }
        avdevice_free_list_devices(&pAVDeviceInfoList);
        #endif
        }
        // 步驟三: 設置輸入設備
        #if 1
        QString deviceStr = QSTRING("audio=%1").arg(QSTRING("麥克風 (USB Audio Device)"));
        // 步驟四: 打開輸入設備
        ret = avformat_open_input(&pAVFormatContext, deviceStr.toUtf8().constData(), pAVInputFormat, 0);
        if(ret < 0)
        {
        LOG << "Failed to open avformat_open_input:" << deviceStr;
        return;
        }
        LOG << "Suceed to open avformat_open_input:" << deviceStr;
        #else
        std::string deviceName = "麥克風 (USB Audio Device)";
        std::string deviceArg = "audio=" + deviceName;
        // 步驟四: 打開輸入設備
        ret = avformat_open_input(&pAVFormatContext, deviceArg.c_str(), pAVInputFormat, 0);
        if(ret < 0)
        {
        LOG << "Failed to open avformat_open_input:" << QString(deviceName.data());
        return;
        }
        #endif
        // 步驟五: 查找流信息, 提取音頻
        for(int index = 0; index < pAVFormatContext->nb_streams; index++)
          {
          pAVCodecContext = pAVFormatContext->streams[index]->codec;
          pAVStream = pAVFormatContext->streams[index];
          switch (pAVCodecContext->codec_type)
          {
          case AVMEDIA_TYPE_UNKNOWN:
          LOG << QSTRING("流序號: %1 類型為: AVMEDIA_TYPE_UNKNOWN").arg(index);
          break;
          case AVMEDIA_TYPE_VIDEO:
          LOG << QSTRING("流序號: %1 類型為: AVMEDIA_TYPE_VIDEO").arg(index);
          break;
          case AVMEDIA_TYPE_AUDIO:
          audioIndex = index;
          LOG << QSTRING("流序號: %1 類型為: AVMEDIA_TYPE_AUDIO").arg(index);
          break;
          case AVMEDIA_TYPE_DATA:
          LOG << QSTRING("流序號: %1 類型為: AVMEDIA_TYPE_DATA").arg(index);
          break;
          case AVMEDIA_TYPE_SUBTITLE:
          LOG << QSTRING("流序號: %1 類型為: AVMEDIA_TYPE_SUBTITLE").arg(index);
          break;
          case AVMEDIA_TYPE_ATTACHMENT:
          LOG << QSTRING("流序號: %1 類型為: AVMEDIA_TYPE_ATTACHMENT").arg(index);
          break;
          case AVMEDIA_TYPE_NB:
          LOG << QSTRING("流序號: %1 類型為: AVMEDIA_TYPE_NB").arg(index);
          break;
          default:
          break;
          }
          // 已經找打視頻品流
          if(audioIndex != -1)
          {
          break;
          }
          }
          if(audioIndex == -1 || !pAVCodecContext)
          {
          LOG << "Failed to find video stream";
          return;
          }
          LOG << "Succeed to find audio stream";
          // 步驟六:獲取解碼器參數
          pAVCodecParameters = pAVFormatContext->streams[audioIndex]->codecpar;
          // 步驟七:查找解碼器
          LOG << "AVCodecID" << pAVCodecParameters->codec_id << pAVCodecContext->codec_id;
            LOG << "AV_CODEC_ID_PCM_S16LE =" << AV_CODEC_ID_PCM_S16LE;
            pAVCodec = avcodec_find_decoder(pAVCodecParameters->codec_id);
            if(!pAVCodec)
            {
            LOG << "Failed to avcodec_find_decoder(pAVCodecContext->codec_id):"
              << pAVCodecContext->codec_id;
                return;
                }
                // 步驟八: 打開解碼器
                ret = avcodec_open2(pAVCodecContext, pAVCodec, NULL);
                if(ret < 0)
                {
                LOG << "Failed to avcodec_open2(pAVCodecContext, pAVCodec, NULL);";
                return;
                }
                #if 1
                // 打印音頻信息
                LOG << QSTRING("音頻信息 采樣率: %1Hz  聲道數: %2  采樣格式: %3")
                .arg(pAVCodecContext->sample_rate)
                .arg(pAVCodecContext->channels)
                .arg(av_get_sample_fmt_name(pAVCodecContext->sample_fmt));
                #endif
                // 只能wav格式,這個demo
                QString fileName = "1.wav";
                //    QString fileName = "1.aac"; // 錄制無法播放
                // 步驟九: 創建輸出上下文
                AVFormatContext *pAVFormatContextOut = 0;
                ret = avformat_alloc_output_context2(&pAVFormatContextOut, 0, 0, fileName.toUtf8().data());
                if(ret < 0)
                {
                LOG << QSTRING("無法創建輸出上下文");
                return;
                }
                // 步驟十: 創建輸出流
                AVStream *pAVStreamOut = 0;                     // ffmpeg流信息(輸出)
                pAVStreamOut = avformat_new_stream(pAVFormatContextOut, 0);
                if(!pAVStreamOut)
                {
                LOG << QSTRING("無法創建輸出流");
                return;
                }
                // 步驟十:復制編碼器信息
                ret = avcodec_parameters_copy(pAVStreamOut->codecpar, pAVCodecParameters);
                if(ret < 0)
                {
                LOG << QSTRING("復制編碼器失敗");
                return;
                }
                #if 0
                // 步驟十一: 設置輸出編碼器參數(想要別的就修改)
                pAVStreamOut->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE;
                pAVStreamOut->codecpar->sample_rate = 44100;
                //    pAVStreamOut->codecpar->sample_rate = 22050;    // 聲音會變得慢低,時間翻倍,
                //    pAVStreamOut->codecpar->sample_rate = 88200;    // 生意會變快尖,時間減半
                pAVStreamOut->codecpar->channels = 2;
                //    pAVStreamOut->codecpar->channels = 1;   // 聲音會變的慢低,時間翻倍
                //    pAVStreamOut->codecpar->channels = 4;   // 聲音會變的快尖,時間減半
                #endif
                // 步驟十二: 創建輸出文件
                ret = avio_open(&pAVFormatContextOut->pb, fileName.toUtf8().data(), AVIO_FLAG_WRITE);
                if(ret < 0)
                {
                LOG << QSTRING("無法開輸出文件");
                return;
                }
                LOG;
                // 步驟十三:寫入頭文件
                ret = avformat_write_header(pAVFormatContextOut, 0);
                LOG;
                if(ret < 0)
                {
                LOG << QSTRING("寫入頭文件失敗");
                return;
                }
                LOG;
                // 步驟十四:錄制循環
                LOG << QSTRING("開始錄制...");
                int frames = 0;
                pAVPacket = av_packet_alloc();
                QElapsedTimer elapsedTimer;
                elapsedTimer.start();
                while(elapsedTimer.elapsed() < 10 * 1000)
                {
                LOG;
                // 步驟十五:讀取一幀音頻數據
                ret = av_read_frame(pAVFormatContext, pAVPacket);
                LOG;
                if(ret < 0)
                {
                LOG << QSTRING("讀取數據包失敗");
                if(ret == AVERROR_EOF)
                {
                break;
                }
                return;
                }
                // 步驟十六:是音頻流則進行時間戳調整
                if(pAVPacket->stream_index == audioIndex)
                {
                // 調整時間戳
                pAVPacket->stream_index = 0;
                av_packet_rescale_ts(pAVPacket,
                pAVFormatContext->streams[audioIndex]->time_base,
                pAVStreamOut->time_base);
                pAVPacket->pos = -1;
                // 寫入數據包
                ret = av_interleaved_write_frame(pAVFormatContextOut, pAVPacket);
                if (ret < 0)
                {
                LOG << QSTRING("寫入數據包失敗:") << ret;
                break;
                }
                frames++;
                }
                av_packet_unref(pAVPacket);
                }
                // 步驟十五: 寫入文件尾巴
                av_write_trailer(pAVFormatContextOut);
                av_packet_free(&pAVPacket);
                avformat_close_input(&pAVFormatContext);
                avio_closep(&pAVFormatContextOut->pb);
                avformat_free_context(pAVFormatContext);
                LOG << QSTRING("錄制完成! 已保存到") << fileName;
                LOG << QSTRING("共寫入 %1 個音頻幀").arg(frames);
                }

      工程模板v1.6.0

      在這里插入圖片描述


      入坑

      入坑一:ffmpeg命令行輸出中文設備亂碼

      問題

      在這里插入圖片描述

      原因

      ??在 Windows 的命令提示符(CMD)中使用 ffmpeg 時出現中文亂碼,通常是由于編碼不匹配導致的,測試改成uft-8即可。

      解決

      chcp 65001

      在這里插入圖片描述

      入坑二:ffmpeg代碼獲取設備失敗

      問題

      ??Ffmpeg代碼獲取失敗,為0。
      在這里插入圖片描述

      原因

      ??代碼exe獲取設備在win10上是需要管理員權限的,無效;
      在這里插入圖片描述

      ??打印錯誤代碼:
      在這里插入圖片描述

      在這里插入圖片描述

      在這里插入圖片描述

      ??ENOSYS(錯誤碼 40)本質上是 FFmpeg 告訴你:“我不認識這個設備類型,因為編譯時沒加支持”。解決的核心是確保 FFmpeg 包含對應平臺的設備模塊,并在代碼中使用正確的設備格式。

      思考

      ??可能是編譯的時候沒編譯dshow進去?但是通過dshow去獲取輸入接口又是可以,只是拿列表不行。
      在這里插入圖片描述

      ??查找編譯參數:

      ffmpeg -buildconf

      在這里插入圖片描述

      ??Windows:尋找 --enable-dshow(DirectShow 設備支持),Linux:尋找 --enable-alsa(ALSA 音頻設備)或 --enable-v4l2(視頻設備)。
      ??沒有編譯進去,那就是。

      解決

      ??未解決,不深究,有興趣讀者可以深入嘗試并交流結果。

      入坑三:ffmpeg打開音頻獲取解碼器失敗

      問題

      ??找不到編碼器。
      在這里插入圖片描述

      在這里插入圖片描述

      嘗試一:列出設備

      ffmpeg -f dshow -i audio="麥克風 (USB Audio Device)" -v debug -t 1 NUL

      在這里插入圖片描述

      在這里插入圖片描述

      嘗試二:切換msvc版本

      ??嘗試切換版本后,打開設備都失敗:
      在這里插入圖片描述

      ??列出設備也失敗,可能就不是版本問題,應該要能列出來。
      ??使用ffmpeg錄音測試,發現msvc版本的ffmpeg(預編譯)可以錄音,而mingw32的ffmpeg(自編譯)不可以錄音:
      在這里插入圖片描述

      ??錄音后打開,發現正常錄制了,下面的是mingw32都無法錄音:
      在這里插入圖片描述

      ??所以懷疑還是版本問題,再次切換至msvc,上面的問題有可能是編碼問題?
      ??搭建號環境后,再次ffmpeg命令行錄音并播放測試:
      在這里插入圖片描述

      ??確認沒有問題,庫是沒問題的,查看代碼運行:
      ??無法列出設備:
      在這里插入圖片描述

      ??編碼切換可以打開設備,也有數據流,但是拿不到解碼器還是:
      在這里插入圖片描述

      在這里插入圖片描述

      ??定位解碼器:
      在這里插入圖片描述

      ffmpeg -codecs

      在這里插入圖片描述

      在這里插入圖片描述

      ??是有的,但是無法通過設備去拿到這個id?
      在這里插入圖片描述

      ??id是對的,鬧烏龍,以為65535是越界,但是更加奇怪,都已經有這個id了,為什么打開其編碼器是失敗的呢?
      ??測試獲取其編碼器和解碼器都失敗:
      在這里插入圖片描述

      在這里插入圖片描述

      ??就好像根本找不到這個一樣。

      ffmpeg -encoders

      在這里插入圖片描述

      ffmpeg -decoders

      在這里插入圖片描述

      ??原地蒙了?沒注冊,試了下,是沒注冊:
      在這里插入圖片描述

      ??測試是否可以獲取設備列表了:
      在這里插入圖片描述

      ??還是不行,查閱細化:
      在這里插入圖片描述

      ??功能未實現。

      解決方式

      ??注冊即可`

      // 步驟一: 注冊ffmpeg所有組件
      av_register_all();                              // 初始化所有組件(只使用這個,找不到dshow)
      avdevice_register_all();                        // 顯示注冊所有設備
      avcodec_register_all();                        // 顯式注冊所有編解碼器

      上一篇:《FFmpeg開發筆記(十一):ffmpeg移植到海思HI35xx平臺之將ffmpeg庫引入到sample的demo中
      下一篇:敬請期待…


      本文章博客地址:https://blog.csdn.net/qq21497936/article/details/152651085

      posted @ 2025-11-04 15:29  yangykaifa  閱讀(7)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 日韩放荡少妇无码视频| 中文字幕无码不卡一区二区三区| 亚洲AV无码久久久久网站蜜桃| 亚洲精品熟女一区二区| 国产小受被做到哭咬床单GV| 免费看女人与善牲交| 人妻av无码一区二区三区| 亚洲精品成人久久av| 亚洲av激情五月性综合| 久久久国产乱子伦精品作者| 久久国产热这里只有精品| 亚洲综合精品第一页| 亚洲男女羞羞无遮挡久久丫| 人人澡人摸人人添| 国产影片AV级毛片特别刺激| 久青草精品视频在线观看| 中文字幕亚洲制服在线看| 色综合亚洲一区二区小说| 亚洲成av一区二区三区| 欧美成人午夜在线观看视频| 国产主播精品福利午夜二区| 99久久免费精品色老| 91精品久久一区二区三区| 国产成人女人在线观看| 国产精品最新免费视频| 乱熟女高潮一区二区在线| 亚洲中文字幕综合网在线| 美女禁区a级全片免费观看| 国产中文字幕久久黄色片| 久久中精品中文字幕入口| 漂亮人妻被强中文字幕久久| 和龙市| 一区二区三区四区精品黄| 亚洲av成人一区在线| 无码AV无码免费一区二区 | 美腿丝袜亚洲综合第一页| 国产精品区一区第一页| gogo无码大胆啪啪艺术| 免费无码va一区二区三区| 国产色无码专区在线观看| 起碰免费公开97在线视频|