【MediaFoundation】OpenCV VideoCapture 读取音频源码

OpenCV 读取音频代码实例

在windows7 以及OpenCV4 过后可以使用 CAP_MSMF 读取音频,但是OpenCV没有播放音频的API。代码示例如下。 本文解析OpenCVCAP_MSMF 进行文件、设备的 音频读取,学习MediaFoundation 的使用。

cpp 复制代码
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main(int argc, const char** argv)
{
    Mat videoFrame;
    Mat audioFrame;
    vector<vector<Mat>> audioData;
    VideoCapture cap;
    vector<int> params {    CAP_PROP_AUDIO_STREAM, 0,
                            CAP_PROP_VIDEO_STREAM, -1,
                            CAP_PROP_AUDIO_DATA_DEPTH, CV_32F   };

    //cap.open(file, CAP_MSMF, params);
    // 打开第一个音频输入设备
    cap.open(0, CAP_MSMF, params);

    if (!cap.isOpened())
    {
        cerr << "ERROR! Can't to open file: " + file << endl;
        return -1;
    }

    const int audioBaseIndex = (int)cap.get(CAP_PROP_AUDIO_BASE_INDEX);
    const int numberOfChannels = (int)cap.get(CAP_PROP_AUDIO_TOTAL_CHANNELS);
    cout << "CAP_PROP_AUDIO_DATA_DEPTH: " << depthToString((int)cap.get(CAP_PROP_AUDIO_DATA_DEPTH)) << endl;
    cout << "CAP_PROP_AUDIO_SAMPLES_PER_SECOND: " << cap.get(CAP_PROP_AUDIO_SAMPLES_PER_SECOND) << endl;
    cout << "CAP_PROP_AUDIO_TOTAL_CHANNELS: " << cap.get(CAP_PROP_AUDIO_TOTAL_CHANNELS) << endl;
    cout << "CAP_PROP_AUDIO_TOTAL_STREAMS: " << cap.get(CAP_PROP_AUDIO_TOTAL_STREAMS) << endl;

    int numberOfSamples = 0;
    int numberOfFrames = 0;
    audioData.resize(numberOfChannels);
    mfcap::AudioOutput audioOutput;
    audioOutput.Open((int)cap.get(CAP_PROP_AUDIO_TOTAL_CHANNELS),
                     (int)cap.get(CAP_PROP_AUDIO_SAMPLES_PER_SECOND),
                     16);
    
    for (;;)
    {
        if (cap.grab())
        {
            //cap.retrieve(videoFrame);
            std::vector<const unsigned char*> planes;
            planes.resize(numberOfChannels);
            for (int nCh = 0; nCh < numberOfChannels; nCh++)
            {
                cap.retrieve(audioFrame, audioBaseIndex+nCh);
                if (!audioFrame.empty())
                {
                    audioData[nCh].push_back(audioFrame);
                    //planes[nCh] = audioFrame.data + nCh * audioFrame.cols;
                }
                numberOfSamples+=audioFrame.cols;
            }
        } else { break; }
    }

    cout << "Number of audio samples: " << numberOfSamples << endl
         << "Number of video frames: " << numberOfFrames << endl;
    return 0;
}

打开设备

cpp 复制代码
bool CvCapture_MSMF::open(int index, const cv::VideoCaptureParameters* params)
{
	// 先重置环境
    close();
    if (index < 0)
        return false;

    if (params)
    {
    	// 开启硬件编解码加速,这里先省略,在后面的硬件加速上学习。
        configureHW(*params);

		/* configureStream 主要是配置是否捕获音频或视频流
		// 如果需要捕获音频流: audioStream = 0 否者 audioStream  = -1
		// 视频流同理,对应的变量为: videoStream
		*/
		
		/* setAudioProperties 
		// outputAudioFormat: 音频的位深, CV_16S 等
		// audioSamplesPerSecond 采样率
		// syncLastFrame: 是否需要音视频同步,OpenCV里面只支持视频文件的音视频同步
		*/
        if (!(configureStreams(*params) && setAudioProperties(*params)))
            return false;
    }
	
	// 仅支持打开音频流或者视频流,不能在一个对象里面打开或者都不打开。
    if (videoStream != -1 && audioStream != -1 || videoStream == -1 && audioStream == -1)
    {
        CV_LOG_DEBUG(NULL, "Only one of the properties CAP_PROP_AUDIO_STREAM " << audioStream << " and " << CAP_PROP_VIDEO_STREAM << " must be different from -1");
        return false;
    }
    DeviceList devices;
    UINT32 count = 0;
    if (audioStream != -1)
        count = devices.read(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID);
    if (videoStream != -1)
        count = devices.read(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
    if (count == 0 || static_cast<UINT32>(index) > count)
    {
        CV_LOG_DEBUG(NULL, "Device " << index << " not found (total " << count << " devices)");
        return false;
    }
    _ComPtr<IMFAttributes> attr = getDefaultSourceConfig();
    _ComPtr<IMFSourceReaderCallback> cb = new SourceReaderCB();
    attr->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, cb.Get());
    _ComPtr<IMFMediaSource> src = devices.activateSource(index);
    if (!src.Get() || FAILED(MFCreateSourceReaderFromMediaSource(src.Get(), attr.Get(), &videoFileSource)))
    {
        CV_LOG_DEBUG(NULL, "Failed to create source reader");
        return false;
    }

    isOpen = true;
    device_status = true;
    camid = index;
    readCallback = cb;
    duration = 0;
    if (configureOutput())
    {
        frameStep = captureVideoFormat.getFrameStep();
    }
    if (isOpen && !openFinalize_(params))
    {
        close();
        return false;
    }
    if (isOpen)
    {
        if (audioStream != -1)
            if (!checkAudioProperties())
                return false;
    }

    return isOpen;
}
相关推荐
春日见12 分钟前
丝滑快速拓展随机树 S-RRT(Smoothly RRT)算法核心原理与完整流程
人工智能·算法·机器学习·路径规划算法·s-rrt
陈文锦丫2 小时前
MixFormer: A Mixed CNN–Transformer Backbone
人工智能·cnn·transformer
小毅&Nora3 小时前
【人工智能】【AI外呼】系统架构设计与实现详解
人工智能·系统架构·ai外呼
顾道长生'3 小时前
(Arxiv-2025)ID-COMPOSER:具有分层身份保持的多主体视频合成
计算机视觉·音视频·composer
jianqiang.xue3 小时前
别把 Scratch 当 “动画玩具”!图形化编程是算法思维的最佳启蒙
人工智能·算法·青少年编程·机器人·少儿编程
Coding茶水间4 小时前
基于深度学习的安全帽检测系统演示与介绍(YOLOv12/v11/v8/v5模型+Pyqt5界面+训练代码+数据集)
图像处理·人工智能·深度学习·yolo·目标检测·计算机视觉
weixin79893765432...4 小时前
Vue + Express + DeepSeek 实现一个简单的对话式 AI 应用
vue.js·人工智能·express
nju_spy5 小时前
ToT与ReAct:突破大模型推理能力瓶颈
人工智能·大模型·大模型推理·tot思维树·react推理行动·人工智能决策·ai推理引擎
AI-智能5 小时前
别啃文档了!3 分钟带小白跑完 Dify 全链路:从 0 到第一个 AI 工作流
人工智能·python·自然语言处理·llm·embedding·agent·rag
y***86695 小时前
C机器学习.NET生态库应用
人工智能·机器学习