#ifndef ECLIPT_SUBTITLE_H #define ECLIPT_SUBTITLE_H #include "Frame.h" #include #include #include #include namespace eclipt { enum class SubtitleType { SRT, VTT, ASS, SSA, DVBSub, DVB_Teletext, EIA_608 }; struct SubtitleCue { int64_t start_time = 0; int64_t end_time = 0; std::string text; std::vector lines; int style_index = -1; bool isValid() const { return !text.empty() && end_time > start_time; } bool isActive(int64_t pts) const { return pts >= start_time && pts < end_time; } }; struct SubtitleStyle { std::string font_name; int font_size = 24; uint32_t primary_color = 0xFFFFFFFF; uint32_t secondary_color = 0xFF000000; uint32_t outline_color = 0xFF000000; uint32_t back_color = 0x00000000; int bold = 0; int italic = 0; int underline = 0; int strikeout = 0; double margin_l = 0; double margin_r = 0; double margin_v = 0; int alignment = 2; double scale_x = 1.0; double scale_y = 1.0; }; struct RenderedSubtitle { VideoFrame frame; int64_t pts = 0; int64_t duration = 0; bool has_ass_events = false; RenderedSubtitle() = default; bool isValid() const { return frame.isValid(); } }; class ISubtitleRenderer { public: virtual ~ISubtitleRenderer() = default; virtual bool initialize(int width, int height) = 0; virtual void shutdown() = 0; virtual bool loadSubtitles(const std::string& path) = 0; virtual bool loadSubtitles(const uint8_t* data, size_t size, SubtitleType type) = 0; virtual void clearSubtitles() = 0; virtual void setStyle(const SubtitleStyle& style) = 0; virtual SubtitleStyle getStyle() const = 0; virtual RenderedSubtitle render(int64_t pts) = 0; virtual const SubtitleCue* getCurrentCue(int64_t pts) const = 0; virtual bool hasSubtitles() const = 0; virtual size_t getCueCount() const = 0; }; class SubtitleDecoder { public: SubtitleDecoder(); ~SubtitleDecoder(); bool open(const std::string& url); bool open(const uint8_t* data, size_t size, SubtitleType type); void close(); bool isOpen() const { return is_open_; } SubtitleType getType() const { return current_type_; } std::vector getCues() const { return cues_; } const SubtitleCue* getCueAtTime(int64_t pts) const; bool parse(); private: bool is_open_ = false; SubtitleType current_type_ = SubtitleType::SRT; std::vector cues_; std::vector data_; bool parseSRT(); bool parseVTT(); bool parseASS(); int64_t parseTimestamp(const std::string& str); std::vector splitLines(const std::string& text); }; class SubtitleRenderer : public ISubtitleRenderer { public: SubtitleRenderer(); ~SubtitleRenderer() override; bool initialize(int width, int height) override; void shutdown() override; bool loadSubtitles(const std::string& path) override; bool loadSubtitles(const uint8_t* data, size_t size, SubtitleType type) override; void clearSubtitles() override; void setStyle(const SubtitleStyle& style) override; SubtitleStyle getStyle() const override; RenderedSubtitle render(int64_t pts) override; const SubtitleCue* getCurrentCue(int64_t pts) const override; bool hasSubtitles() const override; size_t getCueCount() const override; void setVideoParams(int width, int height, int fps_num, int fps_den); private: struct Impl; std::unique_ptr pImpl; }; } #endif