Files
OrcaSlicer/docs/superpowers/specs/2026-08-14-ffmpeg-player-macos-design.md
T
2026-08-14 20:08:55 +08:00

5.8 KiB
Raw Blame History

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 into wxImage (non-Windows) / wxBitmap (Windows) drawn in a paintEvent, feeds via the Bambu_* C API (BambuTunnel.h, BAMBU_DYNAMIC) dlsym'd from the network plugin through StaticBambuLib::get() (GUI/Printer/PrinterFileSystem.cpp, compiled on all platforms).
  • Old player (macOS): GUI/wxMediaCtrl2.mm uses the ObjC BambuPlayer class found via dlsym(module, "OBJC_CLASS_$_BambuPlayer") in libBambuSource.dylib.
  • The macOS network plugin libBambuSource.dylib already exports the full Bambu C API (verified with nm), so the new player needs zero plugin changes.
  • FFmpeg linking in src/slic3r/CMakeLists.txt is guarded by if (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, so libavcodec.a / libswscale.a / libavutil.a are already present at deps/build/arm64/OrcaSlicer_dep/usr/local/lib/.
  • EVT_MEDIA_CTRL_STAT is wxDEFINE_EVENT'd in wxMediaCtrl2.cpp (Win/Linux) and wxMediaCtrl2.mm (macOS); the define in wxMediaCtrl3.cpp is commented out.
  • wxMediaCtrl2 is never instantiated anywhere on any platform — dead code.
  • StatusPanel already creates wxMediaCtrl3; MediaPlayCtrl only uses the wxMediaCtrl3 interface (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 wxImageDrawBitmap 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 1822) that aliases wxMediaCtrl3wxMediaCtrl2. macOS then compiles the real wxMediaCtrl3 class, including the BAMBU_DYNAMIC BambuTunnel path used on Linux.
  • Event symbol fix: move wxDEFINE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent) into wxMediaCtrl3.cpp (uncomment the existing line) and remove it from wxMediaCtrl2.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-static when APPLE. Linux keeps --enable-shared; Windows keeps its prebuilt shared DLL zips. Fresh macOS deps builds install only libavcodec.a / libswscale.a / libavutil.a — no dylibs to bundle, no rpath/install_name handling. (The existing local arm64 deps build already contains the .a files, 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: add GUI/wxMediaCtrl3.cpp, GUI/wxMediaCtrl3.h, GUI/AVVideoDecoder.cpp, GUI/AVVideoDecoder.hpp; remove GUI/wxMediaCtrl2.mm and GUI/wxMediaCtrl2.h (the .h stays on disk for the Win/Linux build of wxMediaCtrl2.cpp, but nothing on macOS includes it after this change).
    • Add an APPLE mirror of the NOT APPLE FFmpeg block: find_library for libavcodec.a, libswscale.a, libavutil.a under ${CMAKE_PREFIX_PATH}/lib with NO_DEFAULT_PATH, link them (order avcodec → swscale → avutil), and add ${CMAKE_PREFIX_PATH}/include as a SYSTEM include directory. Deps are built with --disable-zlib and no external codecs, so the three static libs link cleanly.

3. Remove the old player

  • Delete GUI/wxMediaCtrl2.mm and GUI/BambuPlayer/BambuPlayer.h (header used only by the .mm; the real BambuPlayer lives inside the network plugin).
  • Remove the now-dead __WXMAC__ section of GUI/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 (or build/arm64).
  • Confirm no dynamic FFmpeg dependency: otool -L on the app binary shows no libav* dylib references.
  • Runtime: with the network plugin loaded, the Device tab camera preview streams via the FFmpeg player (check the device page / MediaPlayCtrl).
  • macOS ctest still passes — static linking means no test-executable .so copying 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).