Audio downsample is just static?

EDN Admin

Well-known member
Joined
Aug 7, 2010
Messages
12,794
Location
In the Machine
I am extracting audio from video and then trying to downsample the audio and write to wav file. However, so far my audio comes out as nothing but static! Can anybody point out the errors of my ways? it is probable that my wav header is messed up. but Im
not sure that this would cause the audio to sound as static.
<pre class="prettyprint // extract2.cpp : Defines the entry point for the console application.
//
#define WINVER _WIN32_WINNT_WIN7
#include "stdafx.h"
#include <windows.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include "AudioResampling.h"
#include <stdio.h>
#include <mferror.h>

template<class T> void SafeRelease(T **ppT);
HRESULT WriteWaveFile(IMFSourceReader *pReader, HANDLE hFile, LONG msecAudioData);
HRESULT ConfigureAudioStream(IMFSourceReader *pReader, IMFMediaType **ppPCMAudio );
HRESULT WriteWaveHeader(HANDLE hFile, IMFMediaType *pMediaType, DWORD *pcbWritten);
HRESULT WriteToFile(HANDLE hFile, void* p, DWORD cb);
DWORD CalculateMaxAudioDataSize(IMFMediaType *pAudioType, DWORD cbHeader, DWORD msecAudioData );
HRESULT WriteWaveData(HANDLE hFile, IMFSourceReader *pReader, DWORD cbMaxAudioData, DWORD *pcbDataWritten);
HRESULT FixUpChunkSizes(HANDLE hFile, DWORD cbHeader, DWORD cbAudioData);


template <class T> void SafeRelease(T **ppT)
{
if (*ppT)
{
(*ppT)->Release();
*ppT = NULL;
}
}


int _tmain(int argc, _TCHAR* argv[])
{
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);

if(argc != 3)
{
printf("args");
return 1;
}
const WCHAR *wszSourceFile = argv[1];
const WCHAR *wszTargetFile = argv[2];

const LONG MAX_AUDIO_DURATION_MSEC = 5000; // 5 seconds

HRESULT hr = S_OK;

IMFSourceReader *pReader = NULL;
HANDLE hFile = INVALID_HANDLE_VALUE;

// Initialize the COM library.
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

// Initialize the Media Foundation platform.
if (SUCCEEDED(hr))
{
hr = MFStartup(MF_VERSION);
}

// Create the source reader to read the input file.
if (SUCCEEDED(hr))
{
hr = MFCreateSourceReaderFromURL(wszSourceFile, NULL, &pReader);
if (FAILED(hr))
{
printf("Error opening input file: %Sn", wszSourceFile, hr);
}
}

// Open the output file for writing.
if (SUCCEEDED(hr))
{
hFile = CreateFile(wszTargetFile, GENERIC_WRITE, FILE_SHARE_READ, NULL,
CREATE_ALWAYS, 0, NULL);

if (hFile == INVALID_HANDLE_VALUE)
{
hr = HRESULT_FROM_WIN32(GetLastError());
printf("Cannot create output file: %Sn", wszTargetFile, hr);
}
}

// Write the WAVE file.
if (SUCCEEDED(hr))
{
hr = WriteWaveFile(pReader, hFile, MAX_AUDIO_DURATION_MSEC);
}

if (FAILED(hr))
{
printf("Failed, hr = 0x%Xn", hr);
}

// Clean up.
if (hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
}

SafeRelease(&pReader);
MFShutdown();
CoUninitialize();

return SUCCEEDED(hr) ? 0 : 1;

}


//-------------------------------------------------------------------
// WriteWaveFile
//
// Writes a WAVE file by getting audio data from the source reader.
//
//-------------------------------------------------------------------

HRESULT WriteWaveFile(IMFSourceReader *pReader, HANDLE hFile, LONG msecAudioData )
{
HRESULT hr = S_OK;

DWORD cbHeader = 0; // Size of the WAVE file header, in bytes.
DWORD cbAudioData = 0; // Total bytes of PCM audio data written to the file.
DWORD cbMaxAudioData = 0;

IMFMediaType *pAudioType = NULL; // Represents the PCM audio format.

// Configure the source reader to get uncompressed PCM audio from the source file.
hr = ConfigureAudioStream(pReader, &pAudioType);

// Write the WAVE file header.
if (SUCCEEDED(hr))
{
// header is written
hr = WriteWaveHeader(hFile, pAudioType, &cbHeader);
// wav header is written using our new format types
}

// Calculate the maximum amount of audio to decode, in bytes.
if (SUCCEEDED(hr))
{
cbMaxAudioData = CalculateMaxAudioDataSize(pAudioType, cbHeader, msecAudioData);

// Decode audio data to the file.
hr = WriteWaveData(hFile, pReader, cbMaxAudioData, &cbAudioData);

}

// Fix up the RIFF headers with the correct sizes.
// this is probably what the problem is
if (SUCCEEDED(hr))
{
hr = FixUpChunkSizes(hFile, cbHeader, cbAudioData);
}

SafeRelease(&pAudioType);
return hr;
}

//-------------------------------------------------------------------
// ConfigureAudioStream
//
// Selects an audio stream from the source file, and configures the
// stream to deliver decoded PCM audio.
//-------------------------------------------------------------------

HRESULT ConfigureAudioStream(IMFSourceReader *pReader, IMFMediaType **ppPCMAudio )
{
IMFMediaType *pUncompressedAudioType = NULL;
IMFMediaType *pPartialType = NULL;

// Select the first audio stream, and deselect all other streams.
HRESULT hr = pReader->SetStreamSelection(
(DWORD)MF_SOURCE_READER_ALL_STREAMS, FALSE);

if (SUCCEEDED(hr))
{
hr = pReader->SetStreamSelection(
(DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, TRUE);
}

// Create a partial media type that specifies uncompressed PCM audio.
hr = MFCreateMediaType(&pPartialType);

if (SUCCEEDED(hr))
{
hr = pPartialType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
}

if (SUCCEEDED(hr))
{
hr = pPartialType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
}

// Set this type on the source reader. The source reader will
// load the necessary decoder.
if (SUCCEEDED(hr))
{
hr = pReader->SetCurrentMediaType(
(DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,
NULL, pPartialType);
}

// Get the complete uncompressed format.
if (SUCCEEDED(hr))
{
hr = pReader->GetCurrentMediaType(
(DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,

&pUncompressedAudioType);
}

// Ensure the stream is selected.
if (SUCCEEDED(hr))
{
hr = pReader->SetStreamSelection(
(DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,
TRUE);
}

// Return the PCM format to the caller.
if (SUCCEEDED(hr))
{
*ppPCMAudio = pUncompressedAudioType;
(*ppPCMAudio)->AddRef();
}

SafeRelease(&pUncompressedAudioType);
SafeRelease(&pPartialType);
return hr;
}

//-------------------------------------------------------------------
// WriteWaveHeader
//
// Write the WAVE file header.
//
// Note: This function writes placeholder values for the file size
// and data size, as these values will need to be filled in later.
//-------------------------------------------------------------------

HRESULT WriteWaveHeader(HANDLE hFile, IMFMediaType *pMediaType, DWORD *pcbWritten )
{
HRESULT hr = S_OK;
UINT32 cbFormat = 0;

WAVEFORMATEX *pWav = NULL;


*pcbWritten = 0;

// Convert the PCM audio format into a WAVEFORMATEX structure.
hr = MFCreateWaveFormatExFromMFMediaType(pMediaType, &pWav, &cbFormat);



// Write the RIFF header and the start of the fmt chunk.
if (SUCCEEDED(hr))
{
DWORD header[] = {
// RIFF header
FCC(RIFF),
0,
FCC(WAVE),
// Start of fmt chunk
FCC(fmt ),
cbFormat
};


DWORD dataHeader[] = { FCC(data), 0 };

hr = WriteToFile(hFile, header, sizeof(header));

// Write the WAVEFORMATEX structure.
if (SUCCEEDED(hr))
{



hr = WriteToFile(hFile, pWav, cbFormat);
}

// Write the start of the data chunk

if (SUCCEEDED(hr))
{
hr = WriteToFile(hFile, dataHeader, sizeof(dataHeader));
}

if (SUCCEEDED(hr))
{
*pcbWritten = sizeof(header) + cbFormat + sizeof(dataHeader);
}
}


CoTaskMemFree(pWav);

return hr;
}


//-------------------------------------------------------------------
//
// Writes a block of data to a file
//
// hFile: Handle to the file.
// p: Pointer to the buffer to write.
// cb: Size of the buffer, in bytes.
//
//-------------------------------------------------------------------

HRESULT WriteToFile(HANDLE hFile, void* p, DWORD cb)
{
DWORD cbWritten = 0;
HRESULT hr = S_OK;

BOOL bResult = WriteFile(hFile, p, cb, &cbWritten, NULL);
if (!bResult)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
return hr;
}


//-------------------------------------------------------------------
// CalculateMaxAudioDataSize
//
// Calculates how much audio to write to the WAVE file, given the
// audio format and the maximum duration of the WAVE file.
//-------------------------------------------------------------------

DWORD CalculateMaxAudioDataSize(
IMFMediaType *pAudioType, // The PCM audio format.
DWORD cbHeader, // The size of the WAVE file header.
DWORD msecAudioData // Maximum duration, in milliseconds.
)
{
UINT32 cbBlockSize = 0; // Audio frame size, in bytes.
UINT32 cbBytesPerSecond = 0; // Bytes per second.

// Get the audio block size and number of bytes/second from the audio format.

cbBlockSize = MFGetAttributeUINT32(pAudioType, MF_MT_AUDIO_BLOCK_ALIGNMENT, 0);
cbBytesPerSecond = MFGetAttributeUINT32(pAudioType, MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 0);

// Calculate the maximum amount of audio data to write.
// This value equals (duration in seconds x bytes/second), but cannot
// exceed the maximum size of the data chunk in the WAVE file.

// Size of the desired audio clip in bytes:
DWORD cbAudioClipSize = (DWORD)MulDiv(cbBytesPerSecond, msecAudioData, 1000);

// Largest possible size of the data chunk:
DWORD cbMaxSize = MAXDWORD - cbHeader;

// Maximum size altogether.
cbAudioClipSize = min(cbAudioClipSize, cbMaxSize);

// Round to the audio block size, so that we do not write a partial audio frame.
cbAudioClipSize = (cbAudioClipSize / cbBlockSize) * cbBlockSize;

return cbAudioClipSize;
}


//-------------------------------------------------------------------
// WriteWaveData
//
// Decodes PCM audio data from the source file and writes it to
// the WAVE file.
//-------------------------------------------------------------------

HRESULT WriteWaveData(HANDLE hFile, IMFSourceReader *pReader, DWORD cbMaxAudioData, DWORD *pcbDataWritten)
{
HRESULT hr = S_OK;
DWORD cbAudioData = 0;
DWORD cbBuffer = 0;
BYTE *pAudioData = NULL;

IMFSample *pSample = NULL;
IMFMediaBuffer *pBuffer = NULL;


AudioResampling audioResampling;
try
{
audioResampling.Initialize(44100,2,8000,1); // init

}catch(...)
{
throw;
}
// Get audio samples from the source reader.
while (true)
{
DWORD dwFlags = 0;

// Read the next sample into IMFSample struct
hr = pReader->ReadSample((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, NULL, &dwFlags, NULL, &pSample );

LONGLONG sampleDuration;
pSample->GetSampleDuration(&sampleDuration); // this gives the sample duration as a LONGLONG
printf("sample duration %dn", sampleDuration);

if (FAILED(hr)) { break; }

if (dwFlags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)
{
printf("Type change - not supported by WAVE file format.n");
break;
}
if (dwFlags & MF_SOURCE_READERF_ENDOFSTREAM)
{
printf("End of input file.n");
break;
}

if (pSample == NULL)
{
printf("No samplen");
continue;
}

// Get a pointer to the audio data in the sample.
hr = pSample->ConvertToContiguousBuffer(&pBuffer); // contiguous buffer for memory access

DWORD mediaBufferCurrentLength;
pBuffer->GetCurrentLength(&mediaBufferCurrentLength); // gives us the current length of the sample as long
printf("media Buffer Current Length %dn", mediaBufferCurrentLength);

if (FAILED(hr)) { break; }


hr = pBuffer->Lock(&pAudioData, NULL, &cbBuffer); // [out] buffer as BYTE, [out]null, [out] current length

//unsigned int rawDataLength = (unsigned int)cbBuffer; // this may need to be 8192 == cbBuffer

//unsigned int resampledDataLength = (unsigned int)((__int64)rawDataLength * (8000 * 2) / (44100 * 2) + 2);
//short* resampledDataArray = new short[resampledDataLength / 2];
//unsigned int inputDataLength = 5000; // current length of sample
//unsigned int rawDataUsed;
//short* resampledData = &resampledDataArray[0];
//unsigned int resampledDataProduced;


unsigned int length;
length = (unsigned int)((__int64)mediaBufferCurrentLength * (8000 * 2) / (44100 * 2) + 2);
unsigned int inputDataUsed;
unsigned int outputProduced;
BYTE *outputData = new BYTE[length];
audioResampling.Resample(pAudioData, sampleDuration, &inputDataUsed, outputData, length, &outputProduced);

printf("output data %dn", outputData);
printf("pAudioData %dn", pAudioData);

if (FAILED(hr)) { break; }

// Make sure not to exceed the specified maximum size.
if (cbMaxAudioData - cbAudioData < cbBuffer) // (total length of full file - 0) < cbBuffer
{
cbBuffer = cbMaxAudioData - cbAudioData;
}

hr = WriteToFile(hFile, outputData, outputProduced);
//hr = WriteToFile(hFile, pAudioData, cbBuffer);

if (FAILED(hr)) { break; }

// Unlock the buffer.
hr = pBuffer->Unlock();
pAudioData = NULL; // reset to null
outputData = NULL;
if (FAILED(hr)) { break; }

// Update running total of audio data.
cbAudioData += cbBuffer; // cbAudioData = cbAudioData + cbBuffer (0 = 0 + 8192)

if (cbAudioData >= cbMaxAudioData)
{
break;
}


SafeRelease(&pSample);
SafeRelease(&pBuffer);

} // END WHILE

// what is pAudioData here?
if (SUCCEEDED(hr))
{
printf("Wrote %d bytes of audio data.n", cbAudioData);
*pcbDataWritten = cbAudioData;
}

if (pAudioData)
{
pBuffer->Unlock();
}

SafeRelease(&pBuffer);
SafeRelease(&pSample);
//sampleData.Release();
// when we get here it throws abort
return hr;
}


//-------------------------------------------------------------------
// FixUpChunkSizes
//
// Writes the file-size information into the WAVE file header.
//
// WAVE files use the RIFF file format. Each RIFF chunk has a data
// size, and the RIFF header has a total file size.
//-------------------------------------------------------------------

HRESULT FixUpChunkSizes(
HANDLE hFile, // Output file.
DWORD cbHeader, // Size of the fmt chuck.
DWORD cbAudioData // Size of the data chunk.
)
{
HRESULT hr = S_OK;

LARGE_INTEGER ll;
ll.QuadPart = cbHeader - sizeof(DWORD);

if (0 == SetFilePointerEx(hFile, ll, NULL, FILE_BEGIN))
{
hr = HRESULT_FROM_WIN32(GetLastError());
}

// Write the data size.

if (SUCCEEDED(hr))
{
hr = WriteToFile(hFile, &cbAudioData, sizeof(cbAudioData));
}

if (SUCCEEDED(hr))
{
// Write the file size.
ll.QuadPart = sizeof(FOURCC);

if (0 == SetFilePointerEx(hFile, ll, NULL, FILE_BEGIN))
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
}

if (SUCCEEDED(hr))
{
DWORD cbRiffFileSize = cbHeader + cbAudioData - 8;

// NOTE: The "size" field in the RIFF header does not include
// the first 8 bytes of the file. (That is, the size of the
// data that appears after the size field.)

hr = WriteToFile(hFile, &cbRiffFileSize, sizeof(cbRiffFileSize));
}

return hr;
}
[/code]
<br/><hr class="sig gymrat

View the full article
 
Back
Top