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"
18
19 #include <math.h>
20 #include <memory.h>
21
22 #include "mpp_env.h"
23 #include "mpp_mem.h"
24 #include "mpp_list.h"
25 #include "mpp_common.h"
26
27 #include "rc_debug.h"
28 #include "rc.h"
29 #include "rc_impl.h"
30 #include "rc_base.h"
31
32 typedef struct MppRcImpl_t {
33 void *ctx;
34 const RcImplApi *api;
35 RcCfg cfg;
36
37 RcFpsCfg fps;
38 RK_S32 frm_cnt;
39
40 RK_U32 frm_send;
41 RK_U32 frm_done;
42 } MppRcImpl;
43
44 RK_U32 rc_debug = 0;
45
46 const static char default_rc_api[] = "default";
47
rc_init(RcCtx * ctx,MppCodingType type,const char ** request_name)48 MPP_RET rc_init(RcCtx *ctx, MppCodingType type, const char **request_name)
49 {
50 MPP_RET ret = MPP_NOK;
51 MppRcImpl *p = NULL;
52 const char *name = NULL;
53
54 mpp_env_get_u32("rc_debug", &rc_debug, 0);
55
56 if (NULL == request_name || NULL == *request_name)
57 name = default_rc_api;
58 else
59 name = *request_name;
60
61 rc_dbg_func("enter type %x name %s\n", type, name);
62
63 RcImplApi *api = RcImplApiService::get_instance()->api_get(type, name);
64
65 mpp_assert(api);
66
67 if (api) {
68 void *rc_ctx = mpp_calloc_size(void, api->ctx_size);
69 p = mpp_calloc(MppRcImpl, 1);
70
71 if (NULL == p || NULL == rc_ctx) {
72 mpp_err_f("failed to create context size %d\n", api->ctx_size);
73 MPP_FREE(p);
74 MPP_FREE(rc_ctx);
75 ret = MPP_ERR_MALLOC;
76 } else {
77 p->ctx = rc_ctx;
78 p->api = api;
79 p->frm_cnt = -1;
80 if (request_name && *request_name)
81 mpp_log("using rc impl %s\n", api->name);
82 ret = MPP_OK;
83 }
84 }
85
86 *ctx = p;
87 if (request_name)
88 *request_name = name;
89
90 rc_dbg_func("leave %p\n", p);
91
92 return ret;
93 }
94
rc_deinit(RcCtx ctx)95 MPP_RET rc_deinit(RcCtx ctx)
96 {
97 MppRcImpl *p = (MppRcImpl *)ctx;
98 const RcImplApi *api = p->api;
99 MPP_RET ret = MPP_OK;
100
101 rc_dbg_func("enter %p\n", ctx);
102
103 if (api && api->deinit && p->ctx) {
104 ret = api->deinit(p->ctx);
105 MPP_FREE(p->ctx);
106 }
107
108 MPP_FREE(p);
109
110 rc_dbg_func("leave %p\n", ctx);
111
112 return ret;
113 }
114
rc_update_usr_cfg(RcCtx ctx,RcCfg * cfg)115 MPP_RET rc_update_usr_cfg(RcCtx ctx, RcCfg *cfg)
116 {
117 MppRcImpl *p = (MppRcImpl *)ctx;
118 const RcImplApi *api = p->api;
119 MPP_RET ret = MPP_OK;
120
121 rc_dbg_func("enter %p\n", ctx);
122
123 p->cfg = *cfg;
124 p->fps = cfg->fps;
125
126 if (api && api->init && p->ctx)
127 api->init(p->ctx, &p->cfg);
128
129 rc_dbg_func("leave %p\n", ctx);
130
131 return ret;
132 }
133
rc_frm_check_drop(RcCtx ctx,EncRcTask * task)134 MPP_RET rc_frm_check_drop(RcCtx ctx, EncRcTask *task)
135 {
136 MppRcImpl *p = (MppRcImpl *)ctx;
137 const RcImplApi *api = p->api;
138 MPP_RET ret = MPP_OK;
139
140 rc_dbg_func("enter %p\n", ctx);
141
142 if (api && api->check_drop && p->ctx && task) {
143 ret = api->check_drop(p->ctx, task);
144 return ret;
145 } else {
146 RcFpsCfg *cfg = &p->fps;
147 RK_S32 frm_cnt = p->frm_cnt;
148 RK_S32 rate_in = cfg->fps_in_num * cfg->fps_out_denorm;
149 RK_S32 rate_out = cfg->fps_out_num * cfg->fps_in_denorm;
150 RK_S32 drop = 0;
151
152 mpp_assert(cfg->fps_in_denorm >= 1);
153 mpp_assert(cfg->fps_out_denorm >= 1);
154 mpp_assert(rate_in >= rate_out);
155
156 // frame counter is inited to (rate_in - rate_out) to encode first frame
157 if (frm_cnt < 0)
158 frm_cnt = rate_in - rate_out;
159
160 frm_cnt += rate_out;
161
162 if (frm_cnt < rate_in)
163 drop = 1;
164 else
165 frm_cnt -= rate_in;
166
167 p->frm_cnt = frm_cnt;
168 task->frm.drop = drop;
169 }
170
171 rc_dbg_func("leave %p drop %d\n", ctx, task->frm.drop);
172
173 return ret;
174 }
175
rc_frm_check_reenc(RcCtx ctx,EncRcTask * task)176 MPP_RET rc_frm_check_reenc(RcCtx ctx, EncRcTask *task)
177 {
178 MppRcImpl *p = (MppRcImpl *)ctx;
179 const RcImplApi *api = p->api;
180
181 if (!api || !api->check_reenc || !p->ctx || !task)
182 return MPP_OK;
183
184 return api->check_reenc(p->ctx, task);
185 }
186
rc_frm_start(RcCtx ctx,EncRcTask * task)187 MPP_RET rc_frm_start(RcCtx ctx, EncRcTask *task)
188 {
189 MppRcImpl *p = (MppRcImpl *)ctx;
190 const RcImplApi *api = p->api;
191
192 if (!api || !api->frm_start || !p->ctx || !task)
193 return MPP_OK;
194
195 return api->frm_start(p->ctx, task);
196 }
197
rc_frm_end(RcCtx ctx,EncRcTask * task)198 MPP_RET rc_frm_end(RcCtx ctx, EncRcTask *task)
199 {
200 MppRcImpl *p = (MppRcImpl *)ctx;
201 const RcImplApi *api = p->api;
202
203 if (!api || !api->frm_end || !p->ctx || !task)
204 return MPP_OK;
205
206 return api->frm_end(p->ctx, task);
207 }
208
rc_hal_start(RcCtx ctx,EncRcTask * task)209 MPP_RET rc_hal_start(RcCtx ctx, EncRcTask *task)
210 {
211 MppRcImpl *p = (MppRcImpl *)ctx;
212 const RcImplApi *api = p->api;
213
214 if (!api || !api->hal_start || !p->ctx || !task)
215 return MPP_OK;
216
217 return api->hal_start(p->ctx, task);
218 }
219
rc_hal_end(RcCtx ctx,EncRcTask * task)220 MPP_RET rc_hal_end(RcCtx ctx, EncRcTask *task)
221 {
222 MppRcImpl *p = (MppRcImpl *)ctx;
223 const RcImplApi *api = p->api;
224
225 if (!api || !api->hal_end || !p->ctx || !task)
226 return MPP_OK;
227
228 return api->hal_end(p->ctx, task);
229 }
230