Note: Forums will be making significant UX changes to address key usability improvements surrounding search, discoverability and navigation. To learn more about these changes please visit the announcement which can be found HERE.

Respondido alter code to write to memory

  • quarta-feira, 15 de agosto de 2012 22:04
     
      Contém Código

    How can I alter the given code to write this wav file to memory instead of to a file?

    // extraction.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include <Windows.h>
    #include <mfapi.h>
    #include <mfidl.h>
    #include <mfreadwrite.h>
    #include <stdint.h>
    #include <Mferror.h>
    
    using namespace System;
    using namespace System::IO;
    
    /* prototypes */
    HRESULT WriteWaveFile(IMFSourceReader *pReader, HANDLE hFile, LONG msecAudioData);
    HRESULT FixUpChunkSizes(HANDLE, DWORD cbHeader, DWORD cbAudioData);
    HRESULT WriteWaveData(HANDLE hFile, IMFSourceReader *pReader, DWORD cbMaxAudioData, DWORD *pcbDataWritten);
    DWORD CalculateMaxAudioDataSize(IMFMediaType *pAudioType, DWORD cbHeader, DWORD msecAudioData);
    HRESULT WriteToFile(HANDLE hFile, void* p, DWORD cb);
    HRESULT WriteWaveHeader(HANDLE hFile, IMFMediaType *pMediaType, DWORD *pcbWritten);
    HRESULT ConfigureAudioStream(IMFSourceReader *pReader, IMFMediaType **ppPCMAudio);
    HRESULT WriteWaveFile(IMFSourceReader *pReader, HANDLE hFile, LONG msecAudioData);
    template <class T> void SafeRelease(T **ppT);
    
    /* pre processor */
    #define SAMPLING_AUDIO 44100
    #define CHANNEL_AUDIO 2
    
    
    
    int _tmain(int argc,  _TCHAR* argv[])//_TCHAR*
    {
    	
    	
    	HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
    	/*if (argc != 3)
        {
            printf("arguments: input_file output_file.wav\n");
            return 1;
        }*/
    
    	
        
    	
    	const WCHAR *wszSourceFile = argv[1];
        const WCHAR *wszTargetFile = argv[2];
    
    	const LONG MAX_AUDIO_DURATION_MSEC = 10000; // 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: %S\n", 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: %S\n", wszTargetFile, hr);
            }
        }
    
        // Write the WAVE file.
        if (SUCCEEDED(hr))
        {
    		hr = WriteWaveFile(pReader, hFile, MAX_AUDIO_DURATION_MSEC);
        }
    
        if (FAILED(hr))
        {
            printf("Failed, hr = 0x%X\n", 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,   // Pointer to the source reader.
        HANDLE hFile,               // Handle to the output file.
        LONG msecAudioData          // Maximum amount of audio data to write, in msec.
        )
    {
        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))
        {
            hr = WriteWaveHeader(hFile, pAudioType, &cbHeader);
        }
    	// write the wave file header to byte array
    
    
        // 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.
        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,   // Pointer to the source reader.
        IMFMediaType **ppPCMAudio   // Receives the audio format.
        )
    {
        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,               // Output file.
        IMFMediaType *pMediaType,   // PCM audio format.
        DWORD *pcbWritten           // Receives the size of the header.
        )
    {
        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)); // first writes the header
    
            // Write the WAVEFORMATEX structure.
            if (SUCCEEDED(hr))
            {
                hr = WriteToFile(hFile, pWav, cbFormat); // 2. write the waveformat ex struct to file
            }
    
            // Write the start of the 'data' chunk
    
            if (SUCCEEDED(hr))
            {
                hr = WriteToFile(hFile, dataHeader, sizeof(dataHeader)); // 3. write the 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;
    
    	printf("p currently is %s\n",p);
    	printf("cb currently is %s\n", &cb);
    	
    	// cb is number of bytes to write
    	// p is the buffer
    	// cb written is number of bytes written
    	// NULL value is overlapped bytes
        
    	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,               // Output file.
        IMFSourceReader *pReader,   // Source reader.
        DWORD cbMaxAudioData,       // Maximum amount of audio data (bytes).
        DWORD *pcbDataWritten       // Receives the amount of data written.
        )
    {
        HRESULT hr = S_OK;
        DWORD cbAudioData = 0;
        DWORD cbBuffer = 0;
        BYTE *pAudioData = NULL;
    
        IMFSample *pSample = NULL;
        IMFMediaBuffer *pBuffer = NULL;
    
        // Get audio samples from the source reader.
        while (true)
        {
            DWORD dwFlags = 0;
    
            // Read the next sample.
            hr = pReader->ReadSample((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, NULL, &dwFlags, NULL, &pSample );
    
            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 sample\n");
                continue;
            }
    
            // Get a pointer to the audio data in the sample.
    
            hr = pSample->ConvertToContiguousBuffer(&pBuffer);
    
            if (FAILED(hr)) { break; }
    
    
            hr = pBuffer->Lock(&pAudioData, NULL, &cbBuffer);
    
            if (FAILED(hr)) { break; }
    
    
            // Make sure not to exceed the specified maximum size.
            if (cbMaxAudioData - cbAudioData < cbBuffer)
            {
                cbBuffer = cbMaxAudioData - cbAudioData;
            }
    
            // Write this data to the output file.
            hr = WriteToFile(hFile, pAudioData, cbBuffer);
    
            if (FAILED(hr)) { break; }
    
            // Unlock the buffer.
            hr = pBuffer->Unlock();
            pAudioData = NULL;
    
            if (FAILED(hr)) { break; }
    
            // Update running total of audio data.
            cbAudioData += cbBuffer;
    
            if (cbAudioData >= cbMaxAudioData)
            {
                break;
            }
    
            SafeRelease(&pSample);
            SafeRelease(&pBuffer);
        }
    
        if (SUCCEEDED(hr))
        {
            printf("Wrote %d bytes of audio data.\n", cbAudioData);
    
            *pcbDataWritten = cbAudioData;
        }
    
        if (pAudioData)
        {
            pBuffer->Unlock();
        }
    
        SafeRelease(&pBuffer);
        SafeRelease(&pSample);
        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;
    }
    
    
    template <class T> void SafeRelease(T **ppT)
    {
        if (*ppT)
        {
            (*ppT)->Release();
            *ppT = NULL;
        }
    }

    Any help would be great!

Todas as Respostas

  • quinta-feira, 16 de agosto de 2012 02:14
     
     

    >>How can I alter the given code to write this wav file to memory instead of to a file?

    The code is writing from memory to wav file when it calls WriteToFile with pAudioData. So your question is puzzling: The data is already in memory at pAudioData and you are asking how to write it to memory.

  • quinta-feira, 16 de agosto de 2012 06:44
     
     

    Hi Scott,

    You are right, I should have been more specific. :)

    The end goal here is to downsample (or resample) the wav file while in memory.

    something to the effect:

    myResampler.ResampleAudio(pAudioData, // this would be the wav data
                                 5, // size of the wav data
                                 &rawDataUsed, // buffer
                                 (BYTE*)resampledData, // out
                                 resampledDataLength, // out
                                 &resampledDataProduced); //out

    A better suited question would be:

    1. "Where (in the earlier posted code) would I conduct the resampling?" I feel like the method WriteWaveData would be smart.

    2. "Do I need to include the wav header when resampling?"


    gymrat

  • quinta-feira, 16 de agosto de 2012 13:32
     
     Respondido

    You could conduct the resampling as soon as you get the data. Apparently that would be just before the call to WriteWaveData.

    What are you going to do with the resampled data? A new wav header will be needed if you will be writing the resampled data to a wav file, or if you will be playing the resampled audio.

    • Marcado como Resposta Kswing quinta-feira, 16 de agosto de 2012 19:31
    •  
  • domingo, 26 de agosto de 2012 20:26
     
      Contém Código

    hey scott. My resampling is currently shoving out static. I can not figure out what the problem is. Hoping you could shed some light on this. I am posting the only part of the code I have edited below

    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 %d\n", 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 sample\n");
                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 %d\n", 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 %d\n", outputData);
    		printf("pAudioData %d\n", 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);
    	
    	return hr;
    }


    gymrat

  • terça-feira, 28 de agosto de 2012 01:46
    Moderador
     
     

    Hi Kswing,

    You have opened a new thread asking the shoving out static problem. Please follow the new thread to get help: http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/2b3c632f-509e-4684-9141-477835c5a483

    Thanks,


    Damon Zheng [MSFT]
    MSDN Community Support | Feedback to us