// // Simple FFmpeg-inspired serial decoding toolkit. // #pragma once #include #include #include #include #include #include #include #include namespace ffmsep { // Error codes loosely mirroring FFmpeg semantics. inline constexpr int CP_SUCCESS = 0; inline constexpr int CP_ERROR_EOF = -1; inline constexpr int CP_ERROR_EAGAIN = -2; inline constexpr int CP_ERROR_NOT_OPEN = -3; inline constexpr int CP_ERROR_INVALID_STATE = -4; inline constexpr int CP_ERROR_INVALID_ARGUMENT = -5; enum class CPMediaType : std::uint8_t { Unknown = 0, Data, Audio, Video }; enum class CPCodecID : std::uint32_t { Unknown = 0, Tactile = 0x54514354u // 'T','Q','C','T' marker for tactile quick codec. }; struct CPPacket { std::vector payload; std::int64_t pts = 0; std::int64_t dts = 0; bool end_of_stream = false; bool flush = false; CPPacket() = default; CPPacket(std::vector data, std::int64_t pts_value = 0, std::int64_t dts_value = 0) noexcept : payload(std::move(data)), pts(pts_value), dts(dts_value) {} [[nodiscard]] bool empty() const noexcept { return payload.empty(); } }; struct CPFrame { std::vector data; std::int64_t pts = 0; bool key_frame = false; bool valid = false; void reset() noexcept { data.clear(); pts = 0; key_frame = false; valid = false; } }; struct CPCodecContext; struct CPCodec { using InitFn = int (*)(CPCodecContext*); using CloseFn = void (*)(CPCodecContext*); using SendPacketFn = int (*)(CPCodecContext*, const CPPacket&); using ReceiveFrameFn = int (*)(CPCodecContext*, CPFrame&); const char* name = nullptr; const char* long_name = nullptr; CPMediaType type = CPMediaType::Unknown; CPCodecID id = CPCodecID::Unknown; std::size_t priv_data_size = 0; InitFn init = nullptr; CloseFn close = nullptr; SendPacketFn send_packet = nullptr; ReceiveFrameFn receive_frame = nullptr; }; struct CPCodecContext { const CPCodec* codec = nullptr; void* priv_data = nullptr; CPMediaType codec_type = CPMediaType::Unknown; bool is_open = false; void clear() noexcept { codec = nullptr; priv_data = nullptr; codec_type = CPMediaType::Unknown; is_open = false; priv_storage.clear(); } void* ensure_priv_storage(std::size_t size); void release_priv_storage() noexcept; template [[nodiscard]] T* priv_as() noexcept { return static_cast(priv_data); } template [[nodiscard]] const T* priv_as() const noexcept { return static_cast(priv_data); } private: std::vector priv_storage; friend CPCodecContext* cpcodec_alloc_context3(const CPCodec*); friend int cpcodec_open2(CPCodecContext*, const CPCodec*); friend int cpcodec_close(CPCodecContext*); }; void cpcodec_register(const CPCodec* codec); void cpcodec_register_many(std::initializer_list codecs); const CPCodec* cpcodec_find_decoder(CPCodecID id); const CPCodec* cpcodec_find_decoder_by_name(std::string_view name); std::vector cpcodec_list_codecs(); CPCodecContext* cpcodec_alloc_context3(const CPCodec* codec); int cpcodec_open2(CPCodecContext* ctx, const CPCodec* codec = nullptr); int cpcodec_close(CPCodecContext* ctx); void cpcodec_free_context(CPCodecContext** ctx); int cpcodec_send_packet(CPCodecContext* ctx, const CPPacket* packet); int cpcodec_receive_frame(CPCodecContext* ctx, CPFrame* frame); } // namespace ffmsep