MFMediaEngineAudioStream.cpp (5328B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "MFMediaEngineAudioStream.h" 6 7 #include <mfapi.h> 8 #include <mferror.h> 9 10 #include "MFMediaEngineUtils.h" 11 #include "WMFUtils.h" 12 #include "mozilla/StaticPrefs_media.h" 13 14 namespace mozilla { 15 16 #define LOG(msg, ...) \ 17 MOZ_LOG(gMFMediaEngineLog, LogLevel::Debug, \ 18 ("MFMediaStream=%p (%s), " msg, this, \ 19 this->GetDescriptionName().get(), ##__VA_ARGS__)) 20 21 using Microsoft::WRL::ComPtr; 22 using Microsoft::WRL::MakeAndInitialize; 23 24 /* static */ 25 MFMediaEngineAudioStream* MFMediaEngineAudioStream::Create( 26 uint64_t aStreamId, const TrackInfo& aInfo, bool aIsEncryptedCustomInit, 27 MFMediaSource* aParentSource) { 28 MOZ_ASSERT(aInfo.IsAudio()); 29 MFMediaEngineAudioStream* stream; 30 if (FAILED(MakeAndInitialize<MFMediaEngineAudioStream>( 31 &stream, aStreamId, aInfo, aIsEncryptedCustomInit, aParentSource))) { 32 return nullptr; 33 } 34 return stream; 35 } 36 37 HRESULT MFMediaEngineAudioStream::CreateMediaType(const TrackInfo& aInfo, 38 IMFMediaType** aMediaType) { 39 const AudioInfo& info = *aInfo.GetAsAudioInfo(); 40 mAudioInfo = info; 41 GUID subType = AudioMimeTypeToMediaFoundationSubtype(info.mMimeType); 42 NS_ENSURE_TRUE(subType != GUID_NULL, MF_E_TOPO_CODEC_NOT_FOUND); 43 44 // https://docs.microsoft.com/en-us/windows/win32/medfound/media-type-attributes 45 ComPtr<IMFMediaType> mediaType; 46 RETURN_IF_FAILED(wmf::MFCreateMediaType(&mediaType)); 47 RETURN_IF_FAILED(mediaType->SetGUID(MF_MT_SUBTYPE, subType)); 48 RETURN_IF_FAILED(mediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio)); 49 RETURN_IF_FAILED( 50 mediaType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, info.mChannels)); 51 RETURN_IF_FAILED( 52 mediaType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, info.mRate)); 53 uint64_t bitDepth = info.mBitDepth != 0 ? info.mBitDepth : 16; 54 RETURN_IF_FAILED(mediaType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, bitDepth)); 55 if (subType == MFAudioFormat_AAC) { 56 if (mAACUserData.IsEmpty()) { 57 MOZ_ASSERT(info.mCodecSpecificConfig.is<AacCodecSpecificData>() || 58 info.mCodecSpecificConfig.is<AudioCodecSpecificBinaryBlob>()); 59 RefPtr<MediaByteBuffer> blob; 60 if (info.mCodecSpecificConfig.is<AacCodecSpecificData>()) { 61 blob = info.mCodecSpecificConfig.as<AacCodecSpecificData>() 62 .mDecoderConfigDescriptorBinaryBlob; 63 } else { 64 blob = info.mCodecSpecificConfig.as<AudioCodecSpecificBinaryBlob>() 65 .mBinaryBlob; 66 } 67 AACAudioSpecificConfigToUserData(info.mExtendedProfile, blob->Elements(), 68 blob->Length(), mAACUserData); 69 LOG("Generated AAC user data"); 70 } 71 RETURN_IF_FAILED( 72 mediaType->SetUINT32(MF_MT_AAC_PAYLOAD_TYPE, 0x0)); // Raw AAC packet 73 RETURN_IF_FAILED(mediaType->SetBlob( 74 MF_MT_USER_DATA, mAACUserData.Elements(), mAACUserData.Length())); 75 } 76 LOG("Created audio type, subtype=%s, channel=%" PRIu32 ", rate=%" PRIu32 77 ", bitDepth=%" PRIu64 ", encrypted=%d", 78 GUIDToStr(subType), info.mChannels, info.mRate, bitDepth, 79 mAudioInfo.mCrypto.IsEncrypted()); 80 81 if (IsEncrypted()) { 82 ComPtr<IMFMediaType> protectedMediaType; 83 RETURN_IF_FAILED(wmf::MFWrapMediaType(mediaType.Get(), 84 MFMediaType_Protected, subType, 85 protectedMediaType.GetAddressOf())); 86 LOG("Wrap MFMediaType_Audio into MFMediaType_Protected"); 87 *aMediaType = protectedMediaType.Detach(); 88 } else { 89 *aMediaType = mediaType.Detach(); 90 } 91 return S_OK; 92 } 93 94 bool MFMediaEngineAudioStream::HasEnoughRawData() const { 95 // If more than this much raw audio is queued, we'll hold off request more 96 // audio. 97 return mRawDataQueueForFeedingEngine.PreciseDuration() >= 98 StaticPrefs::media_wmf_media_engine_raw_data_threshold_audio(); 99 } 100 101 already_AddRefed<MediaData> MFMediaEngineAudioStream::OutputDataInternal() { 102 AssertOnTaskQueue(); 103 if (mRawDataQueueForGeneratingOutput.GetSize() == 0) { 104 return nullptr; 105 } 106 // The media engine doesn't provide a way to allow us to access decoded audio 107 // frames, and the audio playback will be handled internally inside the media 108 // engine. So we simply return fake audio data. 109 RefPtr<MediaRawData> input = mRawDataQueueForGeneratingOutput.PopFront(); 110 RefPtr<MediaData> output = 111 new AudioData(input->mOffset, input->mTime, AlignedAudioBuffer{}, 112 mAudioInfo.mChannels, mAudioInfo.mRate); 113 return output.forget(); 114 } 115 116 nsCString MFMediaEngineAudioStream::GetCodecName() const { 117 WMFStreamType type = GetStreamTypeFromMimeType(mAudioInfo.mMimeType); 118 switch (type) { 119 case WMFStreamType::MP3: 120 return "mp3"_ns; 121 case WMFStreamType::AAC: 122 return "aac"_ns; 123 case WMFStreamType::OPUS: 124 return "opus"_ns; 125 case WMFStreamType::VORBIS: 126 return "vorbis"_ns; 127 default: 128 return "unknown"_ns; 129 } 130 } 131 132 bool MFMediaEngineAudioStream::IsEncrypted() const { 133 return mAudioInfo.mCrypto.IsEncrypted() || mIsEncryptedCustomInit; 134 } 135 136 #undef LOG 137 138 } // namespace mozilla