最简单的视音频播放演示样例8:DirectSound播放PCM
=====================================================
最简单的视音频播放演示样例系列文章列表:
最简单的视音频播放演示样例3:Direct3D播放YUV,RGB(通过Surface)
最简单的视音频播放演示样例4:Direct3D播放RGB(通过Texture)
最简单的视音频播放演示样例5:OpenGL播放RGB/YUV
最简单的视音频播放演示样例6:OpenGL播放YUV420P(通过Texture,使用Shader)
最简单的视音频播放演示样例8:DirectSound播放PCM
=====================================================
本文记录DirectSound播放音频的技术。DirectSound是Windows下最常见的音频播放技术。眼下大部分的音频播放应用都是通过DirectSound来播放的。本文记录一个使用DirectSound播放PCM的样例。
注:一位仁兄已经提醒我DirectSound已经计划被XAudio2代替了。后来考证了一下发现确有此事。因此在下次更新中考虑增加XAudio2播放PCM的样例。本文仍然记录一下DirectSound这位“元老”。
DirectSound简单介绍
DirectSound是微软所开发DirectX的组件之中的一个,能够在Windows 操作系统上录音,而且记录波形音效(waveform sound)。眼下DirectSound 是一个成熟的API ,提供很多实用的功能,比如能够在较高的分辨率播放多声道声音。
DirectSound3D(DS3D)最早是1993年与 DirectX 3 一起发表的。DirectX 8以后的DirectSound和DirectSound3D的(DS3D)被合称DirectX Audio。
DirectSound有下面几种对象:
对象 |
数量 |
作用 |
主要接口 |
设备 |
每一个应用程序仅仅有一个设备对象 |
用来管理设备,创建辅助缓冲区 |
IDirectSound8 |
辅助缓冲区 |
每一个声音相应一个辅助缓冲区 |
用来管理一个静态的或者动态的声音流,然后在主缓冲区中混音 |
IDirectSoundBuffer8, IDirectSound3DBuffer8, IDirectSoundNotify8 |
主缓冲区 |
一个应用程序仅仅有一个主缓冲区 |
将辅助缓冲区的数据进行混音,而且控制3D參数. |
IDirectSoundBuffer, IDirectSound3DListener8 |
DirectSound播放音频的流程
使用DirectSound播放音频普通情况下须要例如以下步骤:
1. 初始化
1) 创建一个IDirectSound8接口的对象
2) 设置协作级
3) 创建一个主缓冲对象
4) 创建一个副缓冲对象
5) 创建通知对象
6) 设置通知位置7) 開始播放
2. 循环播放声音
1) 数据填充至副缓冲区2) 等待播放完成
下面结合具体分析一下上文的流程。
1. 初始化
1) 创建一个IDirectSound8接口的对象
通过DirectSoundCreate8()方法能够创建一个设备对象。这个对象通常代表缺省的播放设备。DirectSoundCreate8()函数原型例如以下。
- HRESULT DirectSoundCreate8(
- LPCGUID lpcGuidDevice,
- LPDIRECTSOUND8 * ppDS8,
- LPUNKNOWN pUnkOuter
- )
參数的含义例如以下:
lpcGuidDevice:要创建的设备对象的GUID。能够指定为NULL,代表默认的播放设备。
ppDS8:返回的IDirectSound8对象的地址。
pUnkOuter:必须设为NULL。
比如例如以下代码就可以创建一个IDirectSound8接口的对象
- IDirectSound8 *m_pDS=NULL;
- DirectSoundCreate8(NULL,&m_pDS,NULL);
2) 设置协作级
Windows 是一个多任务环境,同一时间有多个应用程序去訪问设备。通过使用协作级别,DirectSound能够确保应用程序不会在别的设备使用时去訪问,每一个 DirectSound应用程序都有一个协作级别,这个级别决定着訪问硬件的权限。
在创建一个设备对象以后,必须通过用IDirectSound8的SetCooperativeLevel()设置协作权限,否则将听不到声音。SetCooperativeLevel()的原型例如以下
- HRESULT SetCooperativeLevel(
- HWND hwnd,
- DWORD dwLevel
- )
參数的含义例如以下:
hwnd:应用程序窗体句柄。
dwLevel:支持下面几种级别。
DSSCL_EXCLUSIVE:与DSSCL_PRIORITY具有同样的作用。
DSSCL_NORMAL:正常的协调层级标志,其它程序可共享声卡设备进行播放。
DSSCL_PRIORITY:设置声卡设备为当前程序独占。
DSSCL_WRITEPRIMAR:可写主缓冲区,此时副缓冲区就不能进行播放处理,即不能将次缓冲区的数据送进混声器,再输出到主缓冲区上。这是最全然控制声音播放的方式。
3) 创建一个主缓冲对象
使用IDirectSound8的CreateSoundBuffer()能够创建一个IDirectSoundBuffer接口的主缓冲区对象。CreateSoundBuffer()的原型例如以下。
- HRESULT CreateSoundBuffer(
- LPCDSBUFFERDESC pcDSBufferDesc,
- LPDIRECTSOUNDBUFFER * ppDSBuffer,
- LPUNKNOWN pUnkOuter
- )
參数的含义例如以下:
pcDSBufferDesc:描写叙述声音缓冲的DSBUFFERDESC结构体的地址
ppDSBuffer:返回的IDirectSoundBuffer接口的对象的地址。
pUnkOuter:必须设置为NULL。
当中涉及到一个描写叙述声音缓冲的结构体DSBUFFERDESC,该结构体的定义例如以下:
- typedef struct _DSBUFFERDESC
- {
- DWORD dwSize;
- DWORD dwFlags;
- DWORD dwBufferBytes;
- DWORD dwReserved;
- LPWAVEFORMATEX lpwfxFormat;
- } DSBUFFERDESC
简单解释一下当中的变量的含义:
dwSize:结构体的大小。必须初始化该值。
dwFlags:设置声音缓存的属性。有非常多选项,能够组合使用,就不一一列出了。具体的參数能够查看文档。
dwBufferBytes:缓冲的大小。
dwReserved:保留參数,临时没实用。
lpwfxFormat:指向一个WAVE格式文件头的指针。
设置DSBUFFERDESC完成后,就能够使用CreateSoundBuffer()创建主缓冲了。演示样例代码例如以下:
- DSBUFFERDESC dsbd;
- memset(&dsbd,0,sizeof(dsbd));
- dsbd.dwSize=sizeof(dsbd);
- dsbd.dwFlags=DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPOSITIONNOTIFY |DSBCAPS_GETCURRENTPOSITION2;
- dsbd.dwBufferBytes=MAX_AUDIO_BUF*BUFFERNOTIFYSIZE;
- //WAVE Header
- dsbd.lpwfxFormat=(WAVEFORMATEX*)malloc(sizeof(WAVEFORMATEX));
- dsbd.lpwfxFormat->wFormatTag=WAVE_FORMAT_PCM;
- /* format type */
- (dsbd.lpwfxFormat)->nChannels=channels;
- /* number of channels (i.e. mono, stereo...) */
- (dsbd.lpwfxFormat)->nSamplesPerSec=sample_rate;
- /* sample rate */
- (dsbd.lpwfxFormat)->nAvgBytesPerSec=sample_rate*(bits_per_sample/8)*channels;
- /* for buffer estimation */
- (dsbd.lpwfxFormat)->nBlockAlign=(bits_per_sample/8)*channels;
- /* block size of data */
- (dsbd.lpwfxFormat)->wBitsPerSample=bits_per_sample;
- /* number of bits per sample of mono data */
- (dsbd.lpwfxFormat)->cbSize=0;
- //Creates a sound buffer object to manage audio samples.
- HRESULT hr1;
- if( FAILED(m_pDS->CreateSoundBuffer(&dsbd,&m_pDSBuffer,NULL))){
- return FALSE;
- }
4) 创建一个副缓冲对象
使用IDirectSoundBuffer的QueryInterface()能够得到一个IDirectSoundBuffer8接口的对象。IDirectSoundBuffer8的GUID为IID_IDirectSoundBuffer8。演示样例代码例如以下。
- IDirectSoundBuffer *m_pDSBuffer=NULL;
- IDirectSoundBuffer8 *m_pDSBuffer8=NULL;
- ...
- if( FAILED(m_pDSBuffer->QueryInterface(IID_IDirectSoundBuffer8,(LPVOID*)&m_pDSBuffer8))){
- return FALSE ;
- }
5) 创建通知对象
使用IDirectSoundBuffer8的QueryInterface()能够得到一个IDirectSoundNotify8接口的对象。IDirectSoundBuffer8的GUID为IID_IDirectSoundNotify。演示样例代码例如以下。
- IDirectSoundBuffer8 *m_pDSBuffer8=NULL;
- IDirectSoundNotify8 *m_pDSNotify=NULL;
- …
- if(FAILED(m_pDSBuffer8->QueryInterface(IID_IDirectSoundNotify,(LPVOID*)&m_pDSNotify))){
- return FALSE ;
- }
一句话概括一下通知对象的作用:当DirectSound缓冲区中的数据播放完成后,告知系统应该填充新的数据。
6) 设置通知位置
使用IDirectSoundNotify8的SetNotificationPositions()能够设置通知的位置。SetNotificationPositions()的原型例如以下。
- HRESULT SetNotificationPositions(
- DWORD dwPositionNotifies,
- LPCDSBPOSITIONNOTIFY pcPositionNotifies
- )
參数含义例如以下。
dwPositionNotifies:DSBPOSITIONNOTIFY结构体的数量。既包括几个通知的位置。
pcPositionNotifies:指向DSBPOSITIONNOTIFY结构体数组的指针。
再这里涉及到一个结构体DSBPOSITIONNOTIFY,它描写叙述了通知的位置。DSBPOSITIONNOTIFY的定义例如以下。
- typedef struct DSBPOSITIONNOTIFY {
- DWORD dwOffset;
- HANDLE hEventNotify;
- } DSBPOSITIONNOTIFY;
它的成员的含义例如以下。
dwOffset:通知事件触发的位置(距离缓冲開始位置的偏移量)。
hEventNotify:触发的事件的句柄。
7) 開始播放
使用IDirectSoundBuffer8的SetCurrentPosition ()能够设置播放的位置。SetCurrentPosition ()原型例如以下
- HRESULT SetCurrentPosition(
- DWORD dwNewPosition
- )
当中dwNewPosition是播放点与缓冲区首个字节之间的偏移量。
使用IDirectSoundBuffer8的Play ()能够開始播放音频数据。Play ()原型例如以下。
- HRESULT Play(
- DWORD dwReserved1,
- DWORD dwPriority,
- DWORD dwFlags
- )
參数含义:
dwReserved1:保留參数,必须取0。
dwPriority:优先级,普通情况下取0就可以。
dwFlags:标志位。眼下常见的是DSBPLAY_LOOPING。当播放至缓冲区结尾的时候,又一次从缓冲区開始处開始播放。
2. 循环播放声音
1) 数据填充至副缓冲区
数据填充至副缓冲区之前,须要先使用Lock()锁定缓冲区。然后就能够使用fread(),memcpy()等方法将PCM音频採样数据填充至缓冲区。数据填充完成后,使用Unlock()取消对缓冲区的锁定。
Lock()函数的原型例如以下。
- HRESULT Lock(
- DWORD dwOffset,
- DWORD dwBytes,
- LPVOID * ppvAudioPtr1,
- LPDWORD pdwAudioBytes1,
- LPVOID * ppvAudioPtr2,
- LPDWORD pdwAudioBytes2,
- DWORD dwFlags
- )
參数的含义例如以下。
dwOffset:锁定的内存与缓冲区首地址之间的偏移量。
dwBytes:锁定的缓存的大小。
ppvAudioPtr1:获取到的指向缓存数据的指针。
pdwAudioBytes1:获取到的缓存数据的大小。
ppvAudioPtr2:没实用到,设置为NULL。
pdwAudioBytes2:没实用到,设置为0。
dwFlags:临时没有研究。
UnLock()函数的原型例如以下。
- HRESULT Unlock(
- LPVOID pvAudioPtr1,
- DWORD dwAudioBytes1,
- LPVOID pvAudioPtr2,
- DWORD dwAudioBytes2
- )
參数含义例如以下。
pvAudioPtr1:通过Lock()获取到的指向缓存数据的指针。
dwAudioBytes1:写入的数据量。
pvAudioPtr2:没实用到。
dwAudioBytes2:没实用到。
2) 等待播放完成
依据此前设置的通知机制,使用WaitForMultipleObjects()等待缓冲区中的数据播放完成,然后进入下一个循环。
播放音频流程总结
DirectSound播放PCM音频数据的流程例如以下图所看到的。
当中涉及到的几个结构体之间的关系例如以下图所看到的。
代码
贴上源码。
- /**
- * 最简单的DirectSound播放音频的样例(DirectSound播放PCM)
- * Simplest Audio Play DirectSound (DirectSound play PCM)
- *
- * 雷霄骅 Lei Xiaohua
- * leixiaohua1020@126.com
- * 中国传媒大学/数字电视技术
- * Communication University of China / Digital TV Technology
- * http://blog.csdn.net/leixiaohua1020
- *
- * 本程序使用DirectSound播放PCM音频採样数据。
- * 是最简单的DirectSound播放音频的教程。
- *
- * 函数调用过程例如以下:
- *
- * [初始化]
- * DirectSoundCreate8(): 创建一个DirectSound对象。
- * SetCooperativeLevel(): 设置协作权限,不然没有声音。
- * IDirectSound8->CreateSoundBuffer(): 创建一个主缓冲区对象。
- * IDirectSoundBuffer->QueryInterface(IID_IDirectSoundBuffer8..):
- * 创建一个副缓冲区对象,用来存储要播放的声音数据文件。
- * IDirectSoundBuffer8->QueryInterface(IID_IDirectSoundNotify..):
- * 创建通知对象,通知应用程序指定播放位置已经达到。
- * IDirectSoundNotify8->SetNotificationPositions(): 设置通知位置。
- * IDirectSoundBuffer8->SetCurrentPosition(): 设置播放的起始点。
- * IDirectSoundBuffer8->Play(): 開始播放。
- *
- * [循环播放数据]
- * IDirectSoundBuffer8->Lock(): 锁定副缓冲区,准备写入数据。
- * fread(): 读取数据。
- * IDirectSoundBuffer8->Unlock(): 解锁副缓冲区。
- * WaitForMultipleObjects(): 等待“播放位置已经达到”的通知。
- *
- * This software plays PCM raw audio data using DirectSound.
- * It's the simplest tutorial about DirectSound.
- *
- * The process is shown as follows:
- *
- * [Init]
- * DirectSoundCreate8(): Init DirectSound object.
- * SetCooperativeLevel(): Must set, or we won't hear sound.
- * IDirectSound8->CreateSoundBuffer(): Create primary sound buffer.
- * IDirectSoundBuffer->QueryInterface(IID_IDirectSoundBuffer8..):
- * Create secondary sound buffer.
- * IDirectSoundBuffer8->QueryInterface(IID_IDirectSoundNotify..):
- * Create Notification object.
- * IDirectSoundNotify8->SetNotificationPositions():
- * Set Notification Positions.
- * IDirectSoundBuffer8->SetCurrentPosition(): Set position to start.
- * IDirectSoundBuffer8->Play(): Begin to play.
- *
- * [Loop to play data]
- * IDirectSoundBuffer8->Lock(): Lock secondary buffer.
- * fread(): get PCM data.
- * IDirectSoundBuffer8->Unlock(): UnLock secondary buffer.
- * WaitForMultipleObjects(): Wait for Notifications.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <windows.h>
- #include <dsound.h>
- #define MAX_AUDIO_BUF 4
- #define BUFFERNOTIFYSIZE 192000
- int sample_rate=44100; //PCM sample rate
- int channels=2; //PCM channel number
- int bits_per_sample=16; //bits per sample
- BOOL main(int argc,char * argv[])
- {
- int i;
- FILE * fp;
- if((fp=fopen("../NocturneNo2inEflat_44.1k_s16le.pcm","rb"))==NULL){
- printf("cannot open this file\n");
- return -1;
- }
- IDirectSound8 *m_pDS=NULL;
- IDirectSoundBuffer8 *m_pDSBuffer8=NULL; //used to manage sound buffers.
- IDirectSoundBuffer *m_pDSBuffer=NULL;
- IDirectSoundNotify8 *m_pDSNotify=NULL;
- DSBPOSITIONNOTIFY m_pDSPosNotify[MAX_AUDIO_BUF];
- HANDLE m_event[MAX_AUDIO_BUF];
- SetConsoleTitle(TEXT("Simplest Audio Play DirectSound"));//Console Title
- //Init DirectSound
- if(FAILED(DirectSoundCreate8(NULL,&m_pDS,NULL)))
- return FALSE;
- if(FAILED(m_pDS->SetCooperativeLevel(FindWindow(NULL,TEXT("Simplest Audio Play DirectSound")),DSSCL_NORMAL)))
- return FALSE;
- DSBUFFERDESC dsbd;
- memset(&dsbd,0,sizeof(dsbd));
- dsbd.dwSize=sizeof(dsbd);
- dsbd.dwFlags=DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPOSITIONNOTIFY |DSBCAPS_GETCURRENTPOSITION2;
- dsbd.dwBufferBytes=MAX_AUDIO_BUF*BUFFERNOTIFYSIZE;
- //WAVE Header
- dsbd.lpwfxFormat=(WAVEFORMATEX*)malloc(sizeof(WAVEFORMATEX));
- dsbd.lpwfxFormat->wFormatTag=WAVE_FORMAT_PCM;
- /* format type */
- (dsbd.lpwfxFormat)->nChannels=channels;
- /* number of channels (i.e. mono, stereo...) */
- (dsbd.lpwfxFormat)->nSamplesPerSec=sample_rate;
- /* sample rate */
- (dsbd.lpwfxFormat)->nAvgBytesPerSec=sample_rate*(bits_per_sample/8)*channels;
- /* for buffer estimation */
- (dsbd.lpwfxFormat)->nBlockAlign=(bits_per_sample/8)*channels;
- /* block size of data */
- (dsbd.lpwfxFormat)->wBitsPerSample=bits_per_sample;
- /* number of bits per sample of mono data */
- (dsbd.lpwfxFormat)->cbSize=0;
- //Creates a sound buffer object to manage audio samples.
- HRESULT hr1;
- if( FAILED(m_pDS->CreateSoundBuffer(&dsbd,&m_pDSBuffer,NULL))){
- return FALSE;
- }
- if( FAILED(m_pDSBuffer->QueryInterface(IID_IDirectSoundBuffer8,(LPVOID*)&m_pDSBuffer8))){
- return FALSE ;
- }
- //Get IDirectSoundNotify8
- if(FAILED(m_pDSBuffer8->QueryInterface(IID_IDirectSoundNotify,(LPVOID*)&m_pDSNotify))){
- return FALSE ;
- }
- for(i =0;i<MAX_AUDIO_BUF;i++){
- m_pDSPosNotify[i].dwOffset =i*BUFFERNOTIFYSIZE;
- m_event[i]=::CreateEvent(NULL,false,false,NULL);
- m_pDSPosNotify[i].hEventNotify=m_event[i];
- }
- m_pDSNotify->SetNotificationPositions(MAX_AUDIO_BUF,m_pDSPosNotify);
- m_pDSNotify->Release();
- //Start Playing
- BOOL isPlaying =TRUE;
- LPVOID buf=NULL;
- DWORD buf_len=0;
- DWORD res=WAIT_OBJECT_0;
- DWORD offset=BUFFERNOTIFYSIZE;
- m_pDSBuffer8->SetCurrentPosition(0);
- m_pDSBuffer8->Play(0,0,DSBPLAY_LOOPING);
- //Loop
- while(isPlaying){
- if((res >=WAIT_OBJECT_0)&&(res <=WAIT_OBJECT_0+3)){
- m_pDSBuffer8->Lock(offset,BUFFERNOTIFYSIZE,&buf,&buf_len,NULL,NULL,0);
- if(fread(buf,1,buf_len,fp)!=buf_len){
- //File End
- //Loop:
- fseek(fp, 0, SEEK_SET);
- fread(buf,1,buf_len,fp);
- //Close:
- //isPlaying=0;
- }
- m_pDSBuffer8->Unlock(buf,buf_len,NULL,0);
- offset+=buf_len;
- offset %= (BUFFERNOTIFYSIZE * MAX_AUDIO_BUF);
- printf("this is %7d of buffer\n",offset);
- }
- res = WaitForMultipleObjects (MAX_AUDIO_BUF, m_event, FALSE, INFINITE);
- }
- return 0;
- }
执行结果
代码执行之后,会弹出一个“控制台”对话框例如以下图所看到的。同一时候音频设备里面能够听到播放的声音。
下载
代码位于“Simplest Media Play”中
SourceForge项目地址:https://sourceforge.net/projects/simplestmediaplay/
CSDN下载地址:http://download.csdn.net/detail/leixiaohua1020/8054395
注:
该项目会不定时的更新并修复一些小问题,最新的版本号请參考该系列文章的总述页面:
上述project包括了使用各种API(Direct3D,OpenGL,GDI,DirectSound,SDL2)播放多媒体样例。当中音频输入为PCM採样数据。输出至系统的声卡播放出来。视频输入为YUV/RGB像素数据。输出至显示器上的一个窗体播放出来。
通过本project的代码刚開始学习的人能够高速学习使用这几个API播放视频和音频的技术。
一共包括了例如以下几个子project:
simplest_audio_play_directsound: 使用DirectSound播放PCM音频採样数据。
simplest_audio_play_sdl2: 使用SDL2播放PCM音频採样数据。
simplest_video_play_direct3d: 使用Direct3D的Surface播放RGB/YUV视频像素数据。
simplest_video_play_direct3d_texture:使用Direct3D的Texture播放RGB视频像素数据。
simplest_video_play_gdi: 使用GDI播放RGB/YUV视频像素数据。
simplest_video_play_opengl: 使用OpenGL播放RGB/YUV视频像素数据。
simplest_video_play_opengl_texture: 使用OpenGL的Texture播放YUV视频像素数据。
simplest_video_play_sdl2: 使用SDL2播放RGB/YUV视频像素数据。
最简单的视音频播放演示样例8:DirectSound播放PCM的更多相关文章
- 最简单的视音频播放演示样例4:Direct3D播放RGB(通过Texture)
===================================================== 最简单的视音频播放演示样例系列文章列表: 最简单的视音频播放演示样例1:总述 最简单的视音频 ...
- 最简单的视音频播放演示样例5:OpenGL播放RGB/YUV
===================================================== 最简单的视音频播放演示样例系列文章列表: 最简单的视音频播放演示样例1:总述 最简单的视音频 ...
- 最简单的视音频播放演示样例3:Direct3D播放YUV,RGB(通过Surface)
===================================================== 最简单的视音频播放演示样例系列文章列表: 最简单的视音频播放演示样例1:总述 最简单的视音频 ...
- 最简单的视音频播放演示样例7:SDL2播放RGB/YUV
===================================================== 最简单的视音频播放演示样例系列文章列表: 最简单的视音频播放演示样例1:总述 最简单的视音频 ...
- Android - 标准VideoView播放演示样例
标准VideoView播放演示样例 本文地址: http://blog.csdn.net/caroline_wendy 在Android SDK中的ApiDemos内, 提供标准播放视频的代码,使用V ...
- JAVA简单Swing图形界面应用演示样例
JAVA简单Swing图形界面应用演示样例 package org.rui.hello; import javax.swing.JFrame; /** * 简单的swing窗体 * @author l ...
- Nginx 简单的负载均衡配置演示样例
近期在做开放查询应用的时候,因为数据两天特别多,两千多万条呢,用户訪问需求也比較大,所以就用nginx做了 负载均衡,以下是改动之后的相关内容. http://www.cnblogs.com/xiao ...
- CSS3中transform,transition和animation的简单介绍和使用方法演示样例
transform是一个属性,本质跟width,height是一样的,加上transform也就是为类添加一个变换属性. transition是一个属性.它是用来控制过渡效果的,由于用transfor ...
- 最简单的基于FFmpeg的AVUtil样例 (AVLog, AVOption等)
本文的演示样例程序记录了FFmpeg的libavutil中几种工具函数的用法: AVLog:日志输出AVOption (AVClass):选项设置AVDictionary:键值对存储ParseUtil ...
随机推荐
- centos5.5字体为方块问题的解决_深入学习编程_百度空间
centos5.5字体为方块问题的解决_深入学习编程_百度空间 centos5.5字体为方块问题的解决 一.yum -y install fonts-chinese二.yum -y install f ...
- Orchard
Orchard工作原理 概述 本文翻译仅供学习之用,了解Orchard工作原理设计思想.技术点及关键词,如有缺漏请不吝指正.鉴于能力有限定有诸多曲解或不完整的地方,请海涵.不定时完善整理. CMS不像 ...
- SE 2014年4月30日
如图配置: SW1 SW2 SW3 SW4组成一环型网络 Sw2 和Sw4个存在两业务vlan(vlan 10 和vlan 20) 1.Smart Link 组1 的引用实例1(绑定VLAN 10 ) ...
- Windown安装Mysql安装图解
一.MYSQL的安装 1.打开下载的mysql安装文件mysql-5.0.27-win32.zip,双击解压缩,运行“setup.exe”. 2.选择安装类型,有“Typical(默认)”.“Comp ...
- hdu4614(线段树+二分)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4614 题意:给定一个区间[0,N-1],初始时每个位置上的数字都是0,可以对其进行以下两种操作: 1. ...
- LINUX设备驱动程序的注意事项(两)建设和执行模块
<一>:设置測试系统 首先准备好一个内核源代码树,构造一个新内核,然后安装到自己的系统中. <二>:HelloWorld模块 #inclu ...
- openfire插件开发的几点说明
1.关于插件的目录结构 这个网上的资料很多,但是我觉得要看懂也不太容易,我这里上一个包括了jsp和servlet的图,希望大家能马上看懂: ME的Navigator视图下的截图: build path ...
- Knockout应用开发指南 第二章:监控属性(Observables)
原文:Knockout应用开发指南 第二章:监控属性(Observables) 关于Knockout的3个重要概念(Observables,DependentObservables,Observabl ...
- VS2008--无法找到“XXX.exe”的调试信息,或者调试信息不匹配
------解决方案----- 1. 关闭掉Visual Studio 实例. 2. 找到解决方案下的.suo文件并删除之. 3. 重新启动Visual Studio,或者直接双击.sln文件打开 4 ...
- 用python调用R做数据分析-准备工作
0.R的介绍 R是自由软件,不带不论什么担保.在某些条件下你能够将其自由散布,用'license()'或'licence()'来看散布的具体条件. R是个合作计划.有很多人为之做出了贡献,用'cont ...