Files
2026-03-03 08:13:16 +03:00

146 lines
3.6 KiB
C++

#ifndef ECLIPT_SUBTITLE_H
#define ECLIPT_SUBTITLE_H
#include "Frame.h"
#include <string>
#include <vector>
#include <memory>
#include <cstdint>
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<std::string> 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<SubtitleCue> 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<SubtitleCue> cues_;
std::vector<uint8_t> data_;
bool parseSRT();
bool parseVTT();
bool parseASS();
int64_t parseTimestamp(const std::string& str);
std::vector<std::string> 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<Impl> pImpl;
};
}
#endif