1 /*
2 * Copyright 2016 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 "rc_impl"
18
19 #include <string.h>
20
21 #include "mpp_env.h"
22 #include "mpp_mem.h"
23 #include "mpp_common.h"
24
25 #include "rc_debug.h"
26 #include "rc_impl.h"
27
28 #include "h264e_rc.h"
29 #include "h265e_rc.h"
30 #include "jpege_rc.h"
31 #include "vp8e_rc.h"
32 #include "rc_model_v2_smt.h"
33
34 const RcImplApi *rc_apis[] = {
35 &default_h264e,
36 &default_h265e,
37 &default_jpege,
38 &default_vp8e,
39 &smt_h264e,
40 &smt_h265e,
41 };
42
43 // use class to register RcImplApi
44 typedef struct RcImplApiNode_t {
45 struct list_head list;
46 char name[32];
47 MppCodingType type;
48 RcApiBrief brief;
49 RcImplApi api;
50 } RcImplApiNode;
51
set_node_api(RcImplApiNode * node,const RcImplApi * api)52 static void set_node_api(RcImplApiNode *node, const RcImplApi *api)
53 {
54 node->api = *api;
55 node->type = api->type;
56
57 strncpy(node->name, api->name, sizeof(node->name) - 1);
58 node->api.name = api->name;
59
60 node->brief.type = api->type;
61 node->brief.name = api->name;
62 }
63
RcImplApiService()64 RcImplApiService::RcImplApiService()
65 {
66 RK_U32 i;
67
68 mpp_env_get_u32("rc_debug", &rc_debug, 0);
69
70 INIT_LIST_HEAD(&mApis);
71 mApiCount = 0;
72
73 for (i = 0; i < MPP_ARRAY_ELEMS(rc_apis); i++)
74 api_add(rc_apis[i]);
75 }
76
~RcImplApiService()77 RcImplApiService::~RcImplApiService()
78 {
79 AutoMutex auto_lock(get_lock());
80 RcImplApiNode *pos, *n;
81
82 list_for_each_entry_safe(pos, n, &mApis, RcImplApiNode, list) {
83 MPP_FREE(pos);
84 mApiCount--;
85 }
86
87 mpp_assert(mApiCount == 0);
88 }
89
api_add(const RcImplApi * api)90 MPP_RET RcImplApiService::api_add(const RcImplApi *api)
91 {
92 AutoMutex auto_lock(get_lock());
93
94 if (NULL == api) {
95 mpp_err_f("unable to register NULL api\n");
96 return MPP_NOK;
97 }
98
99 /* search for same node for replacement */
100 RcImplApiNode *node = NULL;
101 RcImplApi *node_api = api_get(api->type, api->name);
102
103 if (NULL == node_api) {
104 node = mpp_malloc(RcImplApiNode, 1);
105 if (NULL == node) {
106 mpp_err_f("failed to create api node\n");
107 return MPP_NOK;
108 }
109
110 INIT_LIST_HEAD(&node->list);
111 list_add_tail(&node->list, &mApis);
112
113 mApiCount++;
114 rc_dbg_impl("rc impl %s type %x is added\n", api->name, api->type);
115 } else {
116 node = container_of(node_api, RcImplApiNode, api);
117 rc_dbg_impl("rc impl %s type %x is updated\n", api->name, api->type);
118 }
119
120 set_node_api(node, api);
121
122 return MPP_OK;
123 }
124
api_get(MppCodingType type,const char * name)125 RcImplApi *RcImplApiService::api_get(MppCodingType type, const char *name)
126 {
127 AutoMutex auto_lock(get_lock());
128
129 if (!mApiCount)
130 return NULL;
131
132 if (name) {
133 RcImplApiNode *pos, *n;
134
135 list_for_each_entry_safe(pos, n, &mApis, RcImplApiNode, list) {
136 if (type == pos->type &&
137 !strncmp(name, pos->name, sizeof(pos->name) - 1)) {
138 rc_dbg_impl("rc impl %s is selected\n", pos->name);
139 return &pos->api;
140 }
141 }
142 }
143
144 rc_dbg_impl("failed to find rc impl %s type %x\n", name, type);
145
146 return NULL;
147 }
148
api_get_all(RcApiBrief * brief,RK_S32 * count,RK_S32 max_count)149 MPP_RET RcImplApiService::api_get_all(RcApiBrief *brief, RK_S32 *count, RK_S32 max_count)
150 {
151 RK_S32 cnt = 0;
152 RcImplApiNode *pos, *n;
153
154 AutoMutex auto_lock(get_lock());
155
156 list_for_each_entry_safe(pos, n, &mApis, RcImplApiNode, list) {
157 if (cnt >= max_count)
158 break;
159
160 brief[cnt++] = pos->brief;
161 }
162
163 *count = cnt;
164
165 return MPP_OK;
166 }
167
api_get_by_type(RcApiBrief * brief,RK_S32 * count,RK_S32 max_count,MppCodingType type)168 MPP_RET RcImplApiService::api_get_by_type(RcApiBrief *brief, RK_S32 *count,
169 RK_S32 max_count, MppCodingType type)
170 {
171 RK_S32 cnt = 0;
172 RcImplApiNode *pos, *n;
173
174 AutoMutex auto_lock(get_lock());
175
176 list_for_each_entry_safe(pos, n, &mApis, RcImplApiNode, list) {
177 if (cnt >= max_count)
178 break;
179
180 if (pos->type != type)
181 continue;
182
183 brief[cnt++] = pos->brief;
184 }
185
186 *count = cnt;
187
188 return MPP_OK;
189 }
190
rc_api_add(const RcImplApi * api)191 MPP_RET rc_api_add(const RcImplApi *api)
192 {
193 return RcImplApiService::get_instance()->api_add(api);
194 }
195
rc_brief_get_all(RcApiQueryAll * query)196 MPP_RET rc_brief_get_all(RcApiQueryAll *query)
197 {
198 if (NULL == query) {
199 mpp_err_f("invalide NULL query input\n");
200 return MPP_ERR_NULL_PTR;
201 }
202
203 RcApiBrief *brief = query->brief;
204 RK_S32 *count = &query->count;
205 RK_S32 max_count = query->max_count;
206
207 if (NULL == brief || max_count <= 0) {
208 mpp_err_f("invalide brief buffer %p max count %d\n", brief, max_count);
209 return MPP_NOK;
210 }
211
212 return RcImplApiService::get_instance()->api_get_all(brief, count, max_count);
213 }
214
rc_brief_get_by_type(RcApiQueryType * query)215 MPP_RET rc_brief_get_by_type(RcApiQueryType *query)
216 {
217 if (NULL == query) {
218 mpp_err_f("invalide NULL query input\n");
219 return MPP_ERR_NULL_PTR;
220 }
221
222 RcApiBrief *brief = query->brief;
223 RK_S32 *count = &query->count;
224 RK_S32 max_count = query->max_count;
225 MppCodingType type = query->type;
226
227 if (NULL == brief || max_count <= 0) {
228 mpp_err_f("invalide brief buffer %p max count %d type %x\n",
229 brief, max_count, type);
230 return MPP_NOK;
231 }
232
233 return RcImplApiService::get_instance()->api_get_by_type(brief, count, max_count, type);
234 }
235