#include "cpdecoder.hh" #include "components/ffmsep/cpdecoder.hh" #include #include #include #include #include #include namespace ffmsep { namespace { std::vector& codec_registry() { static std::vector registry; return registry; } std::mutex& registry_mutex() { static std::mutex m; return m; } void attach_codec(CPCodecContext* ctx, const CPCodec* codec) { if (!ctx) { return; } ctx->codec = codec; if (!codec) { ctx->codec_type = CPMediaType::Data; ctx->priv_data = nullptr; ctx->release_priv_storage(); return; } ctx->codec_type = codec->type; ctx->priv_data = ctx->ensure_priv_storage(codec->priv_data_size); } bool codec_name_equals(const CPCodec* codec, std::string_view name) { if (!codec || !codec->name) { return false; } return std::string_view(codec->name) == name; } } // namespace using namespace ffmsep; void* CPCodecContext::ensure_priv_storage(std::size_t size) { if (size == 0U) { priv_storage.clear(); priv_data = nullptr; return nullptr; } if (priv_storage.size() != size) { priv_storage.assign(size, static_cast(0)); } priv_data = priv_storage.data(); return priv_data; } void CPCodecContext::release_priv_storage() noexcept { priv_storage.clear(); priv_data = nullptr; } void cpcodec_register(const CPCodec *codec) { if (!codec || !codec->name) { return; } std::lock_guard lock(registry_mutex()); auto& reg = codec_registry(); auto already = std::find(reg.begin(), reg.end(), codec); if (already != reg.end()) { return; } auto same_id = std::find_if(reg.begin(), reg.end(), [codec](const CPCodec* entry) { return entry && codec && entry->id == codec->id && codec->id != CPCodecID::Unknow; }); if (same_id != reg.end()) { *same_id = codec; return; } reg.push_back(codec); } void cpcodec_register_many(std::initializer_list codecs) { for (const CPCodec* codec : codecs) { cpcodec_register(codec); } } const CPCodec* cpcodec_find_decoder(CPCodecID id) { std::lock_guard lock(registry_mutex()); const auto& reg = codec_registry(); auto it = std::find_if(reg.begin(), reg.end(), [id](const CPCodec* codec){ return codec && codec->id == id; }); return it == reg.end() ? nullptr : *it; } const CPCodec* cpcodec_find_decoder_by_name(std::string_view name) { std::lock_guard lock(registry_mutex()); const auto& reg = codec_registry(); auto it = std::find_if(reg.begin(), reg.end(), [name](const CPCodec* codec){ return codec_name_equals(codec, name); }); return it ==reg.end() ? nullptr : *it; } std::vector cpcodec_list_codecs() { std::lock_guard lock(registry_mutex()); return codec_registry(); } CPCodecContext* cpcodec_alloc_context(const CPCodec* codec) { auto* ctx = new CPCodecContext(); if (codec) { attach_codec(ctx, codec); } return ctx; } int cpcodec_open(CPCodecContext* ctx, const CPCodec* codec) { if (!ctx) { return CP_ERROR_INVALID_ARGUMENT; } if (ctx->is_open) { return CP_ERROR_INVALID_STATE; } if (codec) { attach_codec(ctx, codec); } if (!ctx->codec) { return CP_ERROR_INVALID_ARGUMENT; } ctx->is_open = true; if (ctx->codec->init) { int rc = ctx->codec->init(ctx); if (rc < 0) { ctx->is_open = false; if (ctx->codec->close) { ctx->codec->close(ctx); } return rc; } } return CP_SUCCESS; } int cpcodec_close(CPCodecContext *ctx) { if (!ctx) { return CP_ERROR_INVALID_ARGUMENT; } if (!ctx->is_open) { return CP_SUCCESS; } if (ctx->codec && ctx->codec->close) { ctx->codec->close(ctx); } ctx->is_open = false; ctx->release_priv_storage(); ctx->codec_type = CPMediaType::Unknow; ctx->codec = nullptr; ctx->priv_data = nullptr; return CP_SUCCESS; } void cpcodec_free_context(CPCodecContext **ctx) { if (!ctx || !*ctx) { return; } cpcodec_close(*ctx); delete *ctx; *ctx = nullptr; } int cpcodec_send_packet(CPCodecContext *ctx, const CPPacket *packet) { if (!ctx || !packet) { return CP_ERROR_INVALID_ARGUMENT; } if (!ctx || !ctx->codec) { return CP_ERROR_NOT_OPEN; } if (!ctx->codec->send_packet) { return CP_ERROR_INVALID_STATE; } return ctx->codec->send_packet(ctx, *packet); } int cpcodec_receive_frame(CPCodecContext *ctx, CPFrame *frame) { if (!ctx || !frame) { return CP_ERROR_INVALID_ARGUMENT; } if (!ctx->is_open || !ctx->codec) { return CP_ERROR_NOT_OPEN; } if (!ctx->codec->receive_frame) { return CP_ERROR_INVALID_STATE; } return ctx->codec->receive_frame(ctx, *frame); } }