#include "MjpegEncoder.h" #include #if !defined(__linux__) // =================== 非 Linux 占位:始终失败,调用方回退原始数据 =================== MppMjpegEncoder::~MppMjpegEncoder() = default; bool MppMjpegEncoder::EncodeMono8(const uint8_t*, size_t, int, int, std::vector&) { return false; } void MppMjpegEncoder::SetQuality(int q) { if (q < 1) q = 1; if (q > 99) q = 99; m_quality = q; } #else #include "VrLog.h" #include "rk_type.h" #include "rk_mpi.h" #include "mpp_frame.h" #include "mpp_packet.h" #include "mpp_buffer.h" #include "rk_venc_cfg.h" namespace { inline int alignTo(int v, int a) { return (v + a - 1) & ~(a - 1); } } MppMjpegEncoder::~MppMjpegEncoder() { std::lock_guard lk(m_mutex); release(); } void MppMjpegEncoder::SetQuality(int q) { if (q < 1) q = 1; if (q > 99) q = 99; std::lock_guard lk(m_mutex); if (q != m_quality) { m_quality = q; release(); // 强制下一帧用新质量重建编码器 } } void MppMjpegEncoder::release() { if (m_ctx) { mpp_destroy(static_cast(m_ctx)); m_ctx = nullptr; m_mpi = nullptr; } if (m_grp) { mpp_buffer_group_put(static_cast(m_grp)); m_grp = nullptr; } m_w = m_h = m_hor = m_ver = 0; } bool MppMjpegEncoder::ensureInited(int width, int height) { if (m_ctx && m_w == width && m_h == height) return true; release(); m_w = width; m_h = height; m_hor = alignTo(width, 16); m_ver = alignTo(height, 16); MppCtx ctx = nullptr; MppApi* mpi = nullptr; if (mpp_create(&ctx, &mpi) != MPP_OK || !ctx || !mpi) { LOG_ERROR("[MJPEG] mpp_create fail\n"); release(); return false; } m_ctx = ctx; m_mpi = mpi; if (mpp_init(ctx, MPP_CTX_ENC, MPP_VIDEO_CodingMJPEG) != MPP_OK) { LOG_ERROR("[MJPEG] mpp_init fail\n"); release(); return false; } MppEncCfg cfg = nullptr; if (mpp_enc_cfg_init(&cfg) != MPP_OK || !cfg) { LOG_ERROR("[MJPEG] enc_cfg_init fail\n"); release(); return false; } // 输入帧格式:以 NV12 承载 Mono8(Y=灰度,UV=128),输出标准 JPEG mpp_enc_cfg_set_s32(cfg, "prep:width", m_w); mpp_enc_cfg_set_s32(cfg, "prep:height", m_h); mpp_enc_cfg_set_s32(cfg, "prep:hor_stride", m_hor); mpp_enc_cfg_set_s32(cfg, "prep:ver_stride", m_ver); mpp_enc_cfg_set_s32(cfg, "prep:format", MPP_FMT_YUV420SP); mpp_enc_cfg_set_s32(cfg, "codec:type", MPP_VIDEO_CodingMJPEG); // MJPEG 采用固定质量:q_factor 越大越清晰、体积越大(1~99) mpp_enc_cfg_set_s32(cfg, "rc:mode", MPP_ENC_RC_MODE_FIXQP); mpp_enc_cfg_set_s32(cfg, "jpeg:q_factor", m_quality); mpp_enc_cfg_set_s32(cfg, "jpeg:qf_min", 1); mpp_enc_cfg_set_s32(cfg, "jpeg:qf_max", 99); const int ret = mpi->control(ctx, MPP_ENC_SET_CFG, cfg); mpp_enc_cfg_deinit(cfg); if (ret != MPP_OK) { LOG_ERROR("[MJPEG] MPP_ENC_SET_CFG fail %d\n", ret); release(); return false; } MppBufferGroup grp = nullptr; if (mpp_buffer_group_get_internal(&grp, MPP_BUFFER_TYPE_DRM) != MPP_OK) { LOG_ERROR("[MJPEG] buffer group get fail\n"); release(); return false; } m_grp = grp; LOG_INFO("[MJPEG] encoder ready %dx%d stride=%dx%d q=%d\n", m_w, m_h, m_hor, m_ver, m_quality); return true; } bool MppMjpegEncoder::EncodeMono8(const uint8_t* mono, size_t monoSize, int width, int height, std::vector& jpeg) { if (!mono || width <= 0 || height <= 0) return false; if (monoSize < static_cast(width) * static_cast(height)) return false; std::lock_guard lk(m_mutex); if (!ensureInited(width, height)) return false; MppApi* mpi = static_cast(m_mpi); MppCtx ctx = static_cast(m_ctx); MppBufferGroup grp = static_cast(m_grp); const int frameSize = m_hor * m_ver * 3 / 2; MppBuffer buf = nullptr; if (mpp_buffer_get(grp, &buf, frameSize) != MPP_OK || !buf) return false; uint8_t* dst = static_cast(mpp_buffer_get_ptr(buf)); if (!dst) { mpp_buffer_put(buf); return false; } // Mono8 → NV12:Y 平面逐行拷贝(源 stride=width → 目标 hor_stride),UV 平面填 128(灰度) uint8_t* dstY = dst; uint8_t* dstUV = dst + static_cast(m_hor) * m_ver; for (int y = 0; y < m_h; ++y) std::memcpy(dstY + static_cast(y) * m_hor, mono + static_cast(y) * m_w, m_w); std::memset(dstUV, 128, static_cast(m_hor) * (m_ver / 2)); MppFrame frame = nullptr; mpp_frame_init(&frame); mpp_frame_set_width(frame, m_w); mpp_frame_set_height(frame, m_h); mpp_frame_set_hor_stride(frame, m_hor); mpp_frame_set_ver_stride(frame, m_ver); mpp_frame_set_fmt(frame, MPP_FMT_YUV420SP); mpp_frame_set_buffer(frame, buf); MppPacket pkt = nullptr; const int ret = mpi->encode(ctx, frame, &pkt); mpp_frame_deinit(&frame); mpp_buffer_put(buf); if (ret != MPP_OK || !pkt) return false; void* p = mpp_packet_get_data(pkt); size_t len = mpp_packet_get_length(pkt); bool ok = false; if (p && len > 0) { const uint8_t* bytes = static_cast(p); jpeg.assign(bytes, bytes + len); ok = true; } mpp_packet_deinit(&pkt); return ok; } #endif // __linux__