/***************************************************************************************** * * * OpenSpace * * * * Copyright (c) 2014-2025 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * * without restriction, including without limitation the rights to use, copy, modify, * * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * * permit persons to whom the Software is furnished to do so, subject to the following * * conditions: * * * * The above copyright notice and this permission notice shall be included in all copies * * or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ #ifndef __OPENSPACE_MODULE_VIDEO___VIDEOPLAYER___H__ #define __OPENSPACE_MODULE_VIDEO___VIDEOPLAYER___H__ #include #include #include #include #include #include #include #include #include // libmpv #include #include namespace openspace { enum class PlaybackMode { MapToSimulationTime = 0, RealTimeLoop }; class VideoPlayer : public properties::PropertyOwner, public Syncable { public: BooleanType(PauseAfterSeek); explicit VideoPlayer(const ghoul::Dictionary& dictionary); ~VideoPlayer() override; void initialize(); // Video interaction void pause(); void play(); void goToStart(); void seekToTime(double time, PauseAfterSeek pauseAfter = PauseAfterSeek::Yes); void toggleMute(); const std::unique_ptr& frameTexture() const; bool isInitialized() const; void reload(); void destroy(); void update(); virtual void preSync(bool isMaster) override; virtual void encode(SyncBuffer* syncBuffer) override; virtual void decode(SyncBuffer* syncBuffer) override; virtual void postSync(bool isMaster) override; static documentation::Documentation Documentation(); private: // Libmpv keys enum class MpvKey : uint64_t { Duration = 1, // 0 is the default key in libmpv so avoid that Height, Width, Meta, Time, Fps, Pause, IsSeeking, Mute, Command, Seek, Loop }; // Framebuffer void createTexture(glm::ivec2 size); void resizeTexture(glm::ivec2 size); // Libmpv static void onMpvRenderUpdate(void*); // Has to be static because of C api void initializeMpv(); // Called first time in update void renderMpv(); // Called in update void renderFrame(); // Renders a frame; called in renderMpv void commandAsyncMpv(const char* cmd[], MpvKey key = MpvKey::Command); void handleMpvEvents(); // Libmpv properties void handleMpvProperties(mpv_event* event); void observePropertyMpv(MpvKey key); void setPropertyStringMpv(const char* name, const char* value); void setPropertyAsyncMpv(int value, MpvKey key); void setPropertyAsyncMpv(const char* value, MpvKey key); void setPropertyAsyncMpv(double value, MpvKey key); void getPropertyAsyncMpv(MpvKey key); // Map to simulation time functions double correctVideoPlaybackTime() const; bool isWithingStartEndTime() const; void updateFrameDuration(); // Properties for user interaction properties::TriggerProperty _play; properties::TriggerProperty _pause; properties::TriggerProperty _goToStart; properties::TriggerProperty _reload; properties::BoolProperty _playAudio; properties::BoolProperty _loopVideo; // Video properties. Try to read all these values from the video std::filesystem::path _videoFile; double _currentVideoTime = 0.0; double _fps = 24.0; // If when we read it it is 0, use 24 fps double _videoDuration = 0.0; glm::ivec2 _videoResolution = glm::ivec2(2048, 1024); // Used for the fbos bool _isPaused = false; PlaybackMode _playbackMode = PlaybackMode::RealTimeLoop; // Default is to loop // Maps for keeping track of libmpv commands and formats std::map keys; std::map formats; // Syncing with multiple nodes double _correctPlaybackTime = 0.0; // Video stretching: map to simulation time animation mode double _startJ200Time = 0.0; double _endJ200Time = 0.0; double _frameDuration = 0.0; // Libmpv mpv_handle* _mpvHandle = nullptr; mpv_render_context* _mpvRenderContext = nullptr; std::unique_ptr _frameTexture; GLuint _fbo = 0; // Our opengl framebuffer where mpv renders to int _wakeup = 0; // Signals when libmpv has a new frame ready bool _isInitialized = false; // If libmpv has been inititalized bool _isSeeking = false; // Prevent seeking while already seeking bool _isDestroying = false; double _seekThreshold = 1.0; // Threshold to ensure we seek to a different time }; } // namespace video::globebrowsing #endif // __OPENSPACE_MODULE_VIDEO___VIDEOPLAYER___H__