Skip to content

win-mf: Reintroduce win-mf plugin for Media Foundation-based encoding on WoA #11993

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

thirumalai-qcom
Copy link
Contributor

Description

This PR re-introduces the win-mf plugin to OBS Studio, enabling Media Foundation-based encoding for H264, HEVC, and AAC. This plugin was previously removed in PR #7372 but is now being restored to support hardware-accelerated encoding on Windows on ARM (WoA) devices, specifically those utilizing Qualcomm hardware encoders. The Key changes include:

  • win-mf: Add base files for MFT encoders support on WoA
  • win-mf: Add Media Foundation H264 encoder for WoA
  • win-mf: Add Media Foundation HEVC encoder for WoA
  • win-mf: Add Media Foundation ACC encoder for WoA
  • cmake: Add win-mf plugin to OBS build for WoA

Motivation and Context

The primary motivation for these changes is to enable hardware-accelerated encoding on Windows on ARM (WoA) devices by reintroducing the win-mf plugin in OBS Studio. With the growing adoption of WoA devices, ensuring OBS Studio can leverage hardware encoders on this platform improves performance and efficiency, reducing CPU load while maintaining high-quality encoding.

By integrating the win-mf plugin back into the build system, we enable native support for Media Foundation-based encoding on WoA, ensuring users on this platform can leverage hardware acceleration for streaming and recording. This change ensures better utilization of Qualcomm hardware encoders, providing a more efficient and optimized encoding experience.

How Has This Been Tested?

The changes have been tested by building OBS Studio on a Windows on ARM (WoA) device with Qualcomm hardware. The build completed successfully, and basic functionality tests confirmed that OBS Studio runs as expected with the reintroduced win-mf plugin. Media Foundation-based encoding for H264, HEVC, and AAC was verified to function correctly, ensuring proper hardware acceleration on WoA devices utilizing Qualcomm hardware.

Types of changes

  • New feature (non-breaking change which adds functionality)

Checklist:

  • My code has been run through clang-format.
  • I have read the contributing document.
  • My code is not on the master branch.
  • The code has been tested.
  • All commit messages are properly formatted and commits squashed where appropriate.
  • I have included updates to all appropriate documentation.

@WizardCM WizardCM added Seeking Testers Build artifacts on CI New Feature New feature or plugin labels Mar 24, 2025
@thirumalai-qcom thirumalai-qcom force-pushed the mft-support branch 2 times, most recently from 55aa652 to ea69f55 Compare March 25, 2025 11:32
@thirumalai-qcom thirumalai-qcom marked this pull request as ready for review March 25, 2025 11:55
Copy link
Member

@PatTheMav PatTheMav left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wary about just reintroducing the old code as-is, particularly as we have progressed to C++17 and expect modern C++ coding practices, including but not limited to:

  • Use of anonymous namespaces instead of static functions is deprecated in C++ (static functions are only used for class methods in modern C++).
  • Use of constexpr as it's preferable over macros in almost all situations as they enable the compiler to optimise code better and sometimes resolve entire code paths at compile time
  • Abuse of macros instead of functions marked as constexpr (see above) which makes the code harder to debug

Just merging this would mean re-importing the code smell as well and I just don't see someone else volunteering to "refactor" it after it's been merged again.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file should be adapted to current CMake guidelines instead of copied-over from the legacy variant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PatTheMav
I have Updated the CMakeLists.txt to meet with the current guidelines. Could you please review the changes and share any suggestions you might have?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file still requires some revisions, follow the general skeleton of:

cmake_minimum_required(VERSION 3.28...3.30)

find_package(<dependencies)        # If any 3rd party dependencies

add_library(<module> MODULE)
add_library(OBS::<module> ALIAS <module>)

target_sources(
  <module>
  PRIVATE
    <source and header files, sorted alphabetically>
  PUBLIC                           # If any public headers
    <public source and header files, sorted alphabetically>
)

target_link_libraries(
  <module>
  PRIVATE <dependencies>
  PUBLIC <dependencies>.           # If any public dependencies
)

set_target_properties_obs(<module> PROPERTIES FOLDER plugins PREFIX "")

@derrod
Copy link
Member

derrod commented Mar 25, 2025

I tested this on my Snapdragon X laptop and it does work as expected.

But Ideally this plugin should be either rewritten from the ground up, or replaced wholesale with just using the FFmpeg implemenation. At the very least, the AAC encoder could probably be removed. Of course since this is ancient it also doesn't support AV1 (which the X Elite chips do support).

Aside from what Pat mentioned, the naming also conflicts with #10471 right now.

@dd-han
Copy link

dd-han commented Apr 13, 2025

Will this work with my older Surface Pro X (SQ2)?

If it works I can help test it.

@thirumalai-qcom thirumalai-qcom force-pushed the mft-support branch 4 times, most recently from 13c8aac to 2aa95e6 Compare May 20, 2025 11:10
@thirumalai-qcom
Copy link
Contributor Author

Will this work with my older Surface Pro X (SQ2)?
If it works I can help test it.

@dd-han Thanks for offering to help.
I believe it should work with your Surface Pro X [SQ2] which is based on the Snapdragon 8cx, If you get a change to try it out, please let me know how it goes.

@SA-Root
Copy link

SA-Root commented May 31, 2025

Hi, I tried using version 31.1.0 beta 1 on my pc with 8cx Gen 3, and I got 2 problems with MF based encoding:

  1. When using h264_mf encoder, it seems to be using CPU to encode the video.
    image
    image

  2. When I tried to use hevc_mf encoder, OBS immediately crashed when I click the Start Recording button. The corresponding log files are attached below.
    image
    image

2025-05-31 21-12-18.txt
Crash 2025-05-31 21-14-41.txt

image

@RytoEX
Copy link
Member

RytoEX commented May 31, 2025

Hi, I tried using version 31.1.0 beta 1 on my pc with 8cx Gen 3, and I got 2 problems with MF based encoding:

  1. When using h264_mf encoder, it seems to be using CPU to encode the video.

You are using the Media Foundation encoder via FFmpeg. That is not what is in this PR, and this PR has not been merged, so it is not in OBS Studio 31.1.0 Beta 1. Please use our forums or Discord for assistance.

@driver1998
Copy link

@SA-Root When using h264_mf encoder, it seems to be using CPU to encode the video.

You need to pass additional flags to make hardware encoding work with the ffmpeg backend.
See https://driver1998.github.io/posts/ffmpeg-hardware-video-encoding-on-qualcomm-woa/ (Chinese only)

This commit re-introduces the base files required for Media Foundation
Transform (MFT) support in the win-mf plugin, specifically targeting
Windows on ARM (WoA) devices with Qualcomm hardware. It includes core
implementation files, language configuration files for localization,
and the initial CMakeLists.txt for integration.
This commit introduces H264 encoder support using the Media Foundation
Transform (MFT) interface, specifically targeting Windows on ARM (WoA)
devices with Qualcomm hardware. It adds mf-h264.cpp and
mf-h264-encoder.cpp/.hpp to implement the encoding logic.

Additionally, CMakeLists.txt is updated to include the new source and
header files for proper integration into the win-mf plugin.
This commit introduces HEVC encoder support using the Media Foundation
Transform (MFT) interface, specifically targeting Windows on ARM (WoA)
devices with Qualcomm hardware. It adds mf-hevc.cpp and
mf-hevc-encoder.cpp/.hpp to implement the encoding logic.

Additionally, CMakeLists.txt is updated to include the new source and
header files for proper integration into the win-mf plugin.
This commit introduces AAC encoder support using the Media Foundation
Transform (MFT) interface, specifically targeting Windows on ARM (WoA)
devices with Qualcomm hardware. It adds mf-aac.cpp and
mf-aac-encoder.cpp/.hpp to implement the encoding logic.

Additionally, CMakeLists.txt is updated to include the new source and
header files for proper integration into the win-mf plugin
This commit updates the CMakeLists.txt file in the plugins directory to
incorporate the win-mf plugin into the OBS build system. This change
ensures that Media Foundation-based encoding is available for Windows
on ARM (WoA) devices, utilizing Qualcomm hardware for efficient video
Encoding.
Copy link
Member

@PatTheMav PatTheMav left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a first round of reviews, will still have to look at the HEVC and H264 encoder implementations.

Except for the missing newline issues I haven't commented on every repeat issue, so things like functions marked inline in compilation units, opaque variable names, "magic" global variables, should be fixed throughout and not just were I first encountered them in review.


project(win-mf)

set(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not use separate _SOURCES and _HEADERS variables, call target_sources with them directly (see also the other CMake build scripts in the project).

@@ -0,0 +1,43 @@
cmake_minimum_required(VERSION 3.28...3.30)

project(win-mf)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not specify a separate project for a plugin.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file still requires some revisions, follow the general skeleton of:

cmake_minimum_required(VERSION 3.28...3.30)

find_package(<dependencies)        # If any 3rd party dependencies

add_library(<module> MODULE)
add_library(OBS::<module> ALIAS <module>)

target_sources(
  <module>
  PRIVATE
    <source and header files, sorted alphabetically>
  PUBLIC                           # If any public headers
    <public source and header files, sorted alphabetically>
)

target_link_libraries(
  <module>
  PRIVATE <dependencies>
  PUBLIC <dependencies>.           # If any public dependencies
)

set_target_properties_obs(<module> PROPERTIES FOLDER plugins PREFIX "")

*extraData_ = extraData;
*extraDataLength = sizeof(extraData);
return true;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing newline at the end of file.


#include <array>

inline void LogAAC(const obs_encoder_t *encoder, int level, const char *format, ...)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this function (and the next) are not supposed to have external linkage and are only used within this compilation unit, so they should instead both be wrapped in an anonymous namespace and could even be marked as constexpr:

namespace {
    constexpr void LogCOMError(const obs_encoder_t *encoder, const char *operation, HRESULT hr)
    {
	    _com_error err(hr);
        LogAAC(encoder, LOG_ERROR, "%s failed, %S (0x%08lx)", operation, err.ErrorMessage(), hr);
    }
}

The inline keyword in most cases should only be used to make it explicit that a function or variable is defined "in-line" with its signature in header files, to allow what would otherwise be a violation of ODR.

Using constexpr instead allows the compiler to resolve it at compile time (similar to how a macro would be expanded before compilation) if the associated conditions are fulfilled.

const char *id;
EncoderType type;

} guidNameMap[] = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to think that it would be better for readability and understanding to split the type definition and the initialisation of a new variable with that type into separate statements.


ComHeapPtr<WCHAR> guidW;
StringFromIID(guid, &guidW);
std::string guidString = MBSToString(guidW);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct me if I'm wrong, but C++ has no built-in conversions from wstring to string? IIRC they even deprecated such functions in more recent C++ versions.

bool isHardware;
EncoderType type;
};
}; // namespace MF
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing newline at the end of file.

pendingRequests--;

return true;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing newline at the end of file.

std::atomic<UINT32> outputRequests{0};
std::atomic<UINT32> pendingRequests{0};
};
} // namespace MF
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing newline at the end of file.

@derrod
Copy link
Member

derrod commented Jul 10, 2025

Couple more notes:

  • You should remove the AAC encoder, it was removed due to glitches and we don't really have a reason to reintroduce it
    • If you insist on keeping it, add the .codecs property so it is correctly recognised by the encoder selectors, currently it's not selectable due to missing codec information
  • MediaFoundation does support DirectX textures as encoder input since Windows 8.1 and that should be preferred over copying data to system RAM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
New Feature New feature or plugin Seeking Testers Build artifacts on CI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants