多媒体编程——基于OpenAL的播放封装类


基于OpenAL的播放封装类.


头文件:

//
//  TKAudioPlayer.h
//  FLVPlayer
//
//  Created by administrator on 14-7-11.
//  Copyright (c) 2014年 trustsky. All rights reserved.
//


#include 
#include "al.h"
#include "alc.h"


#define TK_OPENAL_BUFFER_LENGTH 4096


class TKAudioPlayer 
{
public:
	bool create(uint32_t channels, uint32_t sample_rate, uint32_t sample_bits) ;
	bool destory();
	bool start(bool pause) ;
	bool stop();
	bool update(uint8_t* buf, uint32_t len) ;


private:


	void fillbuffer(ALuint bid, uint8_t* buf, uint32_t len);


	uint32_t        _channels ;
	uint32_t        _smplrate ;
	uint32_t        _smplbits ;




	ALCdevice*      _device    ;
	ALCcontext*     _context   ;


	ALuint          _source    ;
	ALuint          _buffer[4] ;


	uint8_t         _boxbuf[TK_OPENAL_BUFFER_LENGTH] ;//由于音频数据的特性,来源可能不定长,但是播放时需要定长的数据,所以需要一个box用来整理。
	uint32_t        _uselen ;
};




实现文件:


#include "stdafx.h"


#include "TKAudioPlayer.h"


#pragma comment(lib, "OpenAL32.lib")


bool TKAudioPlayer::create(uint32_t channels, uint32_t sample_rate, uint32_t sample_bits)
{
	_channels = channels ;
	_smplrate = sample_rate ;
	_smplbits = sample_bits ;


	_device = alcOpenDevice(NULL) ;
	if(_device)
	{
		_context = alcCreateContext(_device, NULL);
		if(_context)
			alcMakeContextCurrent(_context);
	}


	if(_device == NULL || _context == NULL)
	{
		if(_device)
			alcCloseDevice(_device);
		if(_context)
			alcDestroyContext(_context);
		_device  = NULL ;
		_context = NULL ;
		return false ;
	}


	ALuint bufCount = sizeof(_buffer)/sizeof(ALuint) ;


	alGenSources(1, &_source) ;//创建播放源。
	alGenBuffers(bufCount, _buffer); //创建播放缓存。


	alSourcei(_source, AL_LOOPING, AL_FALSE); //多个缓存播放 ,不能循环


	memset(_boxbuf, 0, TK_OPENAL_BUFFER_LENGTH);
	_uselen = 0 ;


	//设置音频格式


	for(ALuint idx=0; idxfillbuffer(_buffer[idx], _boxbuf ,TK_OPENAL_BUFFER_LENGTH);
		//先填充空白数据
	}


	//将多个缓存添加到播放源
	alSourceQueueBuffers(_source, bufCount, _buffer);


	return true ;
}


void TKAudioPlayer::fillbuffer(ALuint bid, uint8_t* buf, uint32_t len)
{
	if(_channels == 1)
	{
		if(_smplbits == 8)
			alBufferData(bid, AL_FORMAT_MONO8, _boxbuf, TK_OPENAL_BUFFER_LENGTH, _smplrate);
		else if(_smplbits == 16)
			alBufferData(bid, AL_FORMAT_MONO16, _boxbuf, TK_OPENAL_BUFFER_LENGTH, _smplrate);
	}
	else if(_channels == 2)
	{
		if(_smplbits == 8)
			alBufferData(bid, AL_FORMAT_STEREO8, _boxbuf, TK_OPENAL_BUFFER_LENGTH, _smplrate);
		else if(_smplbits == 16)
			alBufferData(bid, AL_FORMAT_STEREO16, _boxbuf, TK_OPENAL_BUFFER_LENGTH, _smplrate);
	}
}


bool TKAudioPlayer::destory()
{
	this->stop();


	ALuint bufCount = sizeof(_buffer)/sizeof(ALuint) ;


	alDeleteBuffers(bufCount, _buffer);
	alDeleteSources(1, &_source);
	alcDestroyContext(_context);
	alcCloseDevice(_device);


	_device  = NULL ;
	_context = NULL ;
	_source = 0 ;
	memset(_buffer, 0, bufCount*sizeof(ALuint));


	_channels = 0 ;
	_smplrate = 0 ;
	_smplbits = 0 ;


	return false ;
}


bool TKAudioPlayer::start(bool pause) 
{
	if(pause)
		alSourcePause(_source);
	else
		alSourcePlay(_source);
	return true ;


}
bool TKAudioPlayer::stop()
{
	alSourceStop(_source);
	return true ;
}




bool TKAudioPlayer::update(uint8_t* buf, uint32_t len) 
{
	uint32_t bufempt = TK_OPENAL_BUFFER_LENGTH - _uselen ;
	uint32_t usedLen = len < bufempt ? len : bufempt ;


	memcpy(_boxbuf + _uselen , buf, usedLen);
	_uselen += usedLen ;


	if(_uselen == TK_OPENAL_BUFFER_LENGTH)
	{//box 已经填满
		int processed = 0 ;
		ALuint buffer = 0 ;
		do
		{
			alGetSourcei(_source, AL_BUFFERS_PROCESSED, &processed);
			if(processed > 0)
			{
				alSourceUnqueueBuffers(_source, 1, &buffer);
				this->fillbuffer(buffer, _boxbuf, TK_OPENAL_BUFFER_LENGTH);
				_uselen = 0 ;
				alSourceQueueBuffers(_source, 1, &buffer);
			}


			if(processed == 0)
				Sleep(1);
		}
		while (processed == 0) ;
	}


	if(len > usedLen) //这一次的数据没使用完
		this->update(buf+usedLen,len-usedLen); //递归


	return true ;
}




使用演示:



typedef struct SMFKWaveFileFormat
{
	uint32_t        smfkSize				; /* the count in bytes of the size of */
	uint16_t        smfkFormatTag			; /* format type */
	uint16_t        smfkChannels			; /* number of channels (i.e. mono, stereo...) */
	uint32_t        smfkSamplesPerSec		; /* sample rate */
	uint32_t        smfkAvgBytesPerSec	; /* for buffer estimation */
	uint16_t        smfkBlockAlign		; /* block size of data */
	uint16_t        smfkBitsPerSample		; /* number of bits per sample of mono data */
}SMFKWaveFileFormat;




typedef struct SMFKWAVFileHeader
{
	char        rFlag[4] ;
	uint32_t	rLen	 ;
	char        wFlag[4] ;
	char        fFlag[4] ;
	SMFKWaveFileFormat wavFormat ;
}SMFKWAVFileHeader;


typedef struct SMFKWavDataHeader
{
	char        dFlag[4] ;
	uint32_t	dLen	 ;
}   SMFKWavDataHeader;








FILE* file = _wfopen(L"E:/测试素材/gala-追梦赤子心.wav", L"rb");


	SMFKWAVFileHeader wavFileHeader ;
	SMFKWavDataHeader wavDataHeader ;


	fread(&wavFileHeader, 1, sizeof(SMFKWAVFileHeader), file);
	fread(&wavDataHeader, 1, sizeof(SMFKWavDataHeader), file);


	TKAudioPlayer player ;


	player.create(wavFileHeader.wavFormat.smfkChannels, wavFileHeader.wavFormat.smfkSamplesPerSec,wavFileHeader.wavFormat.smfkBitsPerSample);


	player.start(false);


	uint8_t  buffer[4000] ;
	uint32_t readlen = 0 ;


	while((readlen = fread(buffer, 1, 4000, file)))
		player.update(buffer, readlen);


	player.stop();
	player.destory();


你可能感兴趣的:(多媒体)