Advertisement
Guest User

Untitled

a guest
Aug 19th, 2016
2,127
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #define WINVER _WIN32_WINNT_WIN7
  2.  
  3. #ifndef _UNICODE
  4.   #define _UNICODE
  5. #endif
  6.  
  7. #include <windows.h>
  8. #include <mfapi.h>
  9. #include <mfidl.h>
  10. #include <mfreadwrite.h>
  11. #include <stdio.h>
  12. #include <mferror.h>
  13.  
  14. #pragma comment(lib, "mfplat.lib")
  15. #pragma comment(lib, "mfreadwrite.lib")
  16. #pragma comment(lib, "mfuuid.lib")
  17.  
  18. template <class T> void SafeRelease(T **ppT)
  19. {
  20.   if (*ppT)
  21.   {
  22.     (*ppT)->Release();
  23.     *ppT = NULL;
  24.   }
  25. }
  26.  
  27. //-------------------------------------------------------------------
  28. //
  29. // Writes a block of data to a file
  30. //
  31. // hFile: Handle to the file.
  32. // p: Pointer to the buffer to write.
  33. // cb: Size of the buffer, in bytes.
  34. //
  35. //-------------------------------------------------------------------
  36.  
  37. HRESULT WriteToFile(HANDLE hFile, void* p, DWORD cb)
  38. {
  39.   DWORD cbWritten = 0;
  40.   HRESULT hr = S_OK;
  41.  
  42.   BOOL bResult = WriteFile(hFile, p, cb, &cbWritten, NULL);
  43.   if (!bResult)
  44.   {
  45.     hr = HRESULT_FROM_WIN32(GetLastError());
  46.   }
  47.   return hr;
  48. }
  49.  
  50. //-------------------------------------------------------------------
  51. // FixUpChunkSizes
  52. //
  53. // Writes the file-size information into the WAVE file header.
  54. //
  55. // WAVE files use the RIFF file format. Each RIFF chunk has a data
  56. // size, and the RIFF header has a total file size.
  57. //-------------------------------------------------------------------
  58.  
  59. HRESULT FixUpChunkSizes(
  60.   HANDLE hFile,           // Output file.
  61.   DWORD cbHeader,         // Size of the 'fmt ' chuck.
  62.   DWORD cbAudioData       // Size of the 'data' chunk.
  63. )
  64. {
  65.   HRESULT hr = S_OK;
  66.  
  67.   LARGE_INTEGER ll;
  68.   ll.QuadPart = cbHeader - sizeof(DWORD);
  69.  
  70.   if (0 == SetFilePointerEx(hFile, ll, NULL, FILE_BEGIN))
  71.   {
  72.     hr = HRESULT_FROM_WIN32(GetLastError());
  73.   }
  74.  
  75.   // Write the data size.
  76.  
  77.   if (SUCCEEDED(hr))
  78.   {
  79.     hr = WriteToFile(hFile, &cbAudioData, sizeof(cbAudioData));
  80.   }
  81.  
  82.   if (SUCCEEDED(hr))
  83.   {
  84.     // Write the file size.
  85.     ll.QuadPart = sizeof(FOURCC);
  86.  
  87.     if (0 == SetFilePointerEx(hFile, ll, NULL, FILE_BEGIN))
  88.     {
  89.       hr = HRESULT_FROM_WIN32(GetLastError());
  90.     }
  91.   }
  92.  
  93.   if (SUCCEEDED(hr))
  94.   {
  95.     DWORD cbRiffFileSize = cbHeader + cbAudioData - 8;
  96.  
  97.     // NOTE: The "size" field in the RIFF header does not include
  98.     // the first 8 bytes of the file. (That is, the size of the
  99.     // data that appears after the size field.)
  100.  
  101.     hr = WriteToFile(hFile, &cbRiffFileSize, sizeof(cbRiffFileSize));
  102.   }
  103.  
  104.   return hr;
  105. }
  106.  
  107.  
  108. //-------------------------------------------------------------------
  109. // WriteWaveData
  110. //
  111. // Decodes PCM audio data from the source file and writes it to
  112. // the WAVE file.
  113. //-------------------------------------------------------------------
  114.  
  115. HRESULT WriteWaveData(
  116.   HANDLE hFile,               // Output file.
  117.   IMFSourceReader *pReader,   // Source reader.
  118.   DWORD cbMaxAudioData,       // Maximum amount of audio data (bytes).
  119.   DWORD *pcbDataWritten       // Receives the amount of data written.
  120. )
  121. {
  122.   HRESULT hr = S_OK;
  123.   DWORD cbAudioData = 0;
  124.   DWORD cbBuffer = 0;
  125.   BYTE *pAudioData = NULL;
  126.  
  127.   IMFSample *pSample = NULL;
  128.   IMFMediaBuffer *pBuffer = NULL;
  129.  
  130.   // Get audio samples from the source reader.
  131.   while (true)
  132.   {
  133.     DWORD dwFlags = 0;
  134.  
  135.     // Read the next sample.
  136.     hr = pReader->ReadSample(
  137.       (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,
  138.       0, NULL, &dwFlags, NULL, &pSample);
  139.  
  140.     if (FAILED(hr)) { break; }
  141.  
  142.     if (dwFlags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)
  143.     {
  144.       printf("Type change - not supported by WAVE file format.\n");
  145.       break;
  146.     }
  147.     if (dwFlags & MF_SOURCE_READERF_ENDOFSTREAM)
  148.     {
  149.       printf("End of input file.\n");
  150.       break;
  151.     }
  152.  
  153.     if (pSample == NULL)
  154.     {
  155.       printf("No sample\n");
  156.       continue;
  157.     }
  158.  
  159.     // Get a pointer to the audio data in the sample.
  160.  
  161.     hr = pSample->ConvertToContiguousBuffer(&pBuffer);
  162.  
  163.     if (FAILED(hr)) { break; }
  164.  
  165.  
  166.     hr = pBuffer->Lock(&pAudioData, NULL, &cbBuffer);
  167.  
  168.     if (FAILED(hr)) { break; }
  169.  
  170.  
  171.     // Make sure not to exceed the specified maximum size.
  172.     if (cbMaxAudioData - cbAudioData < cbBuffer)
  173.     {
  174.       cbBuffer = cbMaxAudioData - cbAudioData;
  175.     }
  176.  
  177.     // Write this data to the output file.
  178.     hr = WriteToFile(hFile, pAudioData, cbBuffer);
  179.  
  180.     if (FAILED(hr)) { break; }
  181.  
  182.     // Unlock the buffer.
  183.     hr = pBuffer->Unlock();
  184.     pAudioData = NULL;
  185.  
  186.     if (FAILED(hr)) { break; }
  187.  
  188.     // Update running total of audio data.
  189.     cbAudioData += cbBuffer;
  190.  
  191.     if (cbAudioData >= cbMaxAudioData)
  192.     {
  193.       break;
  194.     }
  195.  
  196.     SafeRelease(&pSample);
  197.     SafeRelease(&pBuffer);
  198.   }
  199.  
  200.   if (SUCCEEDED(hr))
  201.   {
  202.     printf("Wrote %d bytes of audio data.\n", cbAudioData);
  203.  
  204.     *pcbDataWritten = cbAudioData;
  205.   }
  206.  
  207.   if (pAudioData)
  208.   {
  209.     pBuffer->Unlock();
  210.   }
  211.  
  212.   SafeRelease(&pBuffer);
  213.   SafeRelease(&pSample);
  214.   return hr;
  215. }
  216.  
  217.  
  218. //-------------------------------------------------------------------
  219. // CalculateMaxAudioDataSize
  220. //
  221. // Calculates how much audio to write to the WAVE file, given the
  222. // audio format and the maximum duration of the WAVE file.
  223. //-------------------------------------------------------------------
  224.  
  225. DWORD CalculateMaxAudioDataSize(
  226.   IMFMediaType *pAudioType,    // The PCM audio format.
  227.   DWORD cbHeader,              // The size of the WAVE file header.
  228.   DWORD msecAudioData          // Maximum duration, in milliseconds.
  229. )
  230. {
  231.   UINT32 cbBlockSize = 0;         // Audio frame size, in bytes.
  232.   UINT32 cbBytesPerSecond = 0;    // Bytes per second.
  233.  
  234.                                   // Get the audio block size and number of bytes/second from the audio format.
  235.  
  236.   cbBlockSize = MFGetAttributeUINT32(pAudioType, MF_MT_AUDIO_BLOCK_ALIGNMENT, 0);
  237.   cbBytesPerSecond = MFGetAttributeUINT32(pAudioType, MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 0);
  238.  
  239.   // Calculate the maximum amount of audio data to write.
  240.   // This value equals (duration in seconds x bytes/second), but cannot
  241.   // exceed the maximum size of the data chunk in the WAVE file.
  242.  
  243.   // Size of the desired audio clip in bytes:
  244.   DWORD cbAudioClipSize = (DWORD)MulDiv(cbBytesPerSecond, msecAudioData, 1000);
  245.  
  246.   // Largest possible size of the data chunk:
  247.   DWORD cbMaxSize = MAXDWORD - cbHeader;
  248.  
  249.   // Maximum size altogether.
  250.   cbAudioClipSize = min(cbAudioClipSize, cbMaxSize);
  251.  
  252.   // Round to the audio block size, so that we do not write a partial audio frame.
  253.   cbAudioClipSize = (cbAudioClipSize / cbBlockSize) * cbBlockSize;
  254.  
  255.   return cbAudioClipSize;
  256. }
  257.  
  258.  
  259. //-------------------------------------------------------------------
  260. // WriteWaveHeader
  261. //
  262. // Write the WAVE file header.
  263. //
  264. // Note: This function writes placeholder values for the file size
  265. // and data size, as these values will need to be filled in later.
  266. //-------------------------------------------------------------------
  267.  
  268. HRESULT WriteWaveHeader(
  269.   HANDLE hFile,               // Output file.
  270.   IMFMediaType *pMediaType,   // PCM audio format.
  271.   DWORD *pcbWritten           // Receives the size of the header.
  272. )
  273. {
  274.   HRESULT hr = S_OK;
  275.   UINT32 cbFormat = 0;
  276.  
  277.   WAVEFORMATEX *pWav = NULL;
  278.  
  279.   *pcbWritten = 0;
  280.  
  281.   // Convert the PCM audio format into a WAVEFORMATEX structure.
  282.   hr = MFCreateWaveFormatExFromMFMediaType(pMediaType, &pWav, &cbFormat);
  283.  
  284.   // Write the 'RIFF' header and the start of the 'fmt ' chunk.
  285.   if (SUCCEEDED(hr))
  286.   {
  287.     DWORD header[] = {
  288.       // RIFF header
  289.       FCC('RIFF'),
  290.       0,
  291.       FCC('WAVE'),
  292.       // Start of 'fmt ' chunk
  293.       FCC('fmt '),
  294.       cbFormat
  295.     };
  296.  
  297.     DWORD dataHeader[] = { FCC('data'), 0 };
  298.  
  299.     hr = WriteToFile(hFile, header, sizeof(header));
  300.  
  301.     // Write the WAVEFORMATEX structure.
  302.     if (SUCCEEDED(hr))
  303.     {
  304.       hr = WriteToFile(hFile, pWav, cbFormat);
  305.     }
  306.  
  307.     // Write the start of the 'data' chunk
  308.  
  309.     if (SUCCEEDED(hr))
  310.     {
  311.       hr = WriteToFile(hFile, dataHeader, sizeof(dataHeader));
  312.     }
  313.  
  314.     if (SUCCEEDED(hr))
  315.     {
  316.       *pcbWritten = sizeof(header) + cbFormat + sizeof(dataHeader);
  317.     }
  318.   }
  319.   CoTaskMemFree(pWav);
  320.   return hr;
  321. }
  322.  
  323. //-------------------------------------------------------------------
  324. // ConfigureAudioStream
  325. //
  326. // Selects an audio stream from the source file, and configures the
  327. // stream to deliver decoded PCM audio.
  328. //-------------------------------------------------------------------
  329.  
  330. HRESULT ConfigureAudioStream(
  331.   IMFSourceReader *pReader,   // Pointer to the source reader.
  332.   IMFMediaType **ppPCMAudio   // Receives the audio format.
  333. )
  334. {
  335.   IMFMediaType *pUncompressedAudioType = NULL;
  336.   IMFMediaType *pPartialType = NULL;
  337.  
  338.   // Select the first audio stream, and deselect all other streams.
  339.   HRESULT hr = pReader->SetStreamSelection(
  340.     (DWORD)MF_SOURCE_READER_ALL_STREAMS, FALSE);
  341.  
  342.   if (SUCCEEDED(hr))
  343.   {
  344.     hr = pReader->SetStreamSelection(
  345.       (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, TRUE);
  346.   }
  347.  
  348.   // Create a partial media type that specifies uncompressed PCM audio.
  349.   hr = MFCreateMediaType(&pPartialType);
  350.  
  351.   if (SUCCEEDED(hr))
  352.   {
  353.     hr = pPartialType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
  354.   }
  355.  
  356.   if (SUCCEEDED(hr))
  357.   {
  358.     hr = pPartialType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
  359.   }
  360.  
  361.   // Set this type on the source reader. The source reader will
  362.   // load the necessary decoder.
  363.   if (SUCCEEDED(hr))
  364.   {
  365.     hr = pReader->SetCurrentMediaType(
  366.       (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,
  367.       NULL, pPartialType);
  368.   }
  369.  
  370.   // Get the complete uncompressed format.
  371.   if (SUCCEEDED(hr))
  372.   {
  373.     hr = pReader->GetCurrentMediaType(
  374.       (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,
  375.       &pUncompressedAudioType);
  376.   }
  377.  
  378.   // Ensure the stream is selected.
  379.   if (SUCCEEDED(hr))
  380.   {
  381.     hr = pReader->SetStreamSelection(
  382.       (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,
  383.       TRUE);
  384.   }
  385.  
  386.   // Return the PCM format to the caller.
  387.   if (SUCCEEDED(hr))
  388.   {
  389.     *ppPCMAudio = pUncompressedAudioType;
  390.     (*ppPCMAudio)->AddRef();
  391.   }
  392.  
  393.   SafeRelease(&pUncompressedAudioType);
  394.   SafeRelease(&pPartialType);
  395.   return hr;
  396. }
  397.  
  398.  
  399. //-------------------------------------------------------------------
  400. // WriteWaveFile
  401. //
  402. // Writes a WAVE file by getting audio data from the source reader.
  403. //
  404. //-------------------------------------------------------------------
  405.  
  406. HRESULT WriteWaveFile(
  407.   IMFSourceReader *pReader,   // Pointer to the source reader.
  408.   HANDLE hFile,               // Handle to the output file.
  409.   LONG msecAudioData          // Maximum amount of audio data to write, in msec.
  410. )
  411. {
  412.   HRESULT hr = S_OK;
  413.  
  414.   DWORD cbHeader = 0;         // Size of the WAVE file header, in bytes.
  415.   DWORD cbAudioData = 0;      // Total bytes of PCM audio data written to the file.
  416.   DWORD cbMaxAudioData = 0;
  417.  
  418.   IMFMediaType *pAudioType = NULL;    // Represents the PCM audio format.
  419.  
  420.                                       // Configure the source reader to get uncompressed PCM audio from the source file.
  421.  
  422.   hr = ConfigureAudioStream(pReader, &pAudioType);
  423.  
  424.   // Write the WAVE file header.
  425.   if (SUCCEEDED(hr))
  426.   {
  427.     hr = WriteWaveHeader(hFile, pAudioType, &cbHeader);
  428.   }
  429.  
  430.   // Calculate the maximum amount of audio to decode, in bytes.
  431.   if (SUCCEEDED(hr))
  432.   {
  433.     cbMaxAudioData = CalculateMaxAudioDataSize(pAudioType, cbHeader, msecAudioData);
  434.  
  435.     // Decode audio data to the file.
  436.     hr = WriteWaveData(hFile, pReader, cbMaxAudioData, &cbAudioData);
  437.   }
  438.  
  439.   // Fix up the RIFF headers with the correct sizes.
  440.   if (SUCCEEDED(hr))
  441.   {
  442.     hr = FixUpChunkSizes(hFile, cbHeader, cbAudioData);
  443.   }
  444.  
  445.   SafeRelease(&pAudioType);
  446.   return hr;
  447. }
  448.  
  449.  
  450. int wmain(int argc, wchar_t* argv[])
  451. {
  452.   HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
  453.  
  454.   if (argc != 3)
  455.   {
  456.     printf("arguments: input_file output_file.wav\n");
  457.     return 1;
  458.   }
  459.  
  460.   const WCHAR *wszSourceFile = argv[1];
  461.   const WCHAR *wszTargetFile = argv[2];
  462.  
  463.   const LONG MAX_AUDIO_DURATION_MSEC = 5000; // 5 seconds
  464.  
  465.   HRESULT hr = S_OK;
  466.  
  467.   IMFSourceReader *pReader = NULL;
  468.   HANDLE hFile = INVALID_HANDLE_VALUE;
  469.  
  470.   // Initialize the COM library.
  471.   hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
  472.  
  473.   // Initialize the Media Foundation platform.
  474.   if (SUCCEEDED(hr))
  475.   {
  476.     hr = MFStartup(MF_VERSION);
  477.   }
  478.  
  479.   // Create the source reader to read the input file.
  480.   if (SUCCEEDED(hr))
  481.   {
  482.     hr = MFCreateSourceReaderFromURL(wszSourceFile, NULL, &pReader);
  483.     if (FAILED(hr))
  484.     {
  485.       printf("Error opening input file: %S 0x%08lx\n", wszSourceFile, hr);
  486.     }
  487.   }
  488.  
  489.   // Open the output file for writing.
  490.   if (SUCCEEDED(hr))
  491.   {
  492.     hFile = CreateFile(wszTargetFile, GENERIC_WRITE, FILE_SHARE_READ, NULL,
  493.       CREATE_ALWAYS, 0, NULL);
  494.  
  495.     if (hFile == INVALID_HANDLE_VALUE)
  496.     {
  497.       hr = HRESULT_FROM_WIN32(GetLastError());
  498.       printf("Cannot create output file: %S 0x%08lx\n", wszTargetFile, hr);
  499.     }
  500.   }
  501.  
  502.   // Write the WAVE file.
  503.   if (SUCCEEDED(hr))
  504.   {
  505.     hr = WriteWaveFile(pReader, hFile, MAX_AUDIO_DURATION_MSEC);
  506.   }
  507.  
  508.   if (FAILED(hr))
  509.   {
  510.     printf("Failed, hr = 0x%X\n", hr);
  511.   }
  512.  
  513.   // Clean up.
  514.   if (hFile != INVALID_HANDLE_VALUE)
  515.   {
  516.     CloseHandle(hFile);
  517.   }
  518.  
  519.   SafeRelease(&pReader);
  520.   MFShutdown();
  521.   CoUninitialize();
  522.  
  523.   return SUCCEEDED(hr) ? 0 : 1;
  524. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement