1 /*
2 * Copyright 2015 Rockchip Electronics Co. LTD
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define MODULE_TAG "mpp_meta"
18
19 #include <string.h>
20
21 #include "mpp_mem.h"
22 #include "mpp_list.h"
23 #include "mpp_lock.h"
24
25 #include "mpp_meta_impl.h"
26
27 #define META_VAL_INVALID (0x00000000)
28 #define META_VAL_VALID (0x00000001)
29 #define META_VAL_READY (0x00000002)
30
31 #define WRITE_ONCE(x, val) ((*(volatile typeof(x) *) &(x)) = (val))
32 #define READ_ONCE(var) (*((volatile typeof(var) *)(&(var))))
33
34 static MppMetaDef meta_defs[] = {
35 /* categorized by type */
36 /* data flow type */
37 { KEY_INPUT_FRAME, TYPE_FRAME, },
38 { KEY_OUTPUT_FRAME, TYPE_FRAME, },
39 { KEY_INPUT_PACKET, TYPE_PACKET, },
40 { KEY_OUTPUT_PACKET, TYPE_PACKET, },
41 /* buffer for motion detection */
42 { KEY_MOTION_INFO, TYPE_BUFFER, },
43 /* buffer storing the HDR information for current frame*/
44 { KEY_HDR_INFO, TYPE_BUFFER, },
45 /* the offset of HDR meta data in frame buffer */
46 { KEY_HDR_META_OFFSET, TYPE_S32, },
47 { KEY_HDR_META_SIZE, TYPE_S32, },
48
49 { KEY_OUTPUT_INTRA, TYPE_S32, },
50 { KEY_INPUT_BLOCK, TYPE_S32, },
51 { KEY_OUTPUT_BLOCK, TYPE_S32, },
52
53 /* extra information for tsvc */
54 { KEY_TEMPORAL_ID, TYPE_S32, },
55 { KEY_LONG_REF_IDX, TYPE_S32, },
56 { KEY_ENC_AVERAGE_QP, TYPE_S32, },
57
58 { KEY_ROI_DATA, TYPE_PTR, },
59 { KEY_ROI_DATA2, TYPE_PTR, },
60 { KEY_OSD_DATA, TYPE_PTR, },
61 { KEY_OSD_DATA2, TYPE_PTR, },
62 { KEY_USER_DATA, TYPE_PTR, },
63 { KEY_USER_DATAS, TYPE_PTR, },
64 { KEY_QPMAP0, TYPE_BUFFER, },
65 { KEY_MV_LIST, TYPE_PTR, },
66
67 { KEY_ENC_MARK_LTR, TYPE_S32, },
68 { KEY_ENC_USE_LTR, TYPE_S32, },
69 { KEY_ENC_FRAME_QP, TYPE_S32, },
70 { KEY_ENC_BASE_LAYER_PID, TYPE_S32, },
71
72 { KEY_DEC_TBN_EN, TYPE_S32, },
73 { KEY_DEC_TBN_Y_OFFSET, TYPE_S32, },
74 { KEY_DEC_TBN_UV_OFFSET, TYPE_S32, },
75 };
76
77 class MppMetaService
78 {
79 private:
80 // avoid any unwanted function
81 MppMetaService();
82 ~MppMetaService();
83 MppMetaService(const MppMetaService &);
84 MppMetaService &operator=(const MppMetaService &);
85
86 spinlock_t mLock;
87 struct list_head mlist_meta;
88
89 RK_U32 meta_id;
90 RK_S32 meta_count;
91 RK_U32 finished;
92
93 public:
get_inst()94 static MppMetaService *get_inst() {
95 static MppMetaService instance;
96 return &instance;
97 }
98
99 /*
100 * get_index_of_key does two things:
101 * 1. Check the key / type pair is correct or not.
102 * If failed on check return negative value
103 * 2. Compare all exsisting meta data defines to find the non-negative index
104 */
105 RK_S32 get_index_of_key(MppMetaKey key, MppMetaType type);
106
107 MppMetaImpl *get_meta(const char *tag, const char *caller);
108 void put_meta(MppMetaImpl *meta);
109 };
110
MppMetaService()111 MppMetaService::MppMetaService()
112 : meta_id(0),
113 meta_count(0),
114 finished(0)
115 {
116 mpp_spinlock_init(&mLock);
117 INIT_LIST_HEAD(&mlist_meta);
118 }
119
~MppMetaService()120 MppMetaService::~MppMetaService()
121 {
122 if (!list_empty(&mlist_meta)) {
123 MppMetaImpl *pos, *n;
124
125 mpp_log_f("cleaning leaked metadata\n");
126
127 list_for_each_entry_safe(pos, n, &mlist_meta, MppMetaImpl, list_meta) {
128 put_meta(pos);
129 }
130 }
131
132 mpp_assert(meta_count == 0);
133 finished = 1;
134 }
135
get_index_of_key(MppMetaKey key,MppMetaType type)136 RK_S32 MppMetaService::get_index_of_key(MppMetaKey key, MppMetaType type)
137 {
138 RK_S32 i = 0;
139 RK_S32 num = MPP_ARRAY_ELEMS(meta_defs);
140
141 for (i = 0; i < num; i++) {
142 if ((meta_defs[i].key == key) && (meta_defs[i].type == type))
143 break;
144 }
145
146 return (i < num) ? (i) : (-1);
147 }
148
get_meta(const char * tag,const char * caller)149 MppMetaImpl *MppMetaService::get_meta(const char *tag, const char *caller)
150 {
151 MppMetaImpl *impl = mpp_malloc_size(MppMetaImpl, sizeof(MppMetaImpl) +
152 sizeof(MppMetaVal) * MPP_ARRAY_ELEMS(meta_defs));
153 if (impl) {
154 const char *tag_src = (tag) ? (tag) : (MODULE_TAG);
155 RK_U32 i;
156
157 strncpy(impl->tag, tag_src, sizeof(impl->tag));
158 impl->caller = caller;
159 impl->meta_id = MPP_FETCH_ADD(&meta_id, 1);
160 INIT_LIST_HEAD(&impl->list_meta);
161 impl->ref_count = 1;
162 impl->node_count = 0;
163
164 for (i = 0; i < MPP_ARRAY_ELEMS(meta_defs); i++)
165 impl->vals[i].state = 0;
166
167 mpp_spinlock_lock(&mLock);
168 list_add_tail(&impl->list_meta, &mlist_meta);
169 mpp_spinlock_unlock(&mLock);
170 MPP_FETCH_ADD(&meta_count, 1);
171 } else {
172 mpp_err_f("failed to malloc meta data\n");
173 }
174 return impl;
175 }
176
put_meta(MppMetaImpl * meta)177 void MppMetaService::put_meta(MppMetaImpl *meta)
178 {
179 if (finished)
180 return ;
181
182 RK_S32 ref_count = MPP_SUB_FETCH(&meta->ref_count, 1);
183
184 if (ref_count > 0)
185 return;
186
187 if (ref_count < 0) {
188 mpp_err_f("invalid negative ref_count %d\n", ref_count);
189 return;
190 }
191
192 mpp_spinlock_lock(&mLock);
193 list_del_init(&meta->list_meta);
194 mpp_spinlock_unlock(&mLock);
195 MPP_FETCH_SUB(&meta_count, 1);
196
197 mpp_free(meta);
198 }
199
mpp_meta_get_with_tag(MppMeta * meta,const char * tag,const char * caller)200 MPP_RET mpp_meta_get_with_tag(MppMeta *meta, const char *tag, const char *caller)
201 {
202 if (NULL == meta) {
203 mpp_err_f("found NULL input\n");
204 return MPP_ERR_NULL_PTR;
205 }
206
207 MppMetaService *service = MppMetaService::get_inst();
208 MppMetaImpl *impl = service->get_meta(tag, caller);
209 *meta = (MppMeta) impl;
210 return (impl) ? (MPP_OK) : (MPP_NOK);
211 }
212
mpp_meta_put(MppMeta meta)213 MPP_RET mpp_meta_put(MppMeta meta)
214 {
215 if (NULL == meta) {
216 mpp_err_f("found NULL input\n");
217 return MPP_ERR_NULL_PTR;
218 }
219
220 MppMetaService *service = MppMetaService::get_inst();
221 MppMetaImpl *impl = (MppMetaImpl *)meta;
222
223 service->put_meta(impl);
224 return MPP_OK;
225 }
226
mpp_meta_inc_ref(MppMeta meta)227 MPP_RET mpp_meta_inc_ref(MppMeta meta)
228 {
229 if (NULL == meta) {
230 mpp_err_f("found NULL input\n");
231 return MPP_ERR_NULL_PTR;
232 }
233
234 MppMetaImpl *impl = (MppMetaImpl *)meta;
235
236 MPP_FETCH_ADD(&impl->ref_count, 1);
237 return MPP_OK;
238 }
239
mpp_meta_size(MppMeta meta)240 RK_S32 mpp_meta_size(MppMeta meta)
241 {
242 if (NULL == meta) {
243 mpp_err_f("found NULL input\n");
244 return -1;
245 }
246
247 MppMetaImpl *impl = (MppMetaImpl *)meta;
248
249 return MPP_FETCH_ADD(&impl->node_count, 0);
250 }
251
mpp_meta_dump(MppMeta meta)252 MPP_RET mpp_meta_dump(MppMeta meta)
253 {
254 if (NULL == meta) {
255 mpp_err_f("found NULL input\n");
256 return MPP_ERR_NULL_PTR;
257 }
258
259 MppMetaImpl *impl = (MppMetaImpl *)meta;
260 RK_U32 i;
261
262 mpp_log("dumping meta %d node count %d\n", impl->meta_id, impl->node_count);
263
264 for (i = 0; i < MPP_ARRAY_ELEMS(meta_defs); i++) {
265 if (!impl->vals[i].state)
266 continue;
267
268 const char *key = (const char *)&meta_defs[i].key;
269 const char *type = (const char *)&meta_defs[i].type;
270
271 mpp_log("key %c%c%c%c type %c%c%c%c\n",
272 key[3], key[2], key[1], key[0],
273 type[3], type[2], type[1], type[0]);
274 }
275
276 return MPP_OK;
277 }
278
279 #define MPP_META_ACCESSOR(func_type, arg_type, key_type, key_field) \
280 MPP_RET mpp_meta_set_##func_type(MppMeta meta, MppMetaKey key, arg_type val) \
281 { \
282 if (NULL == meta) { \
283 mpp_err_f("found NULL input\n"); \
284 return MPP_ERR_NULL_PTR; \
285 } \
286 MppMetaService *service = MppMetaService::get_inst(); \
287 RK_S32 index = service->get_index_of_key(key, key_type); \
288 if (index < 0) \
289 return MPP_NOK; \
290 MppMetaImpl *impl = (MppMetaImpl *)meta; \
291 MppMetaVal *meta_val = &impl->vals[index]; \
292 if (MPP_BOOL_CAS(&meta_val->state, META_VAL_INVALID, META_VAL_VALID)) \
293 MPP_FETCH_ADD(&impl->node_count, 1); \
294 meta_val->key_field = val; \
295 MPP_FETCH_OR(&meta_val->state, META_VAL_READY); \
296 return MPP_OK; \
297 } \
298 MPP_RET mpp_meta_get_##func_type(MppMeta meta, MppMetaKey key, arg_type *val) \
299 { \
300 if (NULL == meta) { \
301 mpp_err_f("found NULL input\n"); \
302 return MPP_ERR_NULL_PTR; \
303 } \
304 MppMetaService *service = MppMetaService::get_inst(); \
305 RK_S32 index = service->get_index_of_key(key, key_type); \
306 if (index < 0) \
307 return MPP_NOK; \
308 MppMetaImpl *impl = (MppMetaImpl *)meta; \
309 MppMetaVal *meta_val = &impl->vals[index]; \
310 MPP_RET ret = MPP_NOK; \
311 if (MPP_BOOL_CAS(&meta_val->state, META_VAL_VALID | META_VAL_READY, META_VAL_INVALID)) { \
312 *val = meta_val->key_field; \
313 MPP_FETCH_SUB(&impl->node_count, 1); \
314 ret = MPP_OK; \
315 } \
316 return ret; \
317 } \
318 MPP_RET mpp_meta_get_##func_type##_d(MppMeta meta, MppMetaKey key, arg_type *val, arg_type def) \
319 { \
320 if (NULL == meta) { \
321 mpp_err_f("found NULL input\n"); \
322 return MPP_ERR_NULL_PTR; \
323 } \
324 MppMetaService *service = MppMetaService::get_inst(); \
325 RK_S32 index = service->get_index_of_key(key, key_type); \
326 if (index < 0) \
327 return MPP_NOK; \
328 MppMetaImpl *impl = (MppMetaImpl *)meta; \
329 MppMetaVal *meta_val = &impl->vals[index]; \
330 MPP_RET ret = MPP_NOK; \
331 if (MPP_BOOL_CAS(&meta_val->state, META_VAL_VALID | META_VAL_READY, META_VAL_INVALID)) { \
332 *val = meta_val->key_field; \
333 MPP_FETCH_SUB(&impl->node_count, 1); \
334 ret = MPP_OK; \
335 } else { \
336 *val = def; \
337 } \
338 return ret; \
339 }
340
341 MPP_META_ACCESSOR(s32, RK_S32, TYPE_S32, val_s32)
342 MPP_META_ACCESSOR(s64, RK_S64, TYPE_S64, val_s64)
343 MPP_META_ACCESSOR(ptr, void *, TYPE_PTR, val_ptr)
344 MPP_META_ACCESSOR(frame, MppFrame, TYPE_FRAME, frame)
345 MPP_META_ACCESSOR(packet, MppPacket, TYPE_PACKET, packet)
346 MPP_META_ACCESSOR(buffer, MppBuffer, TYPE_BUFFER, buffer)
347