예제 #1
0
static HRESULT
CreateAudioMediaType(const WWMFPcmFormat &fmt, IMFMediaType** ppMediaType)
{
    HRESULT hr;
    IMFMediaType *pMediaType = NULL;
    *ppMediaType = NULL;

    HRG(MFCreateMediaType(&pMediaType) );
    HRG(pMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio));
    HRG(pMediaType->SetGUID(MF_MT_SUBTYPE,
            (fmt.sampleFormat == WWMFBitFormatInt) ? MFAudioFormat_PCM : MFAudioFormat_Float));
    HRG(pMediaType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS,         fmt.nChannels));
    HRG(pMediaType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND,   fmt.sampleRate));
    HRG(pMediaType->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT,      fmt.FrameBytes()));
    HRG(pMediaType->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, fmt.BytesPerSec()));
    HRG(pMediaType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE,      fmt.bits));
    HRG(pMediaType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT,    TRUE));
    if (0 != fmt.dwChannelMask) {
        HRG(pMediaType->SetUINT32(MF_MT_AUDIO_CHANNEL_MASK, fmt.dwChannelMask));
    }
    if (fmt.bits != fmt.validBitsPerSample) {
        HRG(pMediaType->SetUINT32(MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, fmt.validBitsPerSample));
    }

    *ppMediaType = pMediaType;
    pMediaType = NULL; //< prevent release

end:
    SafeRelease(&pMediaType);
    return hr;
}
예제 #2
0
static HRESULT
WriteWavHeader(FILE *fpw, WWMFPcmFormat &format, DWORD dataBytes)
{
    HRESULT hr = E_FAIL;
    int dataChunkSize = ((dataBytes+1)&(~1)) + 4;

    HRG(WriteBytes(fpw, "RIFF", 4U));
    HRG(WriteInt32(fpw, dataChunkSize + 0x24));
    HRG(WriteBytes(fpw, "WAVE", 4U));

    HRG(WriteBytes(fpw, "fmt ", 4U));
    HRG(WriteInt32(fpw, 16));

    // fmt audioFormat size==2 1==int 3==float
    switch (format.sampleFormat) {
    case WWMFBitFormatInt:
        HRG(WriteInt16(fpw, 1));
        break;
    case WWMFBitFormatFloat:
        HRG(WriteInt16(fpw, 3));
        break;
    default:
        goto end;
    }

    // fmt numChannels size==2
    HRG(WriteInt16(fpw, format.nChannels));

    // fmt sampleRate size==4
    HRG(WriteInt32(fpw, format.sampleRate));

    // fmt byteRate size==4
    HRG(WriteInt32(fpw, format.BytesPerSec()));

    // fmt blockAlign size==2
    HRG(WriteInt16(fpw, format.FrameBytes()));

    // fmt bitspersample size==2
    HRG(WriteInt16(fpw, format.bits));

    HRG(WriteBytes(fpw, "data", 4U));
    HRG(WriteInt32(fpw, dataChunkSize));

end:
    return hr;
}
예제 #3
0
int wmain(int argc, wchar_t *argv[])
{
    // _CrtSetBreakAlloc(35);
    // COM leak cannot be detected by debug heap manager ...
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

    HRESULT hr = S_OK;
    bool bCoInitialize = false;
    FILE *fpr = NULL;
    FILE *fpw = NULL;
    errno_t ercd;
    BYTE *buff = NULL;
    DWORD buffBytes = 0;
    DWORD readBytes = 0;
    DWORD remainBytes = 0;
    DWORD expectedOutputDataBytes = 0;
    DWORD result = 0;
    DWORD writeDataTotalBytes = 0;
    int conversionQuality = 60;
    WWMFResampler resampler;
    WWMFPcmFormat inputFormat;
    WWMFPcmFormat outputFormat;
    WWMFSampleData sampleData;

    if (argc != 6) {
        PrintUsage(argv[0]);
        return 1;
    }

    HRG(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE));
    bCoInitialize = true;

    ercd = _wfopen_s(&fpr, argv[1], L"rb");
    if (0 != ercd) {
        printf("file open error %S\n", argv[1]);
        PrintUsage(argv[0]);
        hr = E_FAIL;
        goto end;
    }

    ercd = _wfopen_s(&fpw, argv[2], L"wb");
    if (0 != ercd) {
        printf("file open error %S\n", argv[2]);
        PrintUsage(argv[0]);
        hr = E_FAIL;
        goto end;
    }

    HRG(ReadWavHeader(fpr, &inputFormat, &remainBytes));

    outputFormat = inputFormat;
    outputFormat.sampleRate = _wtoi(argv[3]);
    outputFormat.bits = (short)_wtoi(argv[4]);

    conversionQuality = _wtoi(argv[5]);

    if (0 == outputFormat.sampleRate ||
        0 == conversionQuality) {
        PrintUsage(argv[0]);
        hr = E_FAIL;
        goto end;
    }

    outputFormat.validBitsPerSample = outputFormat.bits;

    switch (outputFormat.bits) {
    case 16:
    case 24:
        outputFormat.sampleFormat = WWMFBitFormatInt;
        break;
    case 32:
        outputFormat.sampleFormat = WWMFBitFormatFloat;
        break;
    default:
        PrintUsage(argv[0]);
        hr = E_FAIL;
        goto end;
    }

    expectedOutputDataBytes = (int64_t)remainBytes
        * outputFormat.BytesPerSec()
        / inputFormat .BytesPerSec();

    HRG(WriteWavHeader(fpw, outputFormat, expectedOutputDataBytes));

    HRG(resampler.Initialize(inputFormat, outputFormat, conversionQuality));

    buffBytes = 128 * 1024 * inputFormat.FrameBytes();
    buff = new BYTE[buffBytes];

    for (;;) {
        // read PCM data from file
        readBytes = buffBytes;
        if (remainBytes < readBytes) {
            readBytes = remainBytes;
        }
        remainBytes -= readBytes;

        result = fread(buff, 1, readBytes, fpr);
        if (result != readBytes) {
            printf("file read error\n");
            hr = E_FAIL;
            goto end;
        }

        // convert
        HRG(resampler.Resample(buff, readBytes, &sampleData));

        // write to file
        result = fwrite(sampleData.data, 1, sampleData.bytes, fpw);
        if (result != sampleData.bytes) {
            printf("file write error\n");
            hr = E_FAIL;
            goto end;
        }
        writeDataTotalBytes += sampleData.bytes;
        sampleData.Release();

        if (remainBytes == 0) {
            // end
            HRG(resampler.Drain(buffBytes, &sampleData));

            // write remaining PCM data to file
            result = fwrite(sampleData.data, 1, sampleData.bytes, fpw);
            if (result != sampleData.bytes) {
                printf("file write error\n");
                hr = E_FAIL;
                goto end;
            }
            writeDataTotalBytes += sampleData.bytes;
            sampleData.Release();
            break;
        }
    }

    // data chunk align is 2 bytes
    if (writeDataTotalBytes & 1) {
        if (0 != fputc(0, fpw)) {
            printf("file write error\n");
            hr = E_FAIL;
            goto end;
        }
        ++writeDataTotalBytes;
    }
    HRG(FixWavHeader(fpw, writeDataTotalBytes));

    hr = S_OK;

end:
    resampler.Finalize();

    if (bCoInitialize) {
        CoUninitialize();
        bCoInitialize = false;
    }

    delete[] buff;
    buff = NULL;

    if (fpw != NULL) {
        fclose(fpw);
        fpw = NULL;
    }
    if (fpr != NULL) {
        fclose(fpr);
        fpr = NULL;
    }

    return SUCCEEDED(hr) ? 0 : 1;
}
예제 #4
0
TBool AudioDriver::CheckMixFormat(TUint aSampleRate,
                                  TUint aNumChannels,
                                  TUint aBitDepth)
{
    HRESULT       hr;
    WAVEFORMATEX *closestMix;
    WAVEFORMATEX  savedMixFormat;
    TBool         retVal = false;

    // Complete any previous resampling session.
    if (iResamplingInput)
    {
        WWMFSampleData sampleData;

        hr = iResampler.Drain((iBufferSize * iFrameSize), &sampleData);

        if (hr == S_OK)
        {
            Log::Print("Resampler drained correctly [%d bytes].\n",
                       sampleData.bytes);

            sampleData.Release();
        }
        else
        {
            Log::Print("Resample drain failed.\n");
        }

        iResampler.Finalize();
    }

    iResamplingInput  = false;

    // Verify the Audio Engine supports the stream format.
    if (iMixFormat == NULL)
    {
        hr = iAudioClient->GetMixFormat(&iMixFormat);
        if (hr != S_OK)
        {
            Log::Print("ERROR: Could not obtain mix system format.\n");
            return false;
        }
    }

    savedMixFormat = *iMixFormat;

    iMixFormat->wFormatTag      = WAVE_FORMAT_PCM;
    iMixFormat->nChannels       = (WORD)aNumChannels;
    iMixFormat->nSamplesPerSec  = aSampleRate;
    iMixFormat->nBlockAlign     = WORD((aNumChannels * aBitDepth)/8);
    iMixFormat->nAvgBytesPerSec = DWORD(aSampleRate * iMixFormat->nBlockAlign);
    iMixFormat->wBitsPerSample  = (WORD)aBitDepth;
    iMixFormat->cbSize          = 0;

    hr = iAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED,
                                         iMixFormat,
                                        &closestMix);

    if (hr != S_OK)
    {
        // The stream format isn't suitable as it stands.
        //
        // Use a media foundation translation to convert to the current
        // mix format.

        //
        // Load the active mix format.
        //
        CoTaskMemFree(iMixFormat);

        hr = iAudioClient->GetMixFormat(&iMixFormat);

        if (hr == S_OK)
        {
            iMixFormat->wFormatTag = WAVE_FORMAT_PCM;
            iMixFormat->cbSize     = 0;

            // Confirm the mix format s valid.
            CoTaskMemFree(closestMix);

            hr = iAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED,
                                                 iMixFormat,
                                                &closestMix);

            if (hr != S_OK)
            {
                Log::Print("ERROR: Cannot obtain valid mix format for stream "
                           "translation\n");

                retVal = false;

                goto end;
            }

            // Setup the translation.

            // Input stream format.
            WWMFPcmFormat inputFormat;

            inputFormat.sampleFormat       = WWMFBitFormatInt;
            inputFormat.nChannels          = (WORD)aNumChannels;
            inputFormat.sampleRate         = aSampleRate;
            inputFormat.bits               = (WORD)aBitDepth;
            inputFormat.validBitsPerSample = (WORD)aBitDepth;

            // System mix format.
            WWMFPcmFormat outputFormat;

            outputFormat.sampleFormat       = WWMFBitFormatInt;
            outputFormat.nChannels          = iMixFormat->nChannels;
            outputFormat.sampleRate         = iMixFormat->nSamplesPerSec;
            outputFormat.bits               = iMixFormat->wBitsPerSample;
            outputFormat.validBitsPerSample = iMixFormat->wBitsPerSample;

            // Store bytes per second values for later calculations around
            // the amount of data generated by the translation.
            iResampleInputBps  = inputFormat.BytesPerSec();
            iResampleOutputBps = outputFormat.BytesPerSec();

            if (iResampler.Initialize(inputFormat,
                                      outputFormat, 60) == S_OK)
            {
                iResamplingInput  = true;
                retVal            = true;
            }
            else
            {
                Log::Print("ERROR: Stream Transaltion Failed.\n");

                Log::Print("Transalte From:\n\n");

                Log::Print("\tSample Rate:        %6u\n", aSampleRate);
                Log::Print("\tNumber Of Channels: %6u\n", aNumChannels);
                Log::Print("\tBit Depth:          %6u\n", aBitDepth);

                Log::Print("Translate To:\n\n");

                Log::Print("\tSample Rate:        %6u\n",
                           iMixFormat->nSamplesPerSec);
                Log::Print("\tNumber Of Channels: %6u\n",
                           iMixFormat->nChannels);
                Log::Print("\tBit Depth:          %6u\n",
                           iMixFormat->wBitsPerSample);
            }
        }
    }
    else
    {
        retVal = true;
    }

end:
    CoTaskMemFree(closestMix);

    return retVal;
}