/* * Copyright 2015 Rockchip Electronics Co. LTD * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MODULE_TAG "mpi" #include #include "rk_mpi.h" #include "mpp_env.h" #include "mpp_mem.h" #include "mpp_debug.h" #include "mpp_common.h" #include "mpi_impl.h" #include "mpp_info.h" RK_U32 mpi_debug = 0; typedef struct { MppCtxType type; MppCodingType coding; const char *type_name; const char *coding_name; } MppCodingTypeInfo; static MppCodingTypeInfo support_list[] = { #if HAVE_MPEG2D { MPP_CTX_DEC, MPP_VIDEO_CodingMPEG2, "dec", "mpeg2", }, #endif #if HAVE_MPEG4D { MPP_CTX_DEC, MPP_VIDEO_CodingMPEG4, "dec", "mpeg4", }, #endif #if HAVE_H263D { MPP_CTX_DEC, MPP_VIDEO_CodingH263, "dec", "h.263", }, #endif #if HAVE_H264D { MPP_CTX_DEC, MPP_VIDEO_CodingAVC, "dec", "h.264/AVC", }, #endif #if HAVE_H265D { MPP_CTX_DEC, MPP_VIDEO_CodingHEVC, "dec", "h.265/HEVC", }, #endif #if HAVE_VP8D { MPP_CTX_DEC, MPP_VIDEO_CodingVP8, "dec", "vp8", }, #endif #if HAVE_VP9D { MPP_CTX_DEC, MPP_VIDEO_CodingVP9, "dec", "VP9", }, #endif #if HAVE_AVSD { MPP_CTX_DEC, MPP_VIDEO_CodingAVSPLUS, "dec", "avs+", }, #endif #if HAVE_JPEGD { MPP_CTX_DEC, MPP_VIDEO_CodingMJPEG, "dec", "jpeg", }, #endif #if HAVE_AV1D { MPP_CTX_DEC, MPP_VIDEO_CodingAV1, "dec", "av1", }, #endif #if HAVE_H264E { MPP_CTX_ENC, MPP_VIDEO_CodingAVC, "enc", "h.264/AVC", }, #endif #if HAVE_JPEGE { MPP_CTX_ENC, MPP_VIDEO_CodingMJPEG, "enc", "jpeg", }, #endif #if HAVE_H265E { MPP_CTX_ENC, MPP_VIDEO_CodingHEVC, "enc", "h265", }, #endif #if HAVE_VP8E { MPP_CTX_ENC, MPP_VIDEO_CodingVP8, "enc", "vp8", } #endif }; #define check_mpp_ctx(ctx) _check_mpp_ctx(ctx, __FUNCTION__) static MPP_RET _check_mpp_ctx(MpiImpl *p, const char *caller) { if (NULL == p || p->check != p || NULL == p->ctx) { _mpp_err(MODULE_TAG, "found invalid context %p\n", caller, p); return MPP_ERR_UNKNOW; } return MPP_OK; } static MPP_RET mpi_decode(MppCtx ctx, MppPacket packet, MppFrame *frame) { MPP_RET ret = MPP_NOK; MpiImpl *p = (MpiImpl *)ctx; mpi_dbg_func("enter ctx %p packet %p frame %p\n", ctx, packet, frame); do { RK_U32 packet_done = 0; Mpp *mpp = p->ctx; ret = check_mpp_ctx(p); if (ret) break; if (NULL == frame || NULL == packet) { mpp_err_f("found NULL input packet %p frame %p\n", packet, frame); ret = MPP_ERR_NULL_PTR; break; } *frame = NULL; do { /* * If there is frame to return get the frame first * But if the output mode is block then we need to send packet first */ if (!mpp->mOutputTimeout || packet_done) { ret = mpp->get_frame(frame); if (ret || *frame) break; } /* when packet is send do one more get frame here */ if (packet_done) break; /* * then send input stream with timeout mode */ ret = mpp->put_packet(packet); if (MPP_OK == ret) packet_done = 1; } while (1); } while (0); mpp_assert(0 == mpp_packet_get_length(packet)); mpi_dbg_func("leave ctx %p ret %d\n", ctx, ret); return ret; } static MPP_RET mpi_decode_put_packet(MppCtx ctx, MppPacket packet) { MPP_RET ret = MPP_NOK; MpiImpl *p = (MpiImpl *)ctx; mpi_dbg_func("enter ctx %p packet %p\n", ctx, packet); do { ret = check_mpp_ctx(p); if (ret) break; if (NULL == packet) { mpp_err_f("found NULL input packet\n"); ret = MPP_ERR_NULL_PTR; break; } ret = p->ctx->put_packet(packet); } while (0); mpi_dbg_func("leave ctx %p ret %d\n", ctx, ret); return ret; } static MPP_RET mpi_decode_get_frame(MppCtx ctx, MppFrame *frame) { MPP_RET ret = MPP_NOK; MpiImpl *p = (MpiImpl *)ctx; mpi_dbg_func("enter ctx %p frame %p\n", ctx, frame); do { ret = check_mpp_ctx(p); if (ret) break; if (NULL == frame) { mpp_err_f("found NULL input frame\n"); ret = MPP_ERR_NULL_PTR; break; } ret = p->ctx->get_frame(frame); } while (0); mpi_dbg_func("leave ctx %p ret %d\n", ctx, ret); return ret; } static MPP_RET mpi_encode(MppCtx ctx, MppFrame frame, MppPacket *packet) { MPP_RET ret = MPP_NOK; MpiImpl *p = (MpiImpl *)ctx; mpi_dbg_func("enter ctx %p frame %p packet %p\n", ctx, frame, packet); do { ret = check_mpp_ctx(p); if (ret) break; if (NULL == frame || NULL == packet) { mpp_err_f("found NULL input frame %p packet %p\n", frame, packet); ret = MPP_ERR_NULL_PTR; break; } // TODO: do encode here } while (0); mpi_dbg_func("leave ctx %p ret %d\n", ctx, ret); return ret; } static MPP_RET mpi_encode_put_frame(MppCtx ctx, MppFrame frame) { MPP_RET ret = MPP_NOK; MpiImpl *p = (MpiImpl *)ctx; mpi_dbg_func("enter ctx %p frame %p\n", ctx, frame); do { ret = check_mpp_ctx(p); if (ret) break; if (NULL == frame) { mpp_err_f("found NULL input frame\n"); ret = MPP_ERR_NULL_PTR; break; } ret = p->ctx->put_frame(frame); } while (0); mpi_dbg_func("leave ctx %p ret %d\n", ctx, ret); return ret; } static MPP_RET mpi_encode_get_packet(MppCtx ctx, MppPacket *packet) { MPP_RET ret = MPP_NOK; MpiImpl *p = (MpiImpl *)ctx; mpi_dbg_func("enter ctx %p packet %p\n", ctx, packet); do { ret = check_mpp_ctx(p); if (ret) break; if (NULL == packet) { mpp_err_f("found NULL input packet\n"); ret = MPP_ERR_NULL_PTR; break; } ret = p->ctx->get_packet(packet); } while (0); mpi_dbg_func("leave ctx %p ret %d\n", ctx, ret); return ret; } static MPP_RET mpi_isp(MppCtx ctx, MppFrame dst, MppFrame src) { MPP_RET ret = MPP_OK; mpi_dbg_func("enter ctx %p dst %p src %p\n", ctx, dst, src); // TODO: do isp process here mpi_dbg_func("leave ctx %p ret %d\n", ctx, ret); return MPP_OK; } static MPP_RET mpi_isp_put_frame(MppCtx ctx, MppFrame frame) { MPP_RET ret = MPP_OK; mpi_dbg_func("enter ctx %p frame %p\n", ctx, frame); // TODO: do isp put frame process here mpi_dbg_func("leave ctx %p ret %d\n", ctx, ret); return ret; } static MPP_RET mpi_isp_get_frame(MppCtx ctx, MppFrame *frame) { MPP_RET ret = MPP_OK; mpi_dbg_func("enter ctx %p frame %p\n", ctx, frame); // TODO: do isp get frame process here mpi_dbg_func("leave ret %d\n", ret); return ret; } static MPP_RET mpi_poll(MppCtx ctx, MppPortType type, MppPollType timeout) { MPP_RET ret = MPP_NOK; MpiImpl *p = (MpiImpl *)ctx; mpi_dbg_func("enter ctx %p type %d timeout %d\n", ctx, type, timeout); do { ret = check_mpp_ctx(p); if (ret) break;; if (type >= MPP_PORT_BUTT || timeout < MPP_POLL_BUTT || timeout > MPP_POLL_MAX) { mpp_err_f("invalid input type %d timeout %d\n", type, timeout); ret = MPP_ERR_UNKNOW; break; } ret = p->ctx->poll(type, timeout); if (ret > 0) ret = MPP_OK; } while (0); mpi_dbg_func("leave ctx %p ret %d\n", ctx, ret); return ret; } static MPP_RET mpi_dequeue(MppCtx ctx, MppPortType type, MppTask *task) { MPP_RET ret = MPP_NOK; MpiImpl *p = (MpiImpl *)ctx; mpi_dbg_func("enter ctx %p type %d task %p\n", ctx, type, task); do { ret = check_mpp_ctx(p); if (ret) break;; if (type >= MPP_PORT_BUTT || NULL == task) { mpp_err_f("invalid input type %d task %p\n", type, task); ret = MPP_ERR_UNKNOW; break; } ret = p->ctx->dequeue(type, task); } while (0); mpi_dbg_func("leave ctx %p ret %d\n", ctx, ret); return ret; } static MPP_RET mpi_enqueue(MppCtx ctx, MppPortType type, MppTask task) { MPP_RET ret = MPP_NOK; MpiImpl *p = (MpiImpl *)ctx; mpi_dbg_func("enter ctx %p type %d task %p\n", ctx, type, task); do { ret = check_mpp_ctx(p); if (ret) break;; if (type >= MPP_PORT_BUTT || NULL == task) { mpp_err_f("invalid input type %d task %p\n", type, task); ret = MPP_ERR_UNKNOW; break; } ret = p->ctx->enqueue(type, task); } while (0); mpi_dbg_func("leave ctx %p ret %d\n", ctx, ret); return ret; } static MPP_RET mpi_reset(MppCtx ctx) { MPP_RET ret = MPP_NOK; MpiImpl *p = (MpiImpl *)ctx; mpi_dbg_func("enter ctx %p\n", ctx); do { ret = check_mpp_ctx(p); if (ret) break;; ret = p->ctx->reset(); } while (0); mpi_dbg_func("leave ctx %p ret %d\n", ctx, ret); return ret; } static MPP_RET mpi_control(MppCtx ctx, MpiCmd cmd, MppParam param) { MPP_RET ret = MPP_NOK; MpiImpl *p = (MpiImpl *)ctx; mpi_dbg_func("enter ctx %p cmd %x parm %p\n", ctx, cmd, param); do { ret = check_mpp_ctx(p); if (ret) break;; ret = p->ctx->control(cmd, param); } while (0); mpi_dbg_func("leave ctx %p ret %d\n", ctx, ret); return ret; } static MppApi mpp_api = { sizeof(mpp_api), 0, mpi_decode, mpi_decode_put_packet, mpi_decode_get_frame, mpi_encode, mpi_encode_put_frame, mpi_encode_get_packet, mpi_isp, mpi_isp_put_frame, mpi_isp_get_frame, mpi_poll, mpi_dequeue, mpi_enqueue, mpi_reset, mpi_control, {0}, }; MPP_RET mpp_create(MppCtx *ctx, MppApi **mpi) { mpp_env_get_u32("mpi_debug", &mpi_debug, 0); mpp_get_log_level(); if (NULL == ctx || NULL == mpi) { mpp_err_f("invalid input ctx %p mpi %p\n", ctx, mpi); return MPP_ERR_NULL_PTR; } *ctx = NULL; *mpi = NULL; MPP_RET ret = MPP_OK; mpi_dbg_func("enter ctx %p mpi %p\n", ctx, mpi); do { MpiImpl *p = mpp_malloc(MpiImpl, 1); if (NULL == p) { mpp_err_f("failed to allocate context\n"); ret = MPP_ERR_MALLOC; break; } memset(p, 0, sizeof(*p)); p->ctx = new Mpp(p); if (NULL == p->ctx) { mpp_free(p); mpp_err_f("failed to new Mpp\n"); ret = MPP_ERR_MALLOC; break; } mpp_api.version = 0; p->api = &mpp_api; p->check = p; *ctx = p; *mpi = p->api; } while (0); show_mpp_version(); mpi_dbg_func("leave ret %d ctx %p mpi %p\n", ret, *ctx, *mpi); return ret; } MPP_RET mpp_init(MppCtx ctx, MppCtxType type, MppCodingType coding) { MPP_RET ret = MPP_OK; MpiImpl *p = (MpiImpl*)ctx; mpi_dbg_func("enter ctx %p type %d coding %d\n", ctx, type, coding); do { ret = check_mpp_ctx(p); if (ret) break; if (type >= MPP_CTX_BUTT || coding >= MPP_VIDEO_CodingMax) { mpp_err_f("invalid input type %d coding %d\n", type, coding); ret = MPP_ERR_UNKNOW; break; } ret = p->ctx->init(type, coding); p->type = type; p->coding = coding; } while (0); mpi_dbg_func("leave ctx %p ret %d\n", ctx, ret); return ret; } MPP_RET mpp_destroy(MppCtx ctx) { mpi_dbg_func("enter ctx %p\n", ctx); MPP_RET ret = MPP_OK; MpiImpl *p = (MpiImpl*)ctx; do { ret = check_mpp_ctx(p); if (ret) return ret; if (p->ctx) delete p->ctx; mpp_free(p); } while (0); mpi_dbg_func("leave ctx %p ret %d\n", ctx, ret); return ret; } MPP_RET mpp_check_support_format(MppCtxType type, MppCodingType coding) { MPP_RET ret = MPP_NOK; RK_U32 i = 0; for (i = 0; i < MPP_ARRAY_ELEMS(support_list); i++) { MppCodingTypeInfo *info = &support_list[i]; if (type == info->type && coding == info->coding) { ret = MPP_OK; break; } } return ret; } void mpp_show_support_format() { RK_U32 i = 0; mpp_log("mpp coding type support list:"); for (i = 0; i < MPP_ARRAY_ELEMS(support_list); i++) { MppCodingTypeInfo *info = &support_list[i]; mpp_log("type: %s id %d coding: %-16s id %d\n", info->type_name, info->type, info->coding_name, info->coding); } } typedef struct { MppFrameFormat format; const char *name; } MppFrameFormatInfo; static MppFrameFormatInfo color_list[] = { { MPP_FMT_YUV420SP, "YUV420SP, NV12" }, { MPP_FMT_YUV420SP_10BIT, "YUV420SP-10bit" }, { MPP_FMT_YUV422SP, "YUV422SP, NV24" }, { MPP_FMT_YUV422SP_10BIT, "YUV422SP-10bit" }, { MPP_FMT_YUV420P, "YUV420P, I420" }, { MPP_FMT_YUV420SP_VU, "YUV420SP, NV21" }, { MPP_FMT_YUV422P, "YUV422P, 422P" }, { MPP_FMT_YUV422SP_VU, "YUV422SP, NV42" }, { MPP_FMT_YUV422_YUYV, "YUV422-YUYV, YUY2" }, { MPP_FMT_YUV422_UYVY, "YUV422-UYVY, UYVY" }, { MPP_FMT_YUV400, "YUV400-Y8, Y800" }, { MPP_FMT_YUV444SP, "YUV444SP" }, { MPP_FMT_YUV444P, "YUV444P" }, { MPP_FMT_RGB565, "RGB565" }, { MPP_FMT_BGR565, "BGR565" }, { MPP_FMT_RGB555, "RGB555" }, { MPP_FMT_BGR555, "BGR555" }, { MPP_FMT_RGB888, "RGB888" }, { MPP_FMT_BGR888, "BGR888" }, { MPP_FMT_ARGB8888, "ARGB8888" }, { MPP_FMT_ABGR8888, "ABGR8888" }, { MPP_FMT_BGRA8888, "BGRA8888" }, { MPP_FMT_RGBA8888, "RGBA8888" }, }; void mpp_show_color_format() { RK_U32 i = 0; mpp_log("mpp color support list:"); for (i = 0; i < MPP_ARRAY_ELEMS(color_list); i++) { MppFrameFormatInfo *info = &color_list[i]; mpp_log("color: id %-5d 0x%05x %s\n", info->format, info->format, info->name); } }