Files
ts-qt/components/ffmsep/cpdecoder.cc
2025-10-29 14:08:18 +08:00

220 lines
5.1 KiB
C++

#include "cpdecoder.hh"
#include "components/ffmsep/cpdecoder.hh"
#include <algorithm>
#include <cstddef>
#include <initializer_list>
#include <mutex>
#include <string_view>
#include <vector>
namespace ffmsep {
namespace {
std::vector<const CPCodec*>& codec_registry() {
static std::vector<const CPCodec*> 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<std::uint8_t>(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<std::mutex> 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<const CPCodec*> codecs) {
for (const CPCodec* codec : codecs) {
cpcodec_register(codec);
}
}
const CPCodec* cpcodec_find_decoder(CPCodecID id) {
std::lock_guard<std::mutex> 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<std::mutex> 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<const CPCodec*> cpcodec_list_codecs() {
std::lock_guard<std::mutex> 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);
}
}