5.8 KiB
FFmpeg Media Player for macOS — Design
Date: 2026-08-14
Branch: dev/ffmpeg-player-macos
Problem
The branch's new FFmpeg-based media player (wxMediaCtrl3 + AVVideoDecoder) is used on
Windows and Linux, but macOS still runs the old player: wxMediaCtrl2.mm, an ObjC
BambuPlayer class dlsym'd from the Bambu network plugin that renders via CALayer.
On macOS, wxMediaCtrl3 is currently aliased to wxMediaCtrl2 and FFmpeg is not linked
into the app at all.
Goal: make macOS use the same FFmpeg player as Windows/Linux, linking the static FFmpeg libraries from the deps build instead of dynamic ones.
Current state (verified)
- New player (Win/Linux):
GUI/wxMediaCtrl3.cpp+GUI/AVVideoDecoder.cpp. Decodes with FFmpeg (libavcodec/libswscale/libavutil), renders frames intowxImage(non-Windows) /wxBitmap(Windows) drawn in apaintEvent, feeds via theBambu_*C API (BambuTunnel.h,BAMBU_DYNAMIC) dlsym'd from the network plugin throughStaticBambuLib::get()(GUI/Printer/PrinterFileSystem.cpp, compiled on all platforms). - Old player (macOS):
GUI/wxMediaCtrl2.mmuses the ObjCBambuPlayerclass found viadlsym(module, "OBJC_CLASS_$_BambuPlayer")inlibBambuSource.dylib. - The macOS network plugin
libBambuSource.dylibalready exports the full Bambu C API (verified withnm), so the new player needs zero plugin changes. - FFmpeg linking in
src/slic3r/CMakeLists.txtis guarded byif (NOT APPLE)— macOS currently does not link FFmpeg. deps/FFMPEG/FFMPEG.cmake: non-MSVC branch builds FFmpeg from source with--enable-shared. The existing arm64 deps build on the dev machine happened to be configured with both static and shared enabled, solibavcodec.a/libswscale.a/libavutil.aare already present atdeps/build/arm64/OrcaSlicer_dep/usr/local/lib/.EVT_MEDIA_CTRL_STATiswxDEFINE_EVENT'd inwxMediaCtrl2.cpp(Win/Linux) andwxMediaCtrl2.mm(macOS); the define inwxMediaCtrl3.cppis commented out.wxMediaCtrl2is never instantiated anywhere on any platform — dead code.StatusPanelalready createswxMediaCtrl3;MediaPlayCtrlonly uses thewxMediaCtrl3interface (Load/Play/Stop/GetState/GetVideoSize/GetLastError/SetIdleImage), so no UI-side changes are needed.
Approach (approved)
Reuse the shared player on macOS. Compile the existing wxMediaCtrl3.cpp +
AVVideoDecoder.cpp on macOS so all three platforms run one implementation.
Rendering uses the existing wxImage → DrawBitmap paint path, identical to Linux.
Known trade-off: frames are scaled to the widget's logical (1x) size, so Retina is
slightly soft compared to the old CALayer player. Accepted for now; a Retina-aware
scaling follow-up is possible later.
Rejected alternative: a native CGImage/CALayer renderer for macOS — faster and Retina-crisp, but adds a second render implementation to maintain.
Changes
1. Enable the FFmpeg player on macOS (source)
GUI/wxMediaCtrl3.h: remove the#ifdef __WXMAC__branch (lines 18–22) that aliaseswxMediaCtrl3→wxMediaCtrl2. macOS then compiles the realwxMediaCtrl3class, including theBAMBU_DYNAMICBambuTunnel path used on Linux.- Event symbol fix: move
wxDEFINE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent)intowxMediaCtrl3.cpp(uncomment the existing line) and remove it fromwxMediaCtrl2.cpp. One definition total in the lib; all three platforms resolve it.
2. Static FFmpeg linking (deps + app)
deps/FFMPEG/FFMPEG.cmake: in the non-MSVC branch, pass--disable-shared --enable-staticwhenAPPLE. Linux keeps--enable-shared; Windows keeps its prebuilt shared DLL zips. Fresh macOS deps builds install onlylibavcodec.a/libswscale.a/libavutil.a— no dylibs to bundle, no rpath/install_name handling. (The existing local arm64 deps build already contains the.afiles, so no deps rebuild is strictly needed to try the change locally, but a fresh CI deps build must produce them.)src/slic3r/CMakeLists.txt:- APPLE branch of
SLIC3R_GUI_SOURCES: addGUI/wxMediaCtrl3.cpp,GUI/wxMediaCtrl3.h,GUI/AVVideoDecoder.cpp,GUI/AVVideoDecoder.hpp; removeGUI/wxMediaCtrl2.mmandGUI/wxMediaCtrl2.h(the.hstays on disk for the Win/Linux build ofwxMediaCtrl2.cpp, but nothing on macOS includes it after this change). - Add an APPLE mirror of the
NOT APPLEFFmpeg block:find_libraryforlibavcodec.a,libswscale.a,libavutil.aunder${CMAKE_PREFIX_PATH}/libwithNO_DEFAULT_PATH, link them (order avcodec → swscale → avutil), and add${CMAKE_PREFIX_PATH}/includeas a SYSTEM include directory. Deps are built with--disable-zliband no external codecs, so the three static libs link cleanly.
- APPLE branch of
3. Remove the old player
- Delete
GUI/wxMediaCtrl2.mmandGUI/BambuPlayer/BambuPlayer.h(header used only by the.mm; the realBambuPlayerlives inside the network plugin). - Remove the now-dead
__WXMAC__section ofGUI/wxMediaCtrl2.h. wxMediaCtrl2.cpp(Win/Linux) stays in the build as-is (dead but harmless; out of scope to remove on this branch).
4. Verification
- Build on macOS:
cmake --build build_arm64(orbuild/arm64). - Confirm no dynamic FFmpeg dependency:
otool -Lon the app binary shows nolibav*dylib references. - Runtime: with the network plugin loaded, the Device tab camera preview streams via
the FFmpeg player (check the device page /
MediaPlayCtrl). - macOS
cteststill passes — static linking means no test-executable.socopying hacks (unlike the Linux shared-lib setup).
Out of scope
- Linux (shared libs, AppImage/flatpak bundling) and Windows (prebuilt DLL zips) keep their current FFmpeg setup.
- Retina-aware frame scaling / native CGImage rendering (follow-up if visual quality is judged insufficient).
- Audio streaming (neither player plays audio in this UI path).