0
votes

I've just spent the all day trying to find a solution regarding that problem, let me explain a bit:

I am developing a video tool on Windows using Visual 2013, Qt, OpenGL and Media Foundation in c++. I've got a IMFSourceReader that is grabbing video frame that I treat and display using openGL inside a QWindow.

Now I want to play the audio stream of the video file. I know how to grab a audio sample (using the same source reader). I also know how to enumerate all my audio devices:

IMMDeviceEnumerator *pEnum = NULL;      // Audio device enumerator.
IMMDeviceCollection *pDevices = NULL;   // Audio device collection.
IMMDevice *pDevice = NULL;              // An audio device.
IMFAttributes *pAttributes = NULL;      // Attribute store.
IMFMediaSink *pSink = NULL;             // Streaming audio renderer (SAR)

LPWSTR wstrID = NULL;                   // Device ID.

// Create the device enumerator.
hr = CoCreateInstance(
    __uuidof(MMDeviceEnumerator),
    NULL,
    CLSCTX_ALL,
    __uuidof(IMMDeviceEnumerator),
    (void**)&pEnum
    );

// Enumerate the rendering devices.
if (SUCCEEDED(hr))
{
    hr = pEnum->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pDevices);
}

// Get ID of the first device in the list.
if (SUCCEEDED(hr))
{
    hr = pDevices->Item(0, &pDevice);
}

if (SUCCEEDED(hr))
{
    hr = pDevice->GetId(&wstrID);
}

// Create an attribute store and set the device ID attribute.
if (SUCCEEDED(hr))
{
    hr = MFCreateAttributes(&pAttributes, 2);
}

if (SUCCEEDED(hr))
{
    hr = pAttributes->SetString(
        MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID,
        wstrID
        );
}

// Create the audio renderer.
if (SUCCEEDED(hr))
{
    hr = MFCreateAudioRenderer(pAttributes, &pSink);
}

SAFE_RELEASE(pEnum);
SAFE_RELEASE(pDevices);
SAFE_RELEASE(pDevice);
SAFE_RELEASE(pAttributes);
CoTaskMemFree(wstrID);
}

I think I have to go with a Streaming Audio Renderer but that is all. I can't find any thing on the web, I even went on the 11th page of a Google search...

You are my only hope SO...

1

1 Answers

0
votes

Just in case some people might need some help with that problem, I found the solution myself, it might not be the more optimize solution but eh, that's the only one I got working!

Header:

class                   AudioPlaybackRenderer : public QObject
{

    Q_OBJECT

private:
    SourceReader *      _sourceReader;
    QAudioOutput *      _audioOutput;
    QIODevice *         _output;
    QByteArray *        _buffer;
    bool                _isPaused;
    PreciseTimer        _deltaTimer;
    int                 _bufferDuration;
    QTimer              _nextRender;

public:
    AudioPlaybackRenderer();
    ~AudioPlaybackRenderer();

public:
    void                setSourceReader(SourceReader *);

private:
    void                playBuffer();

private slots:
    void                render();
};

Implementation:

void                    AudioPlaybackRenderer::playBuffer()
{
    if (this->_audioOutput && this->_audioOutput->state() != QAudio::StoppedState && this->_audioOutput->state() != QAudio::SuspendedState)
    {
        if (_buffer->size())
            this->_buffer->remove(0, _output->write(_buffer->data(), _buffer->size()));
        if (_buffer->size() <= 0)
        {
            delete this->_buffer;
            this->_buffer = NULL;
        }
    }
}

void                    AudioPlaybackRenderer::render()
{
    this->_deltaTimer.stop();
    float lastLoop = this->_deltaTimer.getElapsedTimeinMilliSec();
    if (this->_isPaused == false)
    {
        if (this->_buffer == NULL)
            this->_buffer = this->_sourceReader->getNextAudioSample();
        if (this->_buffer != NULL)
        {
            this->playBuffer();
        }
    }

    if (this->_audioOutput->error() != QAudio::NoError)
        qDebug() << DEBUG_TAG << "ERROR:" << this->_audioOutput->error();

    this->_deltaTimer.start();

    //TODO: Add that as member
    float delta = this->_bufferDuration - lastLoop;
    if (delta < 0)
        delta = 0.f;
    this->_nextRender.start(delta);
}