#ifndef FRAMEGRABBER_H #define FRAMEGRABBER_H #include #include #include #include #include #include #include // use glReadPixel or glGetTextImage // read pixels & pbo should be the fastest // https://stackoverflow.com/questions/38140527/glreadpixels-vs-glgetteximage #define USE_GLREADPIXEL #define DEFAULT_GRABBER_FPS 30 #define MIN_BUFFER_SIZE 33177600 // 33177600 bytes = 1 frames 4K, 9 frames 720p class FrameBuffer; /** * @brief The FrameGrabber class defines the base class for all recorders * used to save images or videos from a frame buffer. * * Every subclass shall at least implement init() and terminate() * * The FrameGrabbing manager calls addFrame() for all its grabbers. */ class FrameGrabber { friend class FrameGrabbing; uint64_t id_; public: FrameGrabber(); virtual ~FrameGrabber(); inline uint64_t id() const { return id_; } virtual void stop(); virtual std::string info() const; virtual uint64_t duration() const; virtual bool finished() const; virtual bool busy() const; protected: // only FrameGrabbing manager can add frame virtual void addFrame(GstBuffer *buffer, GstCaps *caps); // only addFrame method shall call those virtual std::string init(GstCaps *caps) = 0; virtual void terminate() = 0; // thread-safe testing termination std::atomic finished_; std::atomic initialized_; std::atomic active_; std::atomic endofstream_; std::atomic accept_buffer_; std::atomic buffering_full_; // gstreamer pipeline GstElement *pipeline_; GstAppSrc *src_; GstCaps *caps_; GstClock *timer_; GstClockTime timer_firstframe_; GstClockTime timestamp_; GstClockTime duration_; GstClockTime frame_duration_; guint64 frame_count_; guint64 buffering_size_; bool timestamp_on_clock_; // async threaded initializer std::future initializer_; static std::string initialize(FrameGrabber *rec, GstCaps *caps); // gstreamer callbacks static void callback_need_data (GstAppSrc *, guint, gpointer user_data); static void callback_enough_data (GstAppSrc *, gpointer user_data); static GstPadProbeReturn callback_event_probe(GstPad *, GstPadProbeInfo *info, gpointer user_data); }; /** * @brief The FrameGrabbing class manages all frame grabbers * * Session calls grabFrame after each render * */ class FrameGrabbing { friend class Mixer; // Private Constructor FrameGrabbing(); FrameGrabbing(FrameGrabbing const& copy) = delete; FrameGrabbing& operator=(FrameGrabbing const& copy) = delete; public: static FrameGrabbing& manager() { // The only instance static FrameGrabbing _instance; return _instance; } ~FrameGrabbing(); inline uint width() const { return width_; } inline uint height() const { return height_; } void add(FrameGrabber *rec); void chain(FrameGrabber *rec, FrameGrabber *new_rec); void verify(FrameGrabber **rec); bool busy() const; FrameGrabber *get(uint64_t id); void stopAll(); void clearAll(); protected: // only for friend Session void grabFrame(FrameBuffer *frame_buffer); private: std::list grabbers_; std::map grabbers_chain_; guint pbo_[2]; guint pbo_index_; guint pbo_next_index_; guint size_; guint width_; guint height_; bool use_alpha_; GstCaps *caps_; }; #endif // FRAMEGRABBER_H