init
This commit is contained in:
61
libEcliptPlayer/include/eclipt/Config.h
Normal file
61
libEcliptPlayer/include/eclipt/Config.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef ECLIPT_CONFIG_H
|
||||
#define ECLIPT_CONFIG_H
|
||||
|
||||
#include "Frame.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
||||
namespace eclipt {
|
||||
|
||||
struct DecoderConfig {
|
||||
bool use_hw_acceleration = true;
|
||||
std::string hw_device = "auto";
|
||||
int thread_count = 0;
|
||||
bool enable_frame_skiping = false;
|
||||
int max_ref_frames = 2;
|
||||
bool low_latency = false;
|
||||
};
|
||||
|
||||
struct OutputConfig {
|
||||
PixelFormat preferred_format = PixelFormat::YUV420;
|
||||
bool enable_frame_interpolation = false;
|
||||
int target_fps = 0;
|
||||
int frame_pool_size = 8;
|
||||
bool vsync = true;
|
||||
};
|
||||
|
||||
struct StreamConfig {
|
||||
int video_stream_index = -1;
|
||||
int audio_stream_index = -1;
|
||||
int subtitle_stream_index = -1;
|
||||
std::string preferred_language = "eng";
|
||||
bool strict_stream_selection = false;
|
||||
};
|
||||
|
||||
struct PlayerConfig {
|
||||
DecoderConfig decoder;
|
||||
OutputConfig output;
|
||||
StreamConfig stream;
|
||||
int buffer_size_ms = 1000;
|
||||
bool prebuffer = true;
|
||||
};
|
||||
|
||||
enum class LogLevel {
|
||||
Debug,
|
||||
Info,
|
||||
Warning,
|
||||
Error
|
||||
};
|
||||
|
||||
enum class SeekDirection {
|
||||
Forward,
|
||||
Backward,
|
||||
Absolute
|
||||
};
|
||||
|
||||
using LogCallback = std::function<void(LogLevel, const char*)>;
|
||||
|
||||
}
|
||||
#endif
|
||||
156
libEcliptPlayer/include/eclipt/Decoder.h
Normal file
156
libEcliptPlayer/include/eclipt/Decoder.h
Normal file
@@ -0,0 +1,156 @@
|
||||
#ifndef ECLIPT_DECODER_H
|
||||
#define ECLIPT_DECODER_H
|
||||
|
||||
#include "Frame.h"
|
||||
#include "Demuxer.h"
|
||||
#include "Config.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <atomic>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/hwcontext.h>
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace eclipt {
|
||||
|
||||
enum class DecoderType {
|
||||
Software,
|
||||
Hardware,
|
||||
Auto
|
||||
};
|
||||
|
||||
enum class HardwareAPI {
|
||||
None,
|
||||
VAAPI,
|
||||
VDPAU,
|
||||
CUDA,
|
||||
D3D11VA,
|
||||
VideoToolbox,
|
||||
MediaCodec,
|
||||
MMAL,
|
||||
OMX
|
||||
};
|
||||
|
||||
struct DecoderCapabilities {
|
||||
bool supports_hw_decode = false;
|
||||
bool supports_hw_encode = false;
|
||||
std::vector<HardwareAPI> supported_apis;
|
||||
std::vector<std::string> supported_codecs;
|
||||
int max_resolution_width = 0;
|
||||
int max_resolution_height = 0;
|
||||
bool supports_10bit = false;
|
||||
bool supports_hdr = false;
|
||||
};
|
||||
|
||||
struct DecodeStats {
|
||||
int decoded_frames = 0;
|
||||
int dropped_frames = 0;
|
||||
int corrupted_frames = 0;
|
||||
int64_t decode_time_us = 0;
|
||||
double fps = 0.0;
|
||||
bool is_hardware = false;
|
||||
HardwareAPI hw_api = HardwareAPI::None;
|
||||
};
|
||||
|
||||
class IDecoder {
|
||||
public:
|
||||
virtual ~IDecoder() = default;
|
||||
|
||||
virtual bool open(const StreamMetadata& stream, const DecoderConfig& config) = 0;
|
||||
virtual void close() = 0;
|
||||
virtual bool isOpen() const = 0;
|
||||
|
||||
virtual bool sendPacket(const Packet& packet) = 0;
|
||||
virtual bool receiveFrame(VideoFrame& frame) = 0;
|
||||
virtual bool flush() = 0;
|
||||
|
||||
virtual DecoderType getDecoderType() const = 0;
|
||||
virtual HardwareAPI getHardwareAPI() const = 0;
|
||||
virtual const DecodeStats& getStats() const = 0;
|
||||
|
||||
virtual void setHardwareAPI(HardwareAPI api) = 0;
|
||||
virtual bool supportsFormat(const std::string& codec) const = 0;
|
||||
|
||||
virtual std::string getLastError() const = 0;
|
||||
};
|
||||
|
||||
class FFmpegDecoder : public IDecoder {
|
||||
public:
|
||||
FFmpegDecoder();
|
||||
~FFmpegDecoder() override;
|
||||
|
||||
bool open(const StreamMetadata& stream, const DecoderConfig& config) override;
|
||||
void close() override;
|
||||
bool isOpen() const override;
|
||||
|
||||
bool sendPacket(const Packet& packet) override;
|
||||
bool receiveFrame(VideoFrame& frame) override;
|
||||
bool flush() override;
|
||||
|
||||
DecoderType getDecoderType() const override;
|
||||
HardwareAPI getHardwareAPI() const override;
|
||||
const DecodeStats& getStats() const override;
|
||||
|
||||
void setHardwareAPI(HardwareAPI api) override;
|
||||
bool supportsFormat(const std::string& codec) const override;
|
||||
|
||||
std::string getLastError() const override;
|
||||
|
||||
static DecoderCapabilities getCapabilities();
|
||||
static std::vector<HardwareAPI> getAvailableHardwareAPIs();
|
||||
static HardwareAPI probeBestHardwareAPI(const std::string& codec);
|
||||
|
||||
void* getHardwareDeviceContext() const;
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> pImpl;
|
||||
};
|
||||
|
||||
class FramePool : public IFramePool {
|
||||
public:
|
||||
FramePool(size_t max_size, PixelFormat format, uint32_t width, uint32_t height);
|
||||
~FramePool() override;
|
||||
|
||||
VideoFrame acquire() override;
|
||||
void release(VideoFrame&& frame) override;
|
||||
void clear() override;
|
||||
size_t available() const override;
|
||||
|
||||
void setFormat(PixelFormat format);
|
||||
void setDimensions(uint32_t width, uint32_t height);
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> pImpl;
|
||||
};
|
||||
|
||||
class DecoderPool {
|
||||
public:
|
||||
DecoderPool();
|
||||
~DecoderPool();
|
||||
|
||||
void setMaxDecoders(size_t count);
|
||||
size_t getMaxDecoders() const;
|
||||
|
||||
std::shared_ptr<FFmpegDecoder> acquire(const StreamMetadata& stream, const DecoderConfig& config);
|
||||
void release(std::shared_ptr<FFmpegDecoder> decoder);
|
||||
|
||||
void clear();
|
||||
size_t activeCount() const;
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> pImpl;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
149
libEcliptPlayer/include/eclipt/Demuxer.h
Normal file
149
libEcliptPlayer/include/eclipt/Demuxer.h
Normal file
@@ -0,0 +1,149 @@
|
||||
#ifndef ECLIPT_DEMUXER_H
|
||||
#define ECLIPT_DEMUXER_H
|
||||
|
||||
#include "Frame.h"
|
||||
#include "Config.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace eclipt {
|
||||
|
||||
enum class MediaType {
|
||||
Video,
|
||||
Audio,
|
||||
Subtitle,
|
||||
Data,
|
||||
Attachment
|
||||
};
|
||||
|
||||
struct StreamMetadata {
|
||||
int stream_index = -1;
|
||||
MediaType media_type = MediaType::Video;
|
||||
std::string codec_name;
|
||||
std::string codec_long_name;
|
||||
std::string language;
|
||||
std::string title;
|
||||
int profile = 0;
|
||||
int level = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int64_t bitrate = 0;
|
||||
int sample_rate = 0;
|
||||
int channels = 0;
|
||||
std::string channel_layout;
|
||||
int fps_num = 0;
|
||||
int fps_den = 1;
|
||||
int64_t duration = 0;
|
||||
bool is_default = false;
|
||||
bool is_forced = false;
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
std::vector<uint8_t> data;
|
||||
int stream_index = -1;
|
||||
int64_t pts = AV_NOPTS_VALUE;
|
||||
int64_t dts = AV_NOPTS_VALUE;
|
||||
int64_t duration = 0;
|
||||
int flags = 0;
|
||||
MediaType media_type = MediaType::Video;
|
||||
|
||||
Packet() = default;
|
||||
|
||||
bool isKeyframe() const { return flags & AV_PKT_FLAG_KEY; }
|
||||
bool isCorrupt() const { return flags & AV_PKT_FLAG_CORRUPT; }
|
||||
|
||||
void clear() {
|
||||
data.clear();
|
||||
stream_index = -1;
|
||||
pts = AV_NOPTS_VALUE;
|
||||
dts = AV_NOPTS_VALUE;
|
||||
duration = 0;
|
||||
flags = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class IDemuxer {
|
||||
public:
|
||||
virtual ~IDemuxer() = default;
|
||||
|
||||
virtual bool open(const std::string& url, const std::string& mime_type = "") = 0;
|
||||
virtual void close() = 0;
|
||||
virtual bool isOpen() const = 0;
|
||||
|
||||
virtual bool seek(int64_t timestamp_ms, eclipt::SeekDirection dir = eclipt::SeekDirection::Absolute) = 0;
|
||||
virtual bool seekToKeyframe(int64_t timestamp_ms) = 0;
|
||||
|
||||
virtual bool readPacket(Packet& packet) = 0;
|
||||
virtual int getPacketCount() const = 0;
|
||||
|
||||
virtual std::vector<StreamMetadata> getStreams() const = 0;
|
||||
virtual const StreamMetadata* getStream(int index) const = 0;
|
||||
virtual const StreamMetadata* getBestVideoStream() const = 0;
|
||||
virtual const StreamMetadata* getBestAudioStream() const = 0;
|
||||
virtual const StreamMetadata* getBestSubtitleStream() const = 0;
|
||||
|
||||
virtual int64_t getDuration() const = 0;
|
||||
virtual int64_t getStartTime() const = 0;
|
||||
virtual int64_t getBitrate() const = 0;
|
||||
|
||||
virtual std::string getUrl() const = 0;
|
||||
virtual std::string getFormatName() const = 0;
|
||||
|
||||
virtual void setPreferredStream(int media_type, int stream_index) = 0;
|
||||
|
||||
using ReadCallback = std::function<size_t(uint8_t*, size_t)>;
|
||||
virtual void setReadCallback(ReadCallback callback) = 0;
|
||||
};
|
||||
|
||||
class FFmpegDemuxer : public IDemuxer {
|
||||
public:
|
||||
FFmpegDemuxer();
|
||||
~FFmpegDemuxer() override;
|
||||
|
||||
bool open(const std::string& url, const std::string& mime_type = "") override;
|
||||
void close() override;
|
||||
bool isOpen() const override;
|
||||
|
||||
bool seek(int64_t timestamp_ms, eclipt::SeekDirection dir = eclipt::SeekDirection::Absolute) override;
|
||||
bool seekToKeyframe(int64_t timestamp_ms) override;
|
||||
|
||||
bool readPacket(Packet& packet) override;
|
||||
int getPacketCount() const override;
|
||||
|
||||
std::vector<StreamMetadata> getStreams() const override;
|
||||
const StreamMetadata* getStream(int index) const override;
|
||||
const StreamMetadata* getBestVideoStream() const override;
|
||||
const StreamMetadata* getBestAudioStream() const override;
|
||||
const StreamMetadata* getBestSubtitleStream() const override;
|
||||
|
||||
int64_t getDuration() const override;
|
||||
int64_t getStartTime() const override;
|
||||
int64_t getBitrate() const override;
|
||||
|
||||
std::string getUrl() const override;
|
||||
std::string getFormatName() const override;
|
||||
|
||||
void setPreferredStream(int media_type, int stream_index) override;
|
||||
void setReadCallback(ReadCallback callback) override;
|
||||
|
||||
void* getAVFormatContext() const;
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> pImpl;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
104
libEcliptPlayer/include/eclipt/EPG.h
Normal file
104
libEcliptPlayer/include/eclipt/EPG.h
Normal file
@@ -0,0 +1,104 @@
|
||||
#ifndef ECLIPT_EPG_H
|
||||
#define ECLIPT_EPG_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
|
||||
namespace eclipt {
|
||||
|
||||
struct EPGEvent {
|
||||
int64_t id = 0;
|
||||
std::string title;
|
||||
std::string description;
|
||||
int64_t start_time = 0;
|
||||
int64_t end_time = 0;
|
||||
int64_t duration = 0;
|
||||
std::string channel_id;
|
||||
std::string category;
|
||||
std::string icon_url;
|
||||
bool is_current = false;
|
||||
bool is_future = false;
|
||||
bool is_past = false;
|
||||
};
|
||||
|
||||
struct EPGChannel {
|
||||
std::string id;
|
||||
std::string name;
|
||||
std::string icon_url;
|
||||
std::string group;
|
||||
std::vector<EPGEvent> events;
|
||||
|
||||
const EPGEvent* getCurrentEvent() const;
|
||||
std::vector<const EPGEvent*> getEventsInRange(int64_t start, int64_t end) const;
|
||||
};
|
||||
|
||||
struct EPGData {
|
||||
std::string source;
|
||||
int64_t fetched_time = 0;
|
||||
int64_t valid_from = 0;
|
||||
int64_t valid_to = 0;
|
||||
std::map<std::string, EPGChannel> channels;
|
||||
|
||||
bool loadFromFile(const std::string& path);
|
||||
bool loadFromXml(const std::string& xml_content);
|
||||
bool loadFromUrl(const std::string& url);
|
||||
|
||||
bool merge(const EPGData& other);
|
||||
|
||||
const EPGChannel* findChannel(const std::string& id) const;
|
||||
std::vector<const EPGChannel*> findChannels(const std::string& group) const;
|
||||
};
|
||||
|
||||
class EPGParser {
|
||||
public:
|
||||
virtual ~EPGParser() = default;
|
||||
virtual bool parse(const std::string& content, EPGData& epg) = 0;
|
||||
virtual std::string getLastError() const = 0;
|
||||
};
|
||||
|
||||
class XmltvParser : public EPGParser {
|
||||
public:
|
||||
bool parse(const std::string& content, EPGData& epg) override;
|
||||
std::string getLastError() const override { return last_error_; }
|
||||
|
||||
private:
|
||||
std::string last_error_;
|
||||
bool parseChannel(const std::string& xml, EPGChannel& channel);
|
||||
bool parseProgramme(const std::string& xml, EPGEvent& event);
|
||||
int64_t parseXmltvTime(const std::string& str);
|
||||
};
|
||||
|
||||
class EPGFetcher {
|
||||
public:
|
||||
EPGFetcher();
|
||||
~EPGFetcher();
|
||||
|
||||
void setBaseUrl(const std::string& url);
|
||||
void setAuth(const std::string& username, const std::string& password);
|
||||
|
||||
bool fetch(EPGData& epg, const std::string& channel_id = "");
|
||||
bool fetchAll(EPGData& epg);
|
||||
|
||||
void cancel();
|
||||
bool isCancelled() const { return cancelled_; }
|
||||
|
||||
using ProgressCallback = std::function<void(int percent, const char* status)>;
|
||||
void setProgressCallback(ProgressCallback callback);
|
||||
|
||||
private:
|
||||
std::string base_url_;
|
||||
std::string username_;
|
||||
std::string password_;
|
||||
bool cancelled_ = false;
|
||||
ProgressCallback progress_callback_;
|
||||
|
||||
std::string buildUrl(const std::string& channel_id);
|
||||
bool authenticate();
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
102
libEcliptPlayer/include/eclipt/EcliptPlayer.h
Normal file
102
libEcliptPlayer/include/eclipt/EcliptPlayer.h
Normal file
@@ -0,0 +1,102 @@
|
||||
#ifndef ECLIPT_PLAYER_H
|
||||
#define ECLIPT_PLAYER_H
|
||||
|
||||
#include "Config.h"
|
||||
#include "Frame.h"
|
||||
#include "Playlist.h"
|
||||
#include "EPG.h"
|
||||
#include "Decoder.h"
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace eclipt {
|
||||
|
||||
enum class PlayerState {
|
||||
Stopped,
|
||||
Opening,
|
||||
Buffering,
|
||||
Playing,
|
||||
Paused,
|
||||
Error
|
||||
};
|
||||
|
||||
struct PlayerStats {
|
||||
int64_t current_pts = 0;
|
||||
int64_t buffer_duration_ms = 0;
|
||||
int dropped_frames = 0;
|
||||
int decoded_frames = 0;
|
||||
double fps = 0.0;
|
||||
int network_bitrate = 0;
|
||||
bool is_hardware_decoding = false;
|
||||
};
|
||||
|
||||
class IPlatformHooks {
|
||||
public:
|
||||
virtual ~IPlatformHooks() = default;
|
||||
virtual void* createHardwareContext() = 0;
|
||||
virtual void destroyHardwareContext(void* ctx) = 0;
|
||||
virtual bool uploadToTexture(const VideoFrame& frame, void* texture) = 0;
|
||||
virtual bool supportsHardwareDecode(const char* codec) const = 0;
|
||||
virtual std::string getPreferredDecoder() const = 0;
|
||||
};
|
||||
|
||||
class EcliptPlayer {
|
||||
public:
|
||||
EcliptPlayer();
|
||||
~EcliptPlayer();
|
||||
|
||||
void setConfig(const PlayerConfig& config);
|
||||
PlayerConfig getConfig() const;
|
||||
|
||||
void setPlatformHooks(std::unique_ptr<IPlatformHooks> hooks);
|
||||
|
||||
void setLogCallback(LogCallback callback);
|
||||
void setVideoCallback(FrameCallback callback);
|
||||
void setAudioCallback(AudioCallback callback);
|
||||
|
||||
bool open(const std::string& url);
|
||||
bool open(const std::string& url, const std::string& mime_type);
|
||||
void close();
|
||||
|
||||
bool play();
|
||||
bool pause();
|
||||
bool stop();
|
||||
|
||||
bool seek(int64_t timestamp_ms, SeekDirection dir = SeekDirection::Absolute);
|
||||
bool seekToProgram(unsigned int program_id);
|
||||
bool seekToChannel(int channel_number);
|
||||
|
||||
PlayerState getState() const;
|
||||
PlayerStats getStats() const;
|
||||
|
||||
float getVolume() const;
|
||||
void setVolume(float volume);
|
||||
|
||||
bool setAudioTrack(int track_index);
|
||||
bool setSubtitleTrack(int track_index);
|
||||
|
||||
std::vector<StreamInfo> getAudioTracks() const;
|
||||
std::vector<StreamInfo> getSubtitleTracks() const;
|
||||
|
||||
bool isPlaying() const { return getState() == PlayerState::Playing; }
|
||||
int64_t getDuration() const;
|
||||
int64_t getCurrentPosition() const;
|
||||
|
||||
VideoFrame interpolate(const VideoFrame& a, const VideoFrame& b);
|
||||
VideoFrame getDecodedFrame();
|
||||
|
||||
void setInterpolationEnabled(bool enabled);
|
||||
bool isInterpolationEnabled() const;
|
||||
|
||||
static const char* getVersion();
|
||||
static void setGlobalLogLevel(LogLevel level);
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> pImpl;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
90
libEcliptPlayer/include/eclipt/Frame.h
Normal file
90
libEcliptPlayer/include/eclipt/Frame.h
Normal file
@@ -0,0 +1,90 @@
|
||||
#ifndef ECLIPT_FRAME_H
|
||||
#define ECLIPT_FRAME_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
namespace eclipt {
|
||||
|
||||
enum class PixelFormat {
|
||||
YUV420,
|
||||
RGB24,
|
||||
NV12,
|
||||
BGRA32
|
||||
};
|
||||
|
||||
enum class FrameType {
|
||||
Video,
|
||||
Audio,
|
||||
Subtitle
|
||||
};
|
||||
|
||||
struct FrameBuffer {
|
||||
uint8_t* data = nullptr;
|
||||
size_t size = 0;
|
||||
size_t stride = 0;
|
||||
|
||||
FrameBuffer() = default;
|
||||
FrameBuffer(uint8_t* d, size_t s, size_t st = 0) : data(d), size(s), stride(st) {}
|
||||
};
|
||||
|
||||
struct VideoFrame {
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
PixelFormat format = PixelFormat::YUV420;
|
||||
int64_t pts = 0;
|
||||
int64_t dts = 0;
|
||||
int64_t duration = 0;
|
||||
|
||||
FrameBuffer planes[3];
|
||||
bool is_interpolated = false;
|
||||
float interpolation_factor = 0.0f;
|
||||
|
||||
VideoFrame() = default;
|
||||
|
||||
bool isValid() const { return width > 0 && height > 0 && planes[0].data != nullptr; }
|
||||
|
||||
size_t totalSize() const {
|
||||
switch (format) {
|
||||
case PixelFormat::YUV420:
|
||||
return width * height * 3 / 2;
|
||||
case PixelFormat::RGB24:
|
||||
return width * height * 3;
|
||||
case PixelFormat::NV12:
|
||||
return width * height * 3 / 2;
|
||||
case PixelFormat::BGRA32:
|
||||
return width * height * 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct AudioFrame {
|
||||
int sample_rate = 0;
|
||||
int channels = 0;
|
||||
int format = 0;
|
||||
int64_t pts = 0;
|
||||
int64_t duration = 0;
|
||||
FrameBuffer buffer;
|
||||
|
||||
size_t totalSize() const { return buffer.size; }
|
||||
};
|
||||
|
||||
class IFramePool {
|
||||
public:
|
||||
virtual ~IFramePool() = default;
|
||||
virtual VideoFrame acquire() = 0;
|
||||
virtual void release(VideoFrame&& frame) = 0;
|
||||
virtual void clear() = 0;
|
||||
virtual size_t available() const = 0;
|
||||
};
|
||||
|
||||
using FrameCallback = std::function<void(VideoFrame&&)>;
|
||||
using AudioCallback = std::function<void(AudioFrame&&)>;
|
||||
|
||||
}
|
||||
#endif
|
||||
78
libEcliptPlayer/include/eclipt/Playlist.h
Normal file
78
libEcliptPlayer/include/eclipt/Playlist.h
Normal file
@@ -0,0 +1,78 @@
|
||||
#ifndef ECLIPT_PLAYLIST_H
|
||||
#define ECLIPT_PLAYLIST_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
namespace eclipt {
|
||||
|
||||
enum class PlaylistType {
|
||||
M3U,
|
||||
M3U8,
|
||||
PLS,
|
||||
EXT
|
||||
};
|
||||
|
||||
struct StreamInfo {
|
||||
int index = -1;
|
||||
std::string name;
|
||||
std::string language;
|
||||
std::string codec;
|
||||
int bandwidth = 0;
|
||||
std::string url;
|
||||
std::string group;
|
||||
bool is_default = false;
|
||||
bool is_selected = false;
|
||||
};
|
||||
|
||||
struct PlaylistItem {
|
||||
std::string name;
|
||||
std::string url;
|
||||
std::string tvg_name;
|
||||
std::string tvg_id;
|
||||
std::string group;
|
||||
int tvg_logo = 0;
|
||||
int64_t duration = -1;
|
||||
bool is_live = false;
|
||||
std::vector<StreamInfo> streams;
|
||||
};
|
||||
|
||||
struct Playlist {
|
||||
std::string name;
|
||||
PlaylistType type = PlaylistType::M3U;
|
||||
std::vector<PlaylistItem> items;
|
||||
std::string base_url;
|
||||
|
||||
Playlist() = default;
|
||||
bool loadFromFile(const std::string& path);
|
||||
bool loadFromString(const std::string& content);
|
||||
bool loadFromUrl(const std::string& url);
|
||||
|
||||
std::vector<PlaylistItem> getLiveStreams() const;
|
||||
std::vector<PlaylistItem> getByGroup(const std::string& group) const;
|
||||
PlaylistItem* findById(const std::string& id);
|
||||
};
|
||||
|
||||
class IPlaylistParser {
|
||||
public:
|
||||
virtual ~IPlaylistParser() = default;
|
||||
virtual bool parse(const std::string& content, Playlist& playlist) = 0;
|
||||
virtual std::string getLastError() const = 0;
|
||||
};
|
||||
|
||||
class M3UParser : public IPlaylistParser {
|
||||
public:
|
||||
bool parse(const std::string& content, Playlist& playlist) override;
|
||||
std::string getLastError() const override { return last_error_; }
|
||||
|
||||
private:
|
||||
std::string last_error_;
|
||||
bool parseExtInf(const std::string& line, PlaylistItem& item);
|
||||
bool parseAttribute(const std::string& attr, std::string& key, std::string& value);
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
145
libEcliptPlayer/include/eclipt/Subtitle.h
Normal file
145
libEcliptPlayer/include/eclipt/Subtitle.h
Normal file
@@ -0,0 +1,145 @@
|
||||
#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
|
||||
Reference in New Issue
Block a user