blob: f07ed62b3a7df4ff927c2fec286a8adfed3cfe6c [file] [log] [blame]
// Copyright 2017 The Cobalt Authors. 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/media_foundation_utils.h"
#include <Mfapi.h>
#include <Mferror.h>
#include <propvarutil.h>
#include <ios>
#include <sstream>
#include <utility>
#include <vector>
#include "starboard/common/log.h"
#include "starboard/shared/win32/error_utils.h"
namespace starboard {
namespace shared {
namespace win32 {
namespace {
#define MAKE_GUID_PAIR(X) std::pair<GUID, std::string>(X, #X)
const std::pair<GUID, std::string> kMfMtAudio[] = {
MAKE_GUID_PAIR(MF_MT_AAC_PAYLOAD_TYPE),
MAKE_GUID_PAIR(MF_MT_AUDIO_AVG_BYTES_PER_SECOND),
MAKE_GUID_PAIR(MF_MT_AUDIO_BITS_PER_SAMPLE),
MAKE_GUID_PAIR(MF_MT_AUDIO_BLOCK_ALIGNMENT),
MAKE_GUID_PAIR(MF_MT_AUDIO_CHANNEL_MASK),
MAKE_GUID_PAIR(MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND),
MAKE_GUID_PAIR(MF_MT_AUDIO_NUM_CHANNELS),
MAKE_GUID_PAIR(MF_MT_AUDIO_SAMPLES_PER_BLOCK),
MAKE_GUID_PAIR(MF_MT_AUDIO_SAMPLES_PER_SECOND),
MAKE_GUID_PAIR(MF_MT_AUDIO_NUM_CHANNELS),
MAKE_GUID_PAIR(MF_MT_MAJOR_TYPE),
MAKE_GUID_PAIR(MF_MT_AUDIO_PREFER_WAVEFORMATEX),
MAKE_GUID_PAIR(MF_MT_USER_DATA),
MAKE_GUID_PAIR(MF_MT_SUBTYPE),
MAKE_GUID_PAIR(MFAudioFormat_AAC),
MAKE_GUID_PAIR(MFAudioFormat_ADTS),
MAKE_GUID_PAIR(MFAudioFormat_ALAC),
MAKE_GUID_PAIR(MFAudioFormat_AMR_NB),
MAKE_GUID_PAIR(MFAudioFormat_AMR_WB),
MAKE_GUID_PAIR(MFAudioFormat_AMR_WP),
MAKE_GUID_PAIR(MFAudioFormat_Dolby_AC3),
MAKE_GUID_PAIR(MFAudioFormat_Dolby_AC3_SPDIF),
MAKE_GUID_PAIR(MFAudioFormat_Dolby_DDPlus),
MAKE_GUID_PAIR(MFAudioFormat_DRM),
MAKE_GUID_PAIR(MFAudioFormat_DTS),
MAKE_GUID_PAIR(MFAudioFormat_FLAC),
MAKE_GUID_PAIR(MFAudioFormat_Float),
MAKE_GUID_PAIR(MFAudioFormat_Float_SpatialObjects),
MAKE_GUID_PAIR(MFAudioFormat_MP3),
MAKE_GUID_PAIR(MFAudioFormat_MPEG),
MAKE_GUID_PAIR(MFAudioFormat_MSP1),
MAKE_GUID_PAIR(MFAudioFormat_Opus),
MAKE_GUID_PAIR(MFAudioFormat_PCM),
MAKE_GUID_PAIR(MFAudioFormat_WMASPDIF),
MAKE_GUID_PAIR(MFAudioFormat_WMAudio_Lossless),
MAKE_GUID_PAIR(MFAudioFormat_WMAudioV8),
MAKE_GUID_PAIR(MFAudioFormat_WMAudioV9),
MAKE_GUID_PAIR(MFAudioFormat_WMAudioV9),
MAKE_GUID_PAIR(MFMediaType_Audio),
};
#undef MAKE_GUID_PAIR
std::string GuidToFallbackString(GUID guid) {
std::stringstream ss;
wchar_t* guid_str = nullptr;
StringFromCLSID(guid, &guid_str);
ss << guid_str;
CoTaskMemFree(guid_str);
return ss.str();
}
std::string MfGuidToString(GUID guid) {
const size_t n = sizeof(kMfMtAudio) / sizeof(*kMfMtAudio);
for (auto i = 0; i < n; ++i) {
const auto& elems = kMfMtAudio[i];
if (guid == elems.first) {
return elems.second;
}
}
return GuidToFallbackString(guid);
}
std::string ImfAttributesToString(IMFAttributes* type) {
std::stringstream ss;
UINT32 n = 0;
HRESULT hr = type->GetCount(&n);
CheckResult(hr);
for (UINT32 i = 0; i < n; ++i) {
GUID key;
PROPVARIANT val;
type->GetItemByIndex(i, &key, &val);
PropVariantClear(&val);
MF_ATTRIBUTE_TYPE attrib_type;
hr = type->GetItemType(key, &attrib_type);
CheckResult(hr);
std::string key_str = MfGuidToString(key);
ss << key_str << ": ";
switch (attrib_type) {
case MF_ATTRIBUTE_GUID: {
GUID value_guid;
hr = type->GetGUID(key, &value_guid);
ss << MfGuidToString(value_guid) << "\n";
break;
}
case MF_ATTRIBUTE_DOUBLE: {
double value = 0;
hr = type->GetDouble(key, &value);
ss << value << "\n";
break;
}
case MF_ATTRIBUTE_BLOB: {
// Skip.
ss << "<BLOB>"
<< "\n";
break;
}
case MF_ATTRIBUTE_UINT32: {
UINT32 int_val = 0;
hr = type->GetUINT32(key, &int_val);
ss << int_val << "\n";
break;
}
case MF_ATTRIBUTE_UINT64: {
UINT64 int_val = 0;
hr = type->GetUINT64(key, &int_val);
ss << int_val << "\n";
break;
}
case MF_ATTRIBUTE_STRING: {
UINT32 length = 0;
hr = type->GetStringLength(key, &length);
CheckResult(hr);
++length; // For trailing 0.
std::vector<wchar_t> buffer(length);
hr = type->GetString(key, buffer.data(), length, NULL);
CheckResult(hr);
ss << buffer.data() << "\n";
break;
}
case MF_ATTRIBUTE_IUNKNOWN: {
SB_NOTIMPLEMENTED();
break;
}
}
}
ss << "\n";
return ss.str();
}
} // namespace.
void CopyProperties(IMFMediaType* source, IMFMediaType* destination) {
UINT32 attribute_count = 0;
HRESULT hr = source->GetCount(&attribute_count);
CheckResult(hr);
for (UINT32 i = 0; i < attribute_count; ++i) {
GUID key;
PROPVARIANT variant;
hr = source->GetItemByIndex(i, &key, &variant);
CheckResult(hr);
PropVariantClear(&variant);
MF_ATTRIBUTE_TYPE attrib_type;
hr = source->GetItemType(key, &attrib_type);
CheckResult(hr);
switch (attrib_type) {
case MF_ATTRIBUTE_GUID: {
GUID value_guid;
hr = source->GetGUID(key, &value_guid);
CheckResult(hr);
hr = destination->SetGUID(key, value_guid);
CheckResult(hr);
break;
}
case MF_ATTRIBUTE_DOUBLE: {
double value = 0;
hr = source->GetDouble(key, &value);
CheckResult(hr);
hr = destination->SetDouble(key, value);
CheckResult(hr);
break;
}
case MF_ATTRIBUTE_BLOB: {
UINT32 blob_size = 0;
hr = source->GetBlobSize(key, &blob_size);
CheckResult(hr);
std::vector<UINT8> blob(blob_size);
hr = source->GetBlob(key, blob.data(), blob_size, &blob_size);
CheckResult(hr);
hr = destination->SetBlob(key, blob.data(), blob_size);
CheckResult(hr);
break;
}
case MF_ATTRIBUTE_UINT32: {
UINT32 int_val = 0;
hr = source->GetUINT32(key, &int_val);
CheckResult(hr);
hr = destination->SetUINT32(key, int_val);
CheckResult(hr);
break;
}
case MF_ATTRIBUTE_UINT64: {
UINT64 int_val = 0;
hr = source->GetUINT64(key, &int_val);
CheckResult(hr);
hr = destination->SetUINT64(key, int_val);
CheckResult(hr);
break;
}
case MF_ATTRIBUTE_STRING: {
UINT32 length = 0;
hr = source->GetStringLength(key, &length);
CheckResult(hr);
++length; // For trailing 0.
std::vector<wchar_t> buffer(length);
hr = source->GetString(key, buffer.data(), length, NULL);
CheckResult(hr);
hr = destination->SetString(key, buffer.data());
CheckResult(hr);
break;
}
case MF_ATTRIBUTE_IUNKNOWN: {
SB_NOTIMPLEMENTED();
break;
}
}
}
}
std::ostream& operator<<(std::ostream& os, const IMFMediaType& media_type) {
const IMFAttributes* attribs = &media_type; // Upcast.
std::string output_str =
ImfAttributesToString(const_cast<IMFAttributes*>(attribs));
os << output_str;
return os;
}
} // namespace win32
} // namespace shared
} // namespace starboard