《Windows API每日一练》23.1 Windows多媒体

本节我们将讲述单线程到多线程的演进过程,以及进程与线程的区别。

本节必须掌握的知识点:

        多媒体硬件

        API 概述

        第172练:交互输入MCI命令

23.1.1多媒体硬件

多媒体硬件是指用于处理音频、视频和其他多媒体内容的硬件设备。在计算机系统中,常见的多媒体硬件包括:

●声卡(音频设备):声卡是用于处理和播放音频的硬件设备。它包括音频输入和输出接口,用于连接麦克风、扬声器、耳机等外部音频设备。声卡通常包含音频处理器和数字模拟转换器(DAC),用于将数字音频信号转换为模拟信号以供扬声器播放。

●显卡(视频设备):显卡是用于处理和显示图像和视频的硬件设备。它包括图形处理器(GPU)和视频输出接口(如HDMI、VGA、DisplayPort等),用于将图像和视频信号发送到显示器。显卡能够加速图形渲染和视频解码,提供流畅的图形和视频体验。

●摄像头:摄像头是用于捕捉视频和图像的设备。它通常包含图像传感器、图像处理器和接口,用于捕捉、处理和传输视频数据。摄像头广泛应用于视频通话、视频会议、监控系统等场景。

●麦克风和扬声器:麦克风用于捕捉声音和语音,而扬声器用于播放声音。这些设备通常与声卡或音频接口连接,用于音频输入和输出。

除了上述硬件设备,还有其他多媒体相关的设备,如光驱(用于读取光盘中的音频和视频内容)、投影仪(用于投影图像和视频)、电视卡(用于接收和播放电视信号)等。

多媒体硬件与操作系统之间通过驱动程序进行交互。操作系统提供相应的驱动程序接口,用于控制和管理多媒体硬件设备,以及提供对硬件功能的访问和控制。

开发人员可以使用操作系统提供的多媒体API和库,或者使用专门的多媒体开发工具包(如DirectX、Media Foundation等)与多媒体硬件进行交互,实现音频、视频的采集、处理和播放等功能。

最常用的多媒体硬件大概就是波形音频设备了,通常被称为声卡。波形音频设备将麦克风输入或其他模拟音频输入转换为数字化的样本,然后把它们存储在内存中或储存为 以.WAV扩展名结尾的硬盘文件。波形音频设备也可以将波形转换回模拟声音,再通过PC 的扬声器来播放。

声卡通常还包含一个MIDI设备。MIDI是行业标准的乐器数字接口(Musical Instrument Digital Interface)。这种硬件能根据简短的二进制信息来演奏音符。MIDI硬件通常还可以通 过电缆连接到一个MIDI输入设备,如音乐键盘。此外,外部MIDI合成器往往也可以和声卡相连。

大多数现在的计算机所连接的CD-ROM驱动器,通常都能够直接播放普通的音乐CD。 这就是所谓的“CD音频“。波形音频设备、MIDI设备和CD音频设备的输出,往往混合在一起,用户通过Windows的”音量控制“设定可以控制它们的音量。

另些常见的多媒体“设备”不需要任何额外的硬件。Windows的标准视频设备(也称为AVI视频设备)可以播放以“.AVI”(audio-video interleave,音视频交叠)为扩展名的电影或动画文件。ActiveMovie控件可以播放包括QuickTime和MPEG在内的一些其他类型的电影。PC的显卡上还可能带有专门的硬件来协助播放这些电影。

23.1.2 API 概述

Windows中对多媒体功能的API支持主要分为两个集合,分别被称为“底层”接口和“高层”接口。

多媒体定时器函数

在Windows操作系统中,有一组多媒体定时器函数可用于实现高精度的定时器操作。这些函数能够提供毫秒级别的定时器精度,并且适用于多媒体应用程序和实时系统。以下是一些常用的Windows多媒体定时器函数:

●timeSetEvent: 创建一个定时器事件,用于定期触发回调函数。

UINT_PTR timeSetEvent(

  UINT          uDelay,

  UINT          uResolution,

  LPTIMECALLBACK lpTimeProc,

  DWORD_PTR     dwUser,

  UINT          fuEvent

);

uDelay: 定时器事件的延迟时间,以毫秒为单位。

uResolution: 定时器事件的最小分辨率,以毫秒为单位。

lpTimeProc: 回调函数指针,用于处理定时器事件。

dwUser: 用户自定义数据,将传递给回调函数。

fuEvent: 定时器事件的类型和选项。

●timeKillEvent: 终止先前创建的定时器事件。

MMRESULT timeKillEvent(

  UINT_PTR uTimerID

);

uTimerID: 先前创建的定时器事件的标识符。

这些多媒体定时器函数提供了一种高精度的定时器机制,可以用于实现音频、视频的同步、动画效果、实时数据处理等场景。通过创建定时器事件并指定回调函数,可以在指定的延迟时间后触发回调函数的执行。定时器事件可以定期重复执行,或者只触发一次。

【注意】这些函数是以毫秒为单位的时间间隔来操作定时器,但它们的实际精度取决于系统的能力和负载。在使用这些函数时,建议根据实际需求和系统性能进行适当的调整和测试,以确保定时器事件的精确性和可靠性。

此外,还有其他一些定时器相关的函数和结构体,如timeBeginPeriod、timeEndPeriod、TIMECAPS等,用于设置定时器的最小分辨率、获取系统定时器能力等。这些函数和结构体可以帮助开发人员更好地管理和调整定时器的行为。

“底层”接口函数

●waveInGetNumDevs:获取系统中音频输入设备的数量。

UINT waveInGetNumDevs(void);

该函数不接受任何参数。调用该函数将返回一个无符号整数(UINT),表示当前系统中可用的音频输入设备数量。

以下是使用waveInGetNumDevs函数获取音频输入设备数量的示例代码:

#include <stdio.h>

#include <mmsystem.h>

int main() {

    UINT numDevices = waveInGetNumDevs();

    printf("Number of audio input devices: %u\n", numDevices);

    return 0;

}

上述示例代码中,通过调用waveInGetNumDevs函数获取音频输入设备数量,并将结果打印到控制台。

【注意】该函数属于Windows Multimedia API,因此在编译时需要链接winmm.lib库。

●waveInGetDevCaps:获取指定音频输入设备的能力和属性。

MMRESULT waveInGetDevCaps(

  UINT_PTR       uDeviceID,

  LPWAVEINCAPS   pwic,

  UINT           cbwic

);

该函数接受三个参数:

uDeviceID: 音频输入设备的标识符,可以是从0开始的设备索引值。

pwic: 指向WAVEINCAPS结构的指针,用于接收音频输入设备的能力和属性信息。

cbwic: WAVEINCAPS结构的大小,以字节为单位。

WAVEINCAPS结构定义如下:

typedef struct wavein_caps_tag {

  WORD  wMid;                       // 厂商ID

  WORD  wPid;                        // 产品ID

  MMVERSION vDriverVersion;             // 驱动程序版本

  TCHAR szPname[MAXPNAMELEN];      // 设备名称

  DWORD dwFormats;                   // 支持的数据格式

  WORD  wChannels;                   // 支持的通道数

  WORD  wReserved1;                  // 保留字段

} WAVEINCAPS, *PWAVEINCAPS, *NPWAVEINCAPS, *LPWAVEINCAPS;

以下是使用waveInGetDevCaps函数获取音频输入设备能力和属性的示例代码:

#include <stdio.h>

#include <mmsystem.h>

int main() {

    UINT numDevices = waveInGetNumDevs();

    if (numDevices == 0) {

        printf("No audio input devices found.\n");

        return 0;

    }

    for (UINT i = 0; i < numDevices; i++) {

        WAVEINCAPS caps;

        MMRESULT result = waveInGetDevCaps(i, &caps, sizeof(caps));

        if (result == MMSYSERR_NOERROR) {

            printf("Device %u:\n", i);

            printf("  Manufacturer ID: %u\n", caps.wMid);

            printf("  Product ID: %u\n", caps.wPid);

            printf("  Driver Version: %u\n", caps.vDriverVersion);

            printf("  Device Name: %s\n", caps.szPname);

            printf("  Supported Formats: 0x%08X\n", caps.dwFormats);

            printf("  Supported Channels: %u\n", caps.wChannels);

            printf("\n");

        }

    }

    return 0;

}

上述示例代码中,首先使用waveInGetNumDevs函数获取系统中音频输入设备的数量。然后,使用循环遍历每个设备,并调用waveInGetDevCaps函数获取设备的能力和属性信息,将其打印到控制台。

●waveInOpen:打开一个音频输入设备。

MMRESULT waveInOpen(

  LPHWAVEIN       phwi,

  UINT            uDeviceID,

  LPCWAVEFORMATEX pwfx,

  DWORD_PTR       dwCallback,

  DWORD_PTR       dwCallbackInstance,

  DWORD           fdwOpen

);

该函数接受六个参数:

phwi: 指向HWAVEIN句柄的指针,用于接收打开的音频输入设备句柄。

uDeviceID: 音频输入设备的标识符,可以是从0开始的设备索引值。

pwfx: 指向WAVEFORMATEX结构的指针,定义音频流的格式。

dwCallback: 回调函数的指针,用于接收音频输入数据的回调。

dwCallbackInstance: 回调函数的实例句柄,用于标识回调函数的实例。

fdwOpen: 打开标志,用于指定打开音频输入设备的方式和特性。

WAVEFORMATEX结构定义了音频流的格式,包括采样率、位深度、通道数等信息。该结构的定义如下:

typedef struct tWAVEFORMATEX {

  WORD  wFormatTag;        // 音频数据格式

  WORD  nChannels;          // 通道数

  DWORD nSamplesPerSec;     // 采样率

  DWORD nAvgBytesPerSec;     // 平均字节率

  WORD  nBlockAlign;          // 数据块对齐方式

  WORD  wBitsPerSample;      // 位深度

  WORD  cbSize;              // 额外信息的大小

} WAVEFORMATEX, *PWAVEFORMATEX, *LPWAVEFORMATEX;

以下是使用waveInOpen函数打开音频输入设备的示例代码:

#include <stdio.h>

#include <mmsystem.h>

void CALLBACK WaveInCallback(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance,

DWORD_PTR dwParam1, DWORD_PTR dwParam2) {

    // 处理音频输入数据的回调函数

}

int main() {

    UINT numDevices = waveInGetNumDevs();

    if (numDevices == 0) {

        printf("No audio input devices found.\n");

        return 0;

    }

    // 配置音频流的格式

    WAVEFORMATEX format;

    format.wFormatTag = WAVE_FORMAT_PCM;

    format.nChannels = 2;

    format.nSamplesPerSec = 44100;

    format.nAvgBytesPerSec = format.nSamplesPerSec * format.nChannels * 2;

    format.nBlockAlign = format.nChannels * 2;

    format.wBitsPerSample = 16;

    format.cbSize = 0;

    HWAVEIN hwi;

    MMRESULT result = waveInOpen(&hwi, WAVE_MAPPER, &format,

(DWORD_PTR)WaveInCallback, 0, CALLBACK_FUNCTION);

    if (result != MMSYSERR_NOERROR) {

        printf("Failed to open audio input device.\n");

        return 0;

    }

    // 音频输入设备已成功打开,可以进行音频流捕获

    // ...

    // 关闭音频输入设备

    waveInClose(hwi);

    return 0;

}

上述示例代码中,首先使用waveInGetNumDevs函数获取系统中音频输入设备的数量。然后,配置音频流的格式,创建WAVEFORMATEX结构。接下来,调用waveInOpen函数打开音频输入设备,指定音频流的格式、回调函数等参数。如果打开成功,将获得音频输入设备的句柄(HWAVEIN)。在后续的音频流捕获过程中,可以使用该句柄进行操作。

●waveInStart:开始音频输入流的捕获。

MMRESULT waveInStart(

  HWAVEIN hwi

);

该函数接受一个参数:

hwi:要开始数据捕获的音频输入设备的句柄(HWAVEIN)。

以下是使用waveInStart函数开始音频输入设备数据捕获的示例代码:   

// 开始数据捕获

result = waveInStart(hwi);

if (result != MMSYSERR_NOERROR) {

   printf("Failed to start audio input device.\n");

   waveInClose(hwi);

   return 0;

}

●waveInStop:停止音频输入流的捕获。

MMRESULT waveInStop(

  HWAVEIN hwi

);

该函数接受一个参数:

hwi:要停止数据捕获的音频输入设备的句柄(HWAVEIN)。

以下是使用waveInStop函数停止音频输入设备数据捕获的示例代码:

// 停止数据捕获

result = waveInStop(hwi);

if (result != MMSYSERR_NOERROR) {

    printf("Failed to stop audio input device.\n");

    waveInClose(hwi);

    return 0;

}

●waveInClose:关闭先前打开的音频输入设备。

MMRESULT waveInClose(

  HWAVEIN hwi

);

该函数接受一个参数:

hwi:要关闭的音频输入设备的句柄(HWAVEIN)。

以下是使用waveInClose函数关闭音频输入设备的示例代码:

// 关闭音频输入设备

result = waveInClose(hwi);

if (result != MMSYSERR_NOERROR) {

    printf("Failed to close audio input device.\n");

    return 0;

}

●waveOutGetNumDevs:获取系统中音频输出设备的数量。

UINT waveOutGetNumDevs();

该函数没有参数。它返回一个无符号整数(UINT),表示系统中可用的音频输出设备数量。

以下是使用waveOutGetNumDevs函数获取音频输出设备数量的示例代码:

#include <stdio.h>

#include <mmsystem.h>

int main() {

    UINT numDevices = waveOutGetNumDevs();

    if (numDevices == 0) {

        printf("No audio output devices found.\n");

    } else {

        printf("Number of audio output devices: %u\n", numDevices);

    }

   

    return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值