mirror of
https://github.com/WinampDesktop/winamp.git
synced 2024-12-18 16:45:51 +01:00
209 lines
4.7 KiB
C++
209 lines
4.7 KiB
C++
|
#include "MFTDecoder.h"
|
||
|
#include "util.h"
|
||
|
#include "../nsutil/pcm.h"
|
||
|
#include <Mfapi.h>
|
||
|
#include <Mferror.h>
|
||
|
|
||
|
static // Release the events that an MFT might allocate in IMFTransform::ProcessOutput().
|
||
|
void ReleaseEventCollection(MFT_OUTPUT_DATA_BUFFER* pBuffers)
|
||
|
{
|
||
|
|
||
|
if (pBuffers->pEvents)
|
||
|
{
|
||
|
pBuffers->pEvents->Release();
|
||
|
pBuffers->pEvents = NULL;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
MFTDecoder::MFTDecoder()
|
||
|
{
|
||
|
decoder=0;
|
||
|
output_buffer=0;
|
||
|
output_sample=0;
|
||
|
}
|
||
|
|
||
|
MFTDecoder::~MFTDecoder()
|
||
|
{
|
||
|
if (decoder) {
|
||
|
decoder->Release();
|
||
|
}
|
||
|
decoder = 0;
|
||
|
|
||
|
if (output_buffer) {
|
||
|
output_buffer->Release();
|
||
|
}
|
||
|
output_buffer = 0;
|
||
|
|
||
|
if (output_sample) {
|
||
|
output_sample->Release();
|
||
|
}
|
||
|
output_sample = 0;
|
||
|
}
|
||
|
|
||
|
HRESULT MFTDecoder::Open(const void *asc, size_t asc_bytes)
|
||
|
{
|
||
|
HRESULT hr = CreateAACDecoder(&decoder, asc, asc_bytes);
|
||
|
if (SUCCEEDED(hr)) {
|
||
|
decoder->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0);
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT MFTDecoder::Open()
|
||
|
{
|
||
|
HRESULT hr = CreateADTSDecoder(&decoder);
|
||
|
if (SUCCEEDED(hr)) {
|
||
|
decoder->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0);
|
||
|
decoder->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
void MFTDecoder::Flush()
|
||
|
{
|
||
|
if (decoder) {
|
||
|
decoder->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HRESULT MFTDecoder::GetOutputProperties(uint32_t *sampleRate, uint32_t *channels)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
IMFMediaType *media_type;
|
||
|
UINT32 local_sample_rate, local_channels;
|
||
|
|
||
|
if (!decoder) {
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
hr = decoder->GetOutputCurrentType(0, &media_type);
|
||
|
|
||
|
if (FAILED(hr)) {
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr=media_type->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &local_sample_rate))
|
||
|
|| FAILED(hr=media_type->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &local_channels))) {
|
||
|
media_type->Release();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
*sampleRate = local_sample_rate;
|
||
|
*channels = local_channels;
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT MFTDecoder::Feed(const void *inputBuffer, size_t inputBufferBytes)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
if (inputBuffer && inputBufferBytes) {
|
||
|
IMFMediaBuffer *media_buffer=0;
|
||
|
IMFSample *media_sample=0;
|
||
|
MFCreateMemoryBuffer((DWORD)inputBufferBytes, &media_buffer);
|
||
|
MFCreateSample(&media_sample);
|
||
|
media_sample->AddBuffer(media_buffer);
|
||
|
|
||
|
BYTE *buffer;
|
||
|
DWORD max_length, current_length;
|
||
|
media_buffer->Lock(&buffer, &max_length, ¤t_length);
|
||
|
memcpy(buffer, inputBuffer, inputBufferBytes);
|
||
|
|
||
|
media_buffer->Unlock();
|
||
|
media_buffer->SetCurrentLength((DWORD)inputBufferBytes);
|
||
|
|
||
|
hr = decoder->ProcessInput(0, media_sample, 0);
|
||
|
media_sample->Release();
|
||
|
media_buffer->Release();
|
||
|
media_sample=0;
|
||
|
media_buffer=0;
|
||
|
} else {
|
||
|
decoder->ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, 0);
|
||
|
decoder->ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0);
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT MFTDecoder::Decode(void *outputBuffer, size_t *outputBufferBytes, unsigned int bitsPerSample, bool isFloat, double gain)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (!output_sample) {
|
||
|
MFT_OUTPUT_STREAM_INFO output_stream_info;
|
||
|
hr = decoder->GetOutputStreamInfo(0, &output_stream_info);
|
||
|
if (FAILED(hr)) {
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
MFCreateMemoryBuffer(output_stream_info.cbSize, &output_buffer);
|
||
|
MFCreateSample(&output_sample);
|
||
|
output_sample->AddBuffer(output_buffer);
|
||
|
}
|
||
|
|
||
|
output_buffer->SetCurrentLength(0);
|
||
|
MFT_OUTPUT_DATA_BUFFER output_data_buffer = {0, output_sample, 0, 0};
|
||
|
DWORD status=0;
|
||
|
hr = decoder->ProcessOutput(0, 1, &output_data_buffer, &status);
|
||
|
if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
|
||
|
*outputBufferBytes = 0;
|
||
|
return S_OK;
|
||
|
} else if (hr == MF_E_TRANSFORM_STREAM_CHANGE) {
|
||
|
AssociateFloat(decoder);
|
||
|
*outputBufferBytes = 0;
|
||
|
return hr;
|
||
|
}
|
||
|
IMFMediaBuffer *decimation_buffer;
|
||
|
hr = output_data_buffer.pSample->ConvertToContiguousBuffer(&decimation_buffer);
|
||
|
float *pcm;
|
||
|
DWORD max_length, current_length;
|
||
|
decimation_buffer->Lock((BYTE **)&pcm, &max_length, ¤t_length);
|
||
|
size_t num_samples = current_length / 4;
|
||
|
*outputBufferBytes = num_samples*bitsPerSample/8;
|
||
|
|
||
|
if (!isFloat)
|
||
|
{
|
||
|
nsutil_pcm_FloatToInt_Interleaved_Gain(outputBuffer, pcm, bitsPerSample, num_samples, (float)gain);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (size_t i = 0;i != num_samples;i++)
|
||
|
((float *)outputBuffer)[i] = pcm[i] * (float)gain;
|
||
|
}
|
||
|
|
||
|
decimation_buffer->Unlock();
|
||
|
decimation_buffer->Release();
|
||
|
|
||
|
ReleaseEventCollection(&output_data_buffer);
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT MFTDecoder::OutputBlockSizeSamples(size_t *frameSize)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
MFT_OUTPUT_STREAM_INFO output_stream_info;
|
||
|
|
||
|
if (!decoder) {
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
hr = decoder->GetOutputStreamInfo(0, &output_stream_info);
|
||
|
if (FAILED(hr)) {
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
*frameSize = output_stream_info.cbSize;
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
bool MFTDecoder::AcceptingInput()
|
||
|
{
|
||
|
DWORD flags;
|
||
|
if (decoder && SUCCEEDED(decoder->GetInputStatus(0, &flags))) {
|
||
|
if (flags & MFT_INPUT_STATUS_ACCEPT_DATA) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|