Skip to content

Instantly share code, notes, and snippets.

@Gnomorian
Created March 12, 2022 18:27
Show Gist options
  • Save Gnomorian/7c6f0252eee399eeb73eaa2026d1bcd2 to your computer and use it in GitHub Desktop.
Save Gnomorian/7c6f0252eee399eeb73eaa2026d1bcd2 to your computer and use it in GitHub Desktop.
get media metadata from a file
#include <iostream>
#include <Windows.h>
#include <filesystem>
#include <array>
#include <string>
#include <string_view>
#include <vector>
#include <variant>
#include <Wmsdk.h>
#include <stdexcept>
#pragma comment(lib, "Wmvcore.lib")
using std::filesystem::path, std::wcout;
void writeHelp(std::wstring_view message = {})
{
wcout << message << std::endl;
std::array<wchar_t, MAX_PATH> buffer;
const auto actualLength = GetModuleFileNameW(nullptr, buffer.data(), buffer.size());
std::wstring_view exePath(buffer.data(), actualLength);
wcout << exePath << L" <filePath>" << std::endl;
}
struct MetadataName
{
WORD languageIndex;
std::wstring name;
};
using Attribute = std::variant<DWORD, QWORD, BOOL, std::vector<BYTE>, std::wstring>;
using Metadata = std::pair < MetadataName, Attribute>;
std::vector<Metadata> getFileMetadata(path fileName)
{
auto result = CoInitialize(nullptr);
if (result != S_OK)
throw std::runtime_error{ "error in CoInitialize" };
IWMMetadataEditor* editor{ nullptr };
result = WMCreateEditor(&editor);
if (result != S_OK)
throw std::runtime_error("error in WMCreateEditor");
IWMHeaderInfo3* headerinfo{ nullptr };
result = editor->QueryInterface(&headerinfo);
if (result != S_OK)
throw std::runtime_error("error in QueryInterface<IWMHeaderInfo3>");
result = editor->Open(fileName.wstring().c_str());
if (result != S_OK)
throw std::runtime_error{ "error in IWMMetadataEditor::Open" };
constexpr DWORD streamNumber{0xFFFF};
WORD attributeCount{ 0 };
result = headerinfo->GetAttributeCount(streamNumber, &attributeCount);
if (result != S_OK)
throw std::runtime_error{ "error in IWMHeaderInfo3::GetAttributeCount" };
std::vector<Metadata> fileMetadata;
fileMetadata.reserve(attributeCount);
for (int i{0}; i < attributeCount; i++)
{
WORD nameLen{ 0 };
DWORD dataLen{ 0 };
result = headerinfo->GetAttributeByIndexEx(streamNumber, i, nullptr, &nameLen, nullptr, nullptr, nullptr, &dataLen);
if (result != S_OK)
{
throw std::runtime_error{ "error in IWMHeaderInfo3::GetAttributeByIndexEx" };
}
thread_local std::vector<wchar_t> name;
name.resize(nameLen);
thread_local std::vector<BYTE> data;
data.resize(dataLen);
WMT_ATTR_DATATYPE attType{};
WORD langIndex{ 0 };
result = headerinfo->GetAttributeByIndexEx(streamNumber, i, name.data(), &nameLen, &attType, &langIndex, data.data(), &dataLen);
if (result != S_OK)
{
throw std::runtime_error{ "error in IWMHeaderInfo3::GetAttributeByIndexEx" };
}
MetadataName metaName{langIndex, std::wstring(name.begin(), name.end())};
const auto attribute{
[&]
{
switch (attType)
{
case WMT_TYPE_WORD:
return Attribute{ static_cast<WORD>(*data.data()) };
case WMT_TYPE_DWORD:
return Attribute{ static_cast<DWORD>(*data.data()) };
case WMT_TYPE_QWORD:
return Attribute{ static_cast<QWORD>(*data.data()) };
case WMT_TYPE_STRING:
return Attribute{ std::wstring(reinterpret_cast<wchar_t*>(data.data()), dataLen)};
case WMT_TYPE_BINARY:
return Attribute{ data };
case WMT_TYPE_BOOL:
return Attribute{ static_cast<BOOL>(*data.data()) };
case WMT_TYPE_GUID:
return Attribute{ static_cast<DWORD>(*data.data()) };
}
throw std::runtime_error{ "unknown attribute type" };
}()
};
fileMetadata.emplace_back(metaName, attribute);
}
return fileMetadata;
}
Metadata getFileAttributes(path fileName)
{
WIN32_FILE_ATTRIBUTE_DATA buffer{};
if (!GetFileAttributesExW(fileName.wstring().c_str(), GetFileExInfoStandard, &buffer))
{
throw std::runtime_error{ "error in GetFileAttributesExW" };
}
return {};
}
int main(int argc, char* args[])
{
if (argc < 2)
{
writeHelp();
return 0;
}
path path{ args[1] };
if (!std::filesystem::exists(path))
{
writeHelp(L"the file path given doesnt exist");
}
const auto metadata{ getFileMetadata(path)};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment