audio_reader::audio_reader(std::wstring& source) { { IMFByteStreamPtr stream; CHK(MFCreateFile(MF_FILE_ACCESSMODE::MF_ACCESSMODE_READ, MF_FILE_OPENMODE::MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILE_FLAGS::MF_FILEFLAGS_NONE, source.c_str(), &stream)); IMFAttributesPtr attr; CHK(MFCreateAttributes(&attr, 10)); CHK(attr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true)); IMFSourceReaderPtr reader; CHK(MFCreateSourceReaderFromByteStream(stream.Get(), attr.Get(), &reader)); // CHK(MFCreateSourceReaderFromURL(source.c_str(),attr.Get(), &reader)); CHK(reader.As(&reader_)); QWORD length; CHK(stream->GetLength(&length)); fileSize_ = length; } //CHK(reader_->GetServiceForStream(0, MF_WRAPPED_OBJECT, __uuidof(IMFByteStream), &stream)); CHK(reader_->GetNativeMediaType(0, 0, &native_media_type_)); CHK(MFCreateMediaType(¤t_media_type_)); CHK(current_media_type_->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio)); CHK(current_media_type_->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM)); CHK(current_media_type_->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, MFGetAttributeUINT32(native_media_type_.Get(), MF_MT_AUDIO_BITS_PER_SAMPLE, bits_per_sample) ) ); CHK(current_media_type_->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, MFGetAttributeUINT32(native_media_type_.Get(), MF_MT_AUDIO_SAMPLES_PER_SECOND, samples_per_second) )); CHK(current_media_type_->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, MFGetAttributeUINT32(native_media_type_.Get(), MF_MT_AUDIO_NUM_CHANNELS, channel_count) )); //DWORD blockAlign; //CHK(native_media_type_->GetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, &blockAlign)); //CHK(current_media_type_->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT,blockAlign )); CHK(reader_->SetCurrentMediaType(0, nullptr, current_media_type_.Get())); CHK(reader_->GetCurrentMediaType(0, current_media_type_.ReleaseAndGetAddressOf())); UINT32 blockAlign; CHK(current_media_type_->GetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, &blockAlign)); DOUT(boost::wformat(L"Block Align: %10d %10x") % blockAlign % blockAlign); }
static int MediaFoundation_open(Sound_Sample *sample, const char *ext) { MediaFoundationFileContainer* media_foundation_file_container; Sound_SampleInternal* internal = (Sound_SampleInternal*)sample->opaque; HRESULT hresult; IMFSourceReader* source_reader = NULL; // Since the byte stream stuff is so complicated, if you need to test without it, // you can hard code loading a file and use MFCreateSourceReaderFromURL. // const WCHAR* source_file = L"C:\\Users\\username\\Documents\\crystal.wav"; // const WCHAR* source_file = L"C:\\Users\\username\\Documents\\battle_hymn_of_the_republic.mp3"; // const WCHAR* source_file = L"C:\\Users\\username\\Documents\\TheDeclarationOfIndependencePreambleJFK.m4a"; IMFByteStreamRWops* byte_stream = new IMFByteStreamRWops(internal->rw, sample); // hresult = MFCreateSourceReaderFromURL(source_file, NULL, &source_reader); hresult = MFCreateSourceReaderFromByteStream(byte_stream, NULL, &source_reader); if (FAILED(hresult)) { SNDERR("Error opening input file"); return 0; } media_foundation_file_container = (MediaFoundationFileContainer*)calloc(1, sizeof(MediaFoundationFileContainer)); BAIL_IF_MACRO(media_foundation_file_container == NULL, ERR_OUT_OF_MEMORY, 0); internal->decoder_private = media_foundation_file_container; media_foundation_file_container->sourceReader = source_reader; media_foundation_file_container->byteStreamRWops = byte_stream; { HRESULT hr = hresult; IMFMediaType *pUncompressedAudioType = NULL; IMFMediaType* audio_type = NULL; // Select the first audio stream, and deselect all other streams. hr = source_reader->SetStreamSelection((DWORD)MF_SOURCE_READER_ALL_STREAMS, false); if (SUCCEEDED(hr)) { // select first stream hr = source_reader->SetStreamSelection((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, true); } // Getting format data and debugging { // Not sure of the difference between GetNativeMediaType/GetNativeMediaType. // Search suggests GetCurrentMediaType gets the complete uncompressed format. // hr = source_reader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, &audio_type); // The method returns a copy of the media type, so it is safe to modify the object received in the ppMediaType parameter. hr = source_reader->GetNativeMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, // Index of the media type to retreive (don't really know what that means) &audio_type ); if(FAILED(hr)) { SNDERR("GetNativeMediaType failed"); free(media_foundation_file_container); SafeRelease(&source_reader); return 0; } UINT32 all_samples_independent = 0; UINT32 fixed_size_samples = 0; UINT32 sample_size = 0; UINT32 bits_per_sample = 0; UINT32 block_alignment = 0; UINT32 num_channels = 0; UINT32 samples_per_second = 0; hr = audio_type->GetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, &all_samples_independent); hr = audio_type->GetUINT32(MF_MT_FIXED_SIZE_SAMPLES, &fixed_size_samples); hr = audio_type->GetUINT32(MF_MT_SAMPLE_SIZE, &sample_size); hr = audio_type->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, &bits_per_sample); hr = audio_type->GetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment); hr = audio_type->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &num_channels); hr = audio_type->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &samples_per_second); SNDDBG2("WindowsMediaFoundation: all_samples_independent == (%d).\n", all_samples_independent); SNDDBG2("WindowsMediaFoundation: fixed_size_samples == (%d).\n", fixed_size_samples); SNDDBG2("WindowsMediaFoundation: sample_size == (%d).\n", sample_size); SNDDBG2("WindowsMediaFoundation: bits_per_sample == (%d).\n", bits_per_sample); SNDDBG2("WindowsMediaFoundation: block_alignment == (%d).\n", block_alignment); SNDDBG2("WindowsMediaFoundation: num_channels == (%d).\n", num_channels); SNDDBG2("WindowsMediaFoundation: samples_per_second == (%d).\n", samples_per_second); // Get the total length of the stream PROPVARIANT prop_variant; double duration_in_milliseconds = -1.0; // get the duration, which is a 64-bit integer of 100-nanosecond units hr = source_reader->GetPresentationAttribute(MF_SOURCE_READER_MEDIASOURCE, MF_PD_DURATION, &prop_variant); if(FAILED(hr)) { SNDERR("WindowsMediaFoundation: Failed to get duration"); duration_in_milliseconds = -1.0; } else { LONGLONG file_duration = prop_variant.uhVal.QuadPart; //double durationInSeconds = (file_duration / static_cast<double>(10000 * 1000)); duration_in_milliseconds = (file_duration / static_cast<double>(10000)); } PropVariantClear(&prop_variant); sample->flags = SOUND_SAMPLEFLAG_CANSEEK; sample->actual.rate = samples_per_second; sample->actual.channels = (UINT8)num_channels; internal->total_time = (INT32)(duration_in_milliseconds + 0.5); /* * I want to use the native system to do conversion and decoding for performance reasons. * This is particularly important on mobile devices like iOS. * Taking from the Ogg Vorbis decode, I pretend the "actual" format is the same * as the desired format. */ if(0 == sample->desired.format) { sample->actual.format = AUDIO_S16SYS; } else { sample->actual.format = sample->desired.format; } SNDDBG2("WindowsMediaFoundation: total seconds of sample == (%d).\n", internal->total_time); // For compressed files, the bits per sample is undefined if(0 == bits_per_sample) { // hard code to 16 media_foundation_file_container->bitsPerSample = 16; } else { media_foundation_file_container->bitsPerSample = bits_per_sample; } SafeRelease(&audio_type); } { IMFMediaType* target_audio_type = NULL; // Create a partial media type that specifies uncompressed PCM audio. hr = MFCreateMediaType(&target_audio_type); if(FAILED(hr)) { SNDERR("WindowsMediaFoundation: Failed to create target MediaType\n"); SafeRelease(&source_reader); free(media_foundation_file_container); } hr = target_audio_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio); if(FAILED(hr)) { SNDERR("WindowsMediaFoundation: Failed to set MFMediaType_Audio\n"); SafeRelease(&target_audio_type); SafeRelease(&source_reader); free(media_foundation_file_container); return 0; } // We want to decode to raw PCM hr = target_audio_type->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM); if(FAILED(hr)) { SNDERR("WindowsMediaFoundation: Failed to set MFAudioFormat_PCM\n"); SafeRelease(&target_audio_type); SafeRelease(&source_reader); free(media_foundation_file_container); return 0; } // Set this type on the source reader. The source reader will // load the necessary decoder. hr = source_reader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, NULL, target_audio_type); if(FAILED(hr)) { SNDERR("WindowsMediaFoundation: Failed to set SetCurrentMediaType\n"); SafeRelease(&target_audio_type); SafeRelease(&source_reader); free(media_foundation_file_container); return 0; } // Don't need this any more SafeRelease(&target_audio_type); } // specify the output type (pcm) { IMFMediaType* uncompressed_audio_type = NULL; // Get the complete uncompressed format. hr = source_reader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, &uncompressed_audio_type); if(FAILED(hr)) { SNDERR("WindowsMediaFoundation: Failed to set SetCurrentMediaType\n"); SafeRelease(&source_reader); free(media_foundation_file_container); return 0; } hr = source_reader->SetStreamSelection((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, true); // Ensure the stream is selected. if(FAILED(hr)) { SNDERR("WindowsMediaFoundation: Failed to set SetCurrentMediaType\n"); SafeRelease(&uncompressed_audio_type); SafeRelease(&source_reader); free(media_foundation_file_container); return 0; } // libaudiodecoder UINT32 leftover_buffer_size = 0; hr = uncompressed_audio_type->GetUINT32(MF_MT_SAMPLE_SIZE, &leftover_buffer_size); if(FAILED(hr)) { // EW: MS docs say this will fail for varible length samples (proably aac, etc?) // So this could happen a lot. // So far, haven't noticed adverse effects. SNDDBG2("WindowsMediaFoundation: Failed to get leftover_buffer_size\n"); leftover_buffer_size = 32; } media_foundation_file_container->leftoverBufferSize = leftover_buffer_size; media_foundation_file_container->leftoverBufferSize = leftover_buffer_size; media_foundation_file_container->leftoverBufferSize /= 2; // convert size in bytes to size in int16s media_foundation_file_container->leftoverBuffer = (short*)malloc(media_foundation_file_container->leftoverBufferSize * sizeof(short)); media_foundation_file_container->uncompressedAudioType = uncompressed_audio_type; media_foundation_file_container->uncompressedAudioType->AddRef(); SafeRelease(&uncompressed_audio_type); } } return(1); } /* MediaFoundation_open */