LoginSignup
1
0

UnrealEngineでWindowsのファイルのプロパティから動画の再生時間を取得する

Posted at

UnrealEngineでWindowsのファイルのプロパティから動画の再生時間を取得するのをやってみたのでメモしておきます。

試した環境

  • UE5.2.1
  • Windows11

参照サイト

試したコード

[プロジェクト名].build.cs
        if (Target.Platform == UnrealTargetPlatform.Win64)
        {
            PublicSystemLibraries.AddRange(new string[] { "Propsys.lib" });
        }
コード本体
#include "Windows/AllowWindowsPlatformTypes.h"
#include "Windows/AllowWindowsPlatformAtomics.h"
#include "Windows/PreWindowsApi.h"

#include <shobjidl.h>
#include <propsys.h>
#include <propvarutil.h>
#include <propkey.h>
#include <strsafe.h>

#include "Windows/PostWindowsApi.h"
#include "Windows/HideWindowsPlatformAtomics.h"
#include "Windows/HideWindowsPlatformTypes.h"

int UPlatformUtils::GetMediaDurationFromFile(FString Filename)
{
    int Duration = -1;

#if PLATFORM_WINDOWS
    // Convert the Canonical name of the property to PROPERTYKEY
    PROPERTYKEY key;
    HRESULT hr = PSGetPropertyKeyFromName(TEXT("System.Media.Duration"), &key);
    if (!SUCCEEDED(hr))
    {
        UE_LOG(LogTemp, Error, TEXT("Invalid property specified: System.Media.Duration"));
        return Duration;
    }

    IPropertyStore* pps = NULL;

    WCHAR szExpanded[MAX_PATH];
    hr = ExpandEnvironmentStrings(*Filename, szExpanded, ARRAYSIZE(szExpanded)) ? S_OK : HRESULT_FROM_WIN32(GetLastError());
    if (!SUCCEEDED(hr))
    {
        UE_LOG(LogTemp, Error, TEXT("Error %x: failed to ExpandEnvironmentStrings"), hr);
        return Duration;
    }

    WCHAR szAbsPath[MAX_PATH];
    hr = _wfullpath(szAbsPath, szExpanded, ARRAYSIZE(szAbsPath)) ? S_OK : E_FAIL;
    if (!SUCCEEDED(hr))
    {
        UE_LOG(LogTemp, Error, TEXT("Error %x: failed to _wfullpath"), hr);
        return Duration;
    }

    hr = SHGetPropertyStoreFromParsingName(szAbsPath, NULL, GPS_DEFAULT, IID_PPV_ARGS(&pps));
    if (!SUCCEEDED(hr))
    {
        UE_LOG(LogTemp, Error, TEXT("Error %x: getting the propertystore for the item."), hr);
        return Duration;
    }
    TSharedPtr<IPropertyStore> Pps(pps, [](IPropertyStore* ptr) {
        if (ptr) ptr->Release();
        });

    PROPVARIANT propvarValue = { 0 };
    hr = Pps->GetValue(key, &propvarValue);
    if (!SUCCEEDED(hr))
    {
        UE_LOG(LogTemp, Error, TEXT("Error %x: cannot get value"), hr);
        return Duration;
    }
    TSharedPtr<PROPVARIANT> PropvarValue(&propvarValue, [](PROPVARIANT* ptr) {
        if (ptr) PropVariantClear(ptr);
        });

    PWSTR pszDisplayValue = NULL;
    hr = PSFormatForDisplayAlloc(key, propvarValue, PDFF_DEFAULT, &pszDisplayValue);
    if (!SUCCEEDED(hr))
    {
        UE_LOG(LogTemp, Error, TEXT("Error %x: failed to PSFormatForDisplayAlloc."), hr);
        return Duration;
    }
    TSharedPtr<WCHAR> PszDisplayValue(pszDisplayValue, [](PWSTR ptr) {
        if (ptr) CoTaskMemFree(ptr);
        });

    FString DurationStr = PszDisplayValue.Get();

    const FRegexPattern Pattern = FRegexPattern(TEXT("^([0-9]*):([0-9]*):([0-9]*)$"));
    FRegexMatcher Matcher(Pattern, DurationStr);
    if (Matcher.FindNext())
    {
        Duration = FCString::Atoi(*Matcher.GetCaptureGroup(3));
        Duration += FCString::Atoi(*Matcher.GetCaptureGroup(2)) * 60;
        Duration += FCString::Atoi(*Matcher.GetCaptureGroup(1)) * 60 * 60;
    }
    else
    {
        UE_LOG(LogTemp, Error, TEXT("Error: duration format is invalid %s"), *DurationStr);
    }
#endif
    return Duration;
}
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0