/* * 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 "mpp_meta" #include #include "mpp_mem.h" #include "mpp_list.h" #include "mpp_lock.h" #include "mpp_meta_impl.h" #define META_VAL_INVALID (0x00000000) #define META_VAL_VALID (0x00000001) #define META_VAL_READY (0x00000002) #define WRITE_ONCE(x, val) ((*(volatile typeof(x) *) &(x)) = (val)) #define READ_ONCE(var) (*((volatile typeof(var) *)(&(var)))) static MppMetaDef meta_defs[] = { /* categorized by type */ /* data flow type */ { KEY_INPUT_FRAME, TYPE_FRAME, }, { KEY_OUTPUT_FRAME, TYPE_FRAME, }, { KEY_INPUT_PACKET, TYPE_PACKET, }, { KEY_OUTPUT_PACKET, TYPE_PACKET, }, /* buffer for motion detection */ { KEY_MOTION_INFO, TYPE_BUFFER, }, /* buffer storing the HDR information for current frame*/ { KEY_HDR_INFO, TYPE_BUFFER, }, { KEY_OUTPUT_INTRA, TYPE_S32, }, { KEY_INPUT_BLOCK, TYPE_S32, }, { KEY_OUTPUT_BLOCK, TYPE_S32, }, /* extra information for tsvc */ { KEY_TEMPORAL_ID, TYPE_S32, }, { KEY_LONG_REF_IDX, TYPE_S32, }, { KEY_ENC_AVERAGE_QP, TYPE_S32, }, { KEY_ROI_DATA, TYPE_PTR, }, { KEY_ROI_DATA2, TYPE_PTR, }, { KEY_OSD_DATA, TYPE_PTR, }, { KEY_OSD_DATA2, TYPE_PTR, }, { KEY_USER_DATA, TYPE_PTR, }, { KEY_USER_DATAS, TYPE_PTR, }, { KEY_QPMAP0, TYPE_BUFFER, }, { KEY_MV_LIST, TYPE_PTR, }, { KEY_ENC_MARK_LTR, TYPE_S32, }, { KEY_ENC_USE_LTR, TYPE_S32, }, { KEY_ENC_FRAME_QP, TYPE_S32, }, { KEY_ENC_BASE_LAYER_PID, TYPE_S32, }, }; class MppMetaService { private: // avoid any unwanted function MppMetaService(); ~MppMetaService(); MppMetaService(const MppMetaService &); MppMetaService &operator=(const MppMetaService &); spinlock_t mLock; struct list_head mlist_meta; RK_U32 meta_id; RK_S32 meta_count; RK_U32 finished; public: static MppMetaService *get_inst() { static MppMetaService instance; return &instance; } /* * get_index_of_key does two things: * 1. Check the key / type pair is correct or not. * If failed on check return negative value * 2. Compare all exsisting meta data defines to find the non-negative index */ RK_S32 get_index_of_key(MppMetaKey key, MppMetaType type); MppMetaImpl *get_meta(const char *tag, const char *caller); void put_meta(MppMetaImpl *meta); }; MppMetaService::MppMetaService() : meta_id(0), meta_count(0), finished(0) { mpp_spinlock_init(&mLock); INIT_LIST_HEAD(&mlist_meta); } MppMetaService::~MppMetaService() { if (!list_empty(&mlist_meta)) { MppMetaImpl *pos, *n; mpp_log_f("cleaning leaked metadata\n"); list_for_each_entry_safe(pos, n, &mlist_meta, MppMetaImpl, list_meta) { put_meta(pos); } } mpp_assert(meta_count == 0); finished = 1; } RK_S32 MppMetaService::get_index_of_key(MppMetaKey key, MppMetaType type) { RK_S32 i = 0; RK_S32 num = MPP_ARRAY_ELEMS(meta_defs); for (i = 0; i < num; i++) { if ((meta_defs[i].key == key) && (meta_defs[i].type == type)) break; } return (i < num) ? (i) : (-1); } MppMetaImpl *MppMetaService::get_meta(const char *tag, const char *caller) { MppMetaImpl *impl = mpp_malloc_size(MppMetaImpl, sizeof(MppMetaImpl) + sizeof(MppMetaVal) * MPP_ARRAY_ELEMS(meta_defs)); if (impl) { const char *tag_src = (tag) ? (tag) : (MODULE_TAG); RK_U32 i; strncpy(impl->tag, tag_src, sizeof(impl->tag)); impl->caller = caller; impl->meta_id = MPP_FETCH_ADD(&meta_id, 1); INIT_LIST_HEAD(&impl->list_meta); impl->ref_count = 1; impl->node_count = 0; for (i = 0; i < MPP_ARRAY_ELEMS(meta_defs); i++) impl->vals[i].state = 0; mpp_spinlock_lock(&mLock); list_add_tail(&impl->list_meta, &mlist_meta); mpp_spinlock_unlock(&mLock); MPP_FETCH_ADD(&meta_count, 1); } else { mpp_err_f("failed to malloc meta data\n"); } return impl; } void MppMetaService::put_meta(MppMetaImpl *meta) { if (finished) return ; RK_S32 ref_count = MPP_SUB_FETCH(&meta->ref_count, 1); if (ref_count > 0) return; if (ref_count < 0) { mpp_err_f("invalid negative ref_count %d\n", ref_count); return; } mpp_spinlock_lock(&mLock); list_del_init(&meta->list_meta); mpp_spinlock_unlock(&mLock); MPP_FETCH_SUB(&meta_count, 1); mpp_free(meta); } MPP_RET mpp_meta_get_with_tag(MppMeta *meta, const char *tag, const char *caller) { if (NULL == meta) { mpp_err_f("found NULL input\n"); return MPP_ERR_NULL_PTR; } MppMetaService *service = MppMetaService::get_inst(); MppMetaImpl *impl = service->get_meta(tag, caller); *meta = (MppMeta) impl; return (impl) ? (MPP_OK) : (MPP_NOK); } MPP_RET mpp_meta_put(MppMeta meta) { if (NULL == meta) { mpp_err_f("found NULL input\n"); return MPP_ERR_NULL_PTR; } MppMetaService *service = MppMetaService::get_inst(); MppMetaImpl *impl = (MppMetaImpl *)meta; service->put_meta(impl); return MPP_OK; } MPP_RET mpp_meta_inc_ref(MppMeta meta) { if (NULL == meta) { mpp_err_f("found NULL input\n"); return MPP_ERR_NULL_PTR; } MppMetaImpl *impl = (MppMetaImpl *)meta; MPP_FETCH_ADD(&impl->ref_count, 1); return MPP_OK; } RK_S32 mpp_meta_size(MppMeta meta) { if (NULL == meta) { mpp_err_f("found NULL input\n"); return -1; } MppMetaImpl *impl = (MppMetaImpl *)meta; return MPP_FETCH_ADD(&impl->node_count, 0); } MPP_RET mpp_meta_dump(MppMeta meta) { if (NULL == meta) { mpp_err_f("found NULL input\n"); return MPP_ERR_NULL_PTR; } MppMetaImpl *impl = (MppMetaImpl *)meta; RK_U32 i; mpp_log("dumping meta %d node count %d\n", impl->meta_id, impl->node_count); for (i = 0; i < MPP_ARRAY_ELEMS(meta_defs); i++) { if (!impl->vals[i].state) continue; const char *key = (const char *)&meta_defs[i].key; const char *type = (const char *)&meta_defs[i].type; mpp_log("key %c%c%c%c type %c%c%c%c\n", key[3], key[2], key[1], key[0], type[3], type[2], type[1], type[0]); } return MPP_OK; } #define MPP_META_ACCESSOR(func_type, arg_type, key_type, key_field) \ MPP_RET mpp_meta_set_##func_type(MppMeta meta, MppMetaKey key, arg_type val) \ { \ if (NULL == meta) { \ mpp_err_f("found NULL input\n"); \ return MPP_ERR_NULL_PTR; \ } \ MppMetaService *service = MppMetaService::get_inst(); \ RK_S32 index = service->get_index_of_key(key, key_type); \ if (index < 0) \ return MPP_NOK; \ MppMetaImpl *impl = (MppMetaImpl *)meta; \ MppMetaVal *meta_val = &impl->vals[index]; \ if (MPP_BOOL_CAS(&meta_val->state, META_VAL_INVALID, META_VAL_VALID)) \ MPP_FETCH_ADD(&impl->node_count, 1); \ meta_val->key_field = val; \ MPP_FETCH_OR(&meta_val->state, META_VAL_READY); \ return MPP_OK; \ } \ MPP_RET mpp_meta_get_##func_type(MppMeta meta, MppMetaKey key, arg_type *val) \ { \ if (NULL == meta) { \ mpp_err_f("found NULL input\n"); \ return MPP_ERR_NULL_PTR; \ } \ MppMetaService *service = MppMetaService::get_inst(); \ RK_S32 index = service->get_index_of_key(key, key_type); \ if (index < 0) \ return MPP_NOK; \ MppMetaImpl *impl = (MppMetaImpl *)meta; \ MppMetaVal *meta_val = &impl->vals[index]; \ MPP_RET ret = MPP_NOK; \ if (MPP_BOOL_CAS(&meta_val->state, META_VAL_VALID | META_VAL_READY, META_VAL_INVALID)) { \ *val = meta_val->key_field; \ MPP_FETCH_SUB(&impl->node_count, 1); \ ret = MPP_OK; \ } \ return ret; \ } \ MPP_RET mpp_meta_get_##func_type##_d(MppMeta meta, MppMetaKey key, arg_type *val, arg_type def) \ { \ if (NULL == meta) { \ mpp_err_f("found NULL input\n"); \ return MPP_ERR_NULL_PTR; \ } \ MppMetaService *service = MppMetaService::get_inst(); \ RK_S32 index = service->get_index_of_key(key, key_type); \ if (index < 0) \ return MPP_NOK; \ MppMetaImpl *impl = (MppMetaImpl *)meta; \ MppMetaVal *meta_val = &impl->vals[index]; \ MPP_RET ret = MPP_NOK; \ if (MPP_BOOL_CAS(&meta_val->state, META_VAL_VALID | META_VAL_READY, META_VAL_INVALID)) { \ *val = meta_val->key_field; \ MPP_FETCH_SUB(&impl->node_count, 1); \ ret = MPP_OK; \ } else { \ *val = def; \ } \ return ret; \ } MPP_META_ACCESSOR(s32, RK_S32, TYPE_S32, val_s32) MPP_META_ACCESSOR(s64, RK_S64, TYPE_S64, val_s64) MPP_META_ACCESSOR(ptr, void *, TYPE_PTR, val_ptr) MPP_META_ACCESSOR(frame, MppFrame, TYPE_FRAME, frame) MPP_META_ACCESSOR(packet, MppPacket, TYPE_PACKET, packet) MPP_META_ACCESSOR(buffer, MppBuffer, TYPE_BUFFER, buffer)