Skip to content

Instantly share code, notes, and snippets.

@daramkun
Last active September 6, 2017 18:41
Show Gist options
  • Save daramkun/f94fe6e8acdb0d23878bb084d641dfe6 to your computer and use it in GitHub Desktop.
Save daramkun/f94fe6e8acdb0d23878bb084d641dfe6 to your computer and use it in GitHub Desktop.
OpenAL Streaming with MediaFoundation
#include <Windows.h>
#include <atlbase.h>
#include <vector>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <mfplay.h>
#include <mftransform.h>
#pragma comment ( lib, "mfplat.lib" )
#pragma comment ( lib, "mfuuid.lib" )
#pragma comment ( lib, "mfreadwrite.lib" )
#include <al.h>
#include <alc.h>
#pragma comment ( lib, "OpenAL32.lib" )
#define AL_EXT_MCFORMATS 1
#define AL_FORMAT_QUAD8 0x1204
#define AL_FORMAT_QUAD16 0x1205
#define AL_FORMAT_QUAD32 0x1206
#define AL_FORMAT_REAR8 0x1207
#define AL_FORMAT_REAR16 0x1208
#define AL_FORMAT_REAR32 0x1209
#define AL_FORMAT_51CHN8 0x120A
#define AL_FORMAT_51CHN16 0x120B
#define AL_FORMAT_51CHN32 0x120C
#define AL_FORMAT_61CHN8 0x120D
#define AL_FORMAT_61CHN16 0x120E
#define AL_FORMAT_61CHN32 0x120F
#define AL_FORMAT_71CHN8 0x1210
#define AL_FORMAT_71CHN16 0x1211
#define AL_FORMAT_71CHN32 0x1212
#define BUFFER_COUNT 2
bool readSample ( IMFSourceReader * reader, ALuint sourceId, ALuint bufferId, ALenum bufferFormat, ALint samplerate, LONGLONG * timeStamp )
{
HRESULT hResult;
DWORD flags;
LONGLONG tempTimeStamp;
CComPtr<IMFSample> sample;
if ( FAILED ( hResult = reader->ReadSample ( MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, nullptr, &flags, timeStamp ? timeStamp : &tempTimeStamp, &sample ) ) )
{
alSourceStop ( sourceId );
return false;
}
if ( flags & MF_SOURCE_READERF_ENDOFSTREAM )
{
alSourceStop ( sourceId );
return false;
}
CComPtr<IMFMediaBuffer> buf;
if ( FAILED ( hResult = sample->ConvertToContiguousBuffer ( &buf ) ) )
{
alSourceStop ( sourceId );
return false;
}
BYTE * lockedBuffer;
DWORD lockedCurrentLength;
if ( FAILED ( hResult = buf->Lock ( &lockedBuffer, nullptr, &lockedCurrentLength ) ) )
{
alSourceStop ( sourceId );
return false;
}
alBufferData ( bufferId, bufferFormat, lockedBuffer, lockedCurrentLength, samplerate );
return true;
}
int main ( void )
{
HRESULT hResult;
MFStartup ( MF_VERSION, 0 );
ALCdevice * alcDevice = alcOpenDevice ( nullptr );
ALCint attrList [] = { 0, };
ALCcontext * alcContext = alcCreateContext ( alcDevice, attrList );
alcMakeContextCurrent ( alcContext );
CComPtr<IMFAttributes> attr;
hResult = MFCreateAttributes ( &attr, 0 );
hResult = attr->SetUINT32 ( MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, 1 );
CComPtr<IMFSourceReader> reader;
hResult = MFCreateSourceReaderFromURL ( TEXT ( "Sample.mp3" ), attr, &reader );
hResult = reader->SetStreamSelection ( MF_SOURCE_READER_ALL_STREAMS, false );
hResult = reader->SetStreamSelection ( MF_SOURCE_READER_FIRST_AUDIO_STREAM, true );
CComPtr<IMFMediaType> setMediaType;
MFCreateMediaType ( &setMediaType );
setMediaType->SetGUID ( MF_MT_MAJOR_TYPE, MFMediaType_Audio );
setMediaType->SetGUID ( MF_MT_SUBTYPE, MFAudioFormat_PCM );
hResult = reader->SetCurrentMediaType ( MF_SOURCE_READER_FIRST_AUDIO_STREAM, nullptr, setMediaType );
setMediaType.Release ();
CComPtr<IMFMediaType> mediaType;
hResult = reader->GetCurrentMediaType ( MF_SOURCE_READER_FIRST_AUDIO_STREAM, &mediaType );
WAVEFORMATEX * wf;
UINT wfSize = sizeof ( WAVEFORMATEX );
hResult = MFCreateWaveFormatExFromMFMediaType ( mediaType, &wf, &wfSize, 0 );
PROPVARIANT va;
hResult = reader->GetPresentationAttribute ( MF_SOURCE_READER_MEDIASOURCE, MF_PD_DURATION, &va );
int channels = wf->nChannels;
int bitsPerSample = wf->wBitsPerSample;
int samplerate = wf->nSamplesPerSec;
LONGLONG duration = va.uhVal.QuadPart;
ALenum bufferFormat =
( ( channels == 2 ) ? ( ( bitsPerSample == 16 ) ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO8 ) :
( ( channels == 1 ) ? ( ( bitsPerSample == 16 ) ? AL_FORMAT_MONO16 : AL_FORMAT_MONO8 ) :
( ( channels == 6 ) ? ( ( bitsPerSample == 16 ) ? AL_FORMAT_51CHN16 : AL_FORMAT_51CHN8 ) :
( channels == 8 ) ? ( ( bitsPerSample == 16 ) ? AL_FORMAT_71CHN16 : AL_FORMAT_71CHN8 ) : 0
) ) );
int byteRate = channels * ( bitsPerSample / 8 ) * samplerate;
ALuint sourceId;
alGenSources ( 1, &sourceId );
std::vector<ALuint> bufferIds ( BUFFER_COUNT );
alGenBuffers ( BUFFER_COUNT, &bufferIds [ 0 ] );
for ( int i = 0; i < BUFFER_COUNT; ++i )
readSample ( reader, sourceId, bufferIds [ i ], bufferFormat, samplerate, nullptr );
alSourceQueueBuffers ( sourceId, BUFFER_COUNT, &bufferIds [ 0 ] );
alSourcePlay ( sourceId );
ALint totalPlaying = 0;
bool failed = false;
while ( true )
{
ALint status;
alGetSourcei ( sourceId, AL_SOURCE_STATE, &status );
if ( status == AL_PLAYING )
{
//printf ( "Still Playing.\n" );
}
if ( GetAsyncKeyState ( VK_SPACE ) & 0x8000 != 0 )
{
alSourceStop ( sourceId );
alSourceUnqueueBuffers ( sourceId, BUFFER_COUNT, &bufferIds [ 0 ] );
PROPVARIANT pos;
pos.vt = VT_I8;
pos.uhVal.QuadPart = 30 * 10000000ULL;
reader->SetCurrentPosition ( GUID_NULL, pos );
totalPlaying = 30 * byteRate;
for ( int i = 0; i < BUFFER_COUNT; ++i )
readSample ( reader, sourceId, bufferIds [ i ], bufferFormat, samplerate, nullptr );
alSourceQueueBuffers ( sourceId, 8, &bufferIds [ 0 ] );
alSourcePlay ( sourceId );
}
ALint position;
alGetSourcei ( sourceId, AL_SAMPLE_OFFSET, &position );
printf ( "Position: %f / %f\n", ( totalPlaying + position ) / ( float ) byteRate, duration / 10000000.0f );
if ( failed )
break;
ALint proceed;
alGetSourcei ( sourceId, AL_BUFFERS_PROCESSED, &proceed );
//printf ( "Proceed Buffer Count: %d.\n", proceed );
if ( proceed > 0 )
{
std::vector<ALuint> proceedBuffers;
for ( int i = 0; i < proceed; ++i )
{
proceedBuffers.push_back ( bufferIds [ 0 ] );
bufferIds.erase ( bufferIds.begin () );
}
for ( auto i = proceedBuffers.begin (); i != proceedBuffers.end (); ++i )
{
ALuint temp = *i;
bufferIds.push_back ( temp );
alSourceUnqueueBuffers ( sourceId, 1, &temp );
if ( !readSample ( reader, sourceId, temp, bufferFormat, samplerate, nullptr ) )
{
printf ( "All buffer readed.\n" );
failed = true;
}
ALint size;
alGetBufferi ( temp, AL_SIZE, &size );
totalPlaying += size;
alSourceQueueBuffers ( sourceId, 1, &temp );
}
}
}
alDeleteBuffers ( BUFFER_COUNT, &bufferIds [ 0 ] );
alDeleteSources ( 1, &sourceId );
alcDestroyContext ( alcContext );
alcCloseDevice ( alcDevice );
mediaType.Release ();
reader.Release ();
attr.Release ();
MFShutdown ();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment