blob: 85c03b1aea78f1f4007d17165ad194887e60a799 [file] [log] [blame]
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "starboard/shared/win32/audio_transform.h"
#include <vector>
#include "starboard/memory.h"
#include "starboard/shared/win32/error_utils.h"
#include "starboard/shared/win32/media_common.h"
#include "starboard/shared/win32/media_foundation_utils.h"
namespace starboard {
namespace shared {
namespace win32 {
using Microsoft::WRL::ComPtr;
namespace {
GUID ConvertToWin32AudioCodec(SbMediaAudioCodec codec) {
switch (codec) {
case kSbMediaAudioCodecNone: {
return MFAudioFormat_PCM;
}
case kSbMediaAudioCodecAac: {
return MFAudioFormat_AAC;
}
case kSbMediaAudioCodecOpus: {
return MFAudioFormat_Opus;
}
default: {
SB_NOTIMPLEMENTED();
return MFAudioFormat_PCM;
}
}
}
class WinAudioFormat {
public:
explicit WinAudioFormat(const SbMediaAudioHeader& audio_header) {
// The WAVEFORMATEX structure has many specializations with varying
// data attached at the end.
format_buffer_.resize(sizeof(WAVEFORMATEX) +
audio_header.audio_specific_config_size);
WAVEFORMATEX* wave_format = WaveFormatData();
wave_format->nAvgBytesPerSec = audio_header.average_bytes_per_second;
wave_format->nBlockAlign = audio_header.block_alignment;
wave_format->nChannels = audio_header.number_of_channels;
wave_format->nSamplesPerSec = audio_header.samples_per_second;
wave_format->wBitsPerSample = audio_header.bits_per_sample;
wave_format->wFormatTag = audio_header.format_tag;
wave_format->cbSize = audio_header.audio_specific_config_size;
if (audio_header.audio_specific_config_size > 0) {
uint8_t* config_data = format_buffer_.data() + sizeof(WAVEFORMATEX);
SbMemoryCopy(config_data,
audio_header.audio_specific_config,
audio_header.audio_specific_config_size);
}
}
WAVEFORMATEX* WaveFormatData() {
return reinterpret_cast<WAVEFORMATEX*>(format_buffer_.data());
}
UINT32 Size() const { return static_cast<UINT32>(format_buffer_.size()); }
private:
std::vector<uint8_t> format_buffer_;
};
} // namespace.
scoped_ptr<MediaTransform> CreateAudioTransform(
const SbMediaAudioHeader& audio,
SbMediaAudioCodec codec) {
ComPtr<IMFTransform> transform;
HRESULT hr = CreateDecoderTransform(CLSID_MSAACDecMFT, &transform);
CheckResult(hr);
ComPtr<IMFMediaType> input_type;
hr = MFCreateMediaType(&input_type);
CheckResult(hr);
WinAudioFormat audio_fmt(audio);
hr = MFInitMediaTypeFromWaveFormatEx(
input_type.Get(), audio_fmt.WaveFormatData(), audio_fmt.Size());
CheckResult(hr);
hr = input_type->SetUINT32(MF_MT_AAC_PAYLOAD_TYPE, 0); // raw aac
CheckResult(hr);
GUID win32_audio_type = ConvertToWin32AudioCodec(codec);
hr = input_type->SetGUID(MF_MT_SUBTYPE, win32_audio_type);
CheckResult(hr);
std::vector<ComPtr<IMFMediaType>> available_types =
GetAllInputMediaTypes(MediaTransform::kStreamId, transform.Get());
available_types = FilterMediaBySubType(available_types, win32_audio_type);
SB_DCHECK(available_types.size());
ComPtr<IMFMediaType> selected = available_types[0];
std::vector<GUID> attribs = {
MF_MT_AUDIO_BLOCK_ALIGNMENT, MF_MT_AUDIO_SAMPLES_PER_SECOND,
MF_MT_AUDIO_AVG_BYTES_PER_SECOND, MF_MT_AUDIO_NUM_CHANNELS,
};
for (auto it = attribs.begin(); it != attribs.end(); ++it) {
CopyUint32Property(*it, input_type.Get(), selected.Get());
}
scoped_ptr<MediaTransform> output(new MediaTransform(transform));
output->SetInputType(selected);
output->SetOutputTypeBySubType(MFAudioFormat_Float);
return output.Pass();
}
} // namespace win32
} // namespace shared
} // namespace starboard