xref: /rockchip-linux_mpp/mpp/codec/rc/rc.c (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
1 /* SPDX-License-Identifier: Apache-2.0 OR MIT */
2 /*
3  * Copyright (c) 2016 Rockchip Electronics Co., Ltd.
4  */
5 
6 #define MODULE_TAG "rc"
7 
8 #include <math.h>
9 #include <memory.h>
10 
11 #include "mpp_env.h"
12 #include "mpp_mem.h"
13 #include "mpp_list.h"
14 #include "mpp_common.h"
15 
16 #include "rc_debug.h"
17 #include "rc.h"
18 #include "rc_api.h"
19 #include "rc_base.h"
20 
21 typedef struct MppRcImpl_t {
22     void            *ctx;
23     const RcImplApi *api;
24     RcCfg           cfg;
25 
26     RcFpsCfg        fps;
27     RK_S32          frm_cnt;
28 
29     RK_U32          frm_send;
30     RK_U32          frm_done;
31 } MppRcImpl;
32 
33 RK_U32 rc_debug = 0;
34 
35 static const char default_rc_api[] = "default";
36 
rc_init(RcCtx * ctx,MppCodingType type,const char ** request_name)37 MPP_RET rc_init(RcCtx *ctx, MppCodingType type, const char **request_name)
38 {
39     MPP_RET ret = MPP_NOK;
40     MppRcImpl *p = NULL;
41     RcImplApi *api = NULL;
42     const char *name = NULL;
43 
44     mpp_env_get_u32("rc_debug", &rc_debug, 0);
45 
46     if (NULL == request_name || NULL == *request_name)
47         name = default_rc_api;
48     else
49         name = *request_name;
50 
51     rc_dbg_func("enter type %x name %s\n", type, name);
52 
53     api = rc_api_get(type, name);
54 
55     mpp_assert(api);
56 
57     if (api) {
58         void *rc_ctx = mpp_calloc_size(void, api->ctx_size);
59 
60         p = mpp_calloc(MppRcImpl, 1);
61         if (NULL == p || NULL == rc_ctx) {
62             mpp_err_f("failed to create context size %d\n", api->ctx_size);
63             MPP_FREE(p);
64             MPP_FREE(rc_ctx);
65             ret = MPP_ERR_MALLOC;
66         } else {
67             p->ctx = rc_ctx;
68             p->api = api;
69             p->frm_cnt = -1;
70             if (request_name && *request_name)
71                 mpp_log("using rc impl %s\n", api->name);
72             ret = MPP_OK;
73         }
74     }
75 
76     *ctx = p;
77     if (request_name)
78         *request_name = name;
79 
80     rc_dbg_func("leave %p\n", p);
81 
82     return ret;
83 }
84 
rc_deinit(RcCtx ctx)85 MPP_RET rc_deinit(RcCtx ctx)
86 {
87     MppRcImpl *p = (MppRcImpl *)ctx;
88     const RcImplApi *api = p->api;
89     MPP_RET ret = MPP_OK;
90 
91     rc_dbg_func("enter %p\n", ctx);
92 
93     if (api && api->deinit && p->ctx) {
94         ret = api->deinit(p->ctx);
95         MPP_FREE(p->ctx);
96     }
97 
98     MPP_FREE(p);
99 
100     rc_dbg_func("leave %p\n", ctx);
101 
102     return ret;
103 }
104 
rc_update_usr_cfg(RcCtx ctx,RcCfg * cfg)105 MPP_RET rc_update_usr_cfg(RcCtx ctx, RcCfg *cfg)
106 {
107     MppRcImpl *p = (MppRcImpl *)ctx;
108     const RcImplApi *api = p->api;
109     MPP_RET ret = MPP_OK;
110 
111     rc_dbg_func("enter %p\n", ctx);
112 
113     p->cfg = *cfg;
114     p->fps = cfg->fps;
115 
116     if (api && api->init && p->ctx)
117         api->init(p->ctx, &p->cfg);
118 
119     rc_dbg_func("leave %p\n", ctx);
120 
121     return ret;
122 }
123 
rc_frm_check_drop(RcCtx ctx,EncRcTask * task)124 MPP_RET rc_frm_check_drop(RcCtx ctx, EncRcTask *task)
125 {
126     MppRcImpl *p = (MppRcImpl *)ctx;
127     const RcImplApi *api = p->api;
128     MPP_RET ret = MPP_OK;
129 
130     rc_dbg_func("enter %p\n", ctx);
131 
132     if (api && api->check_drop && p->ctx && task) {
133         ret = api->check_drop(p->ctx, task);
134         return ret;
135     } else {
136         RcFpsCfg *cfg = &p->fps;
137         RK_S32 frm_cnt  = p->frm_cnt;
138         RK_S32 rate_in  = cfg->fps_in_num * cfg->fps_out_denom;
139         RK_S32 rate_out = cfg->fps_out_num * cfg->fps_in_denom;
140         RK_S32 drop = 0;
141 
142         mpp_assert(cfg->fps_in_denom >= 1);
143         mpp_assert(cfg->fps_out_denom >= 1);
144         mpp_assert(rate_in >= rate_out);
145 
146         // frame counter is inited to (rate_in - rate_out)  to encode first frame
147         if (frm_cnt < 0)
148             frm_cnt = rate_in - rate_out;
149 
150         frm_cnt += rate_out;
151 
152         if (frm_cnt < rate_in)
153             drop = 1;
154         else
155             frm_cnt -= rate_in;
156 
157         p->frm_cnt = frm_cnt;
158         task->frm.drop = drop;
159     }
160 
161     rc_dbg_func("leave %p drop %d\n", ctx, task->frm.drop);
162 
163     return ret;
164 }
165 
166 #define MPP_ENC_RC_FUNC(flow, func) \
167     MPP_RET rc_##flow##_##func(RcCtx ctx, EncRcTask *task)      \
168     {                                                           \
169         MppRcImpl *p = (MppRcImpl *)ctx;                        \
170         const RcImplApi *api = p->api;                          \
171         if (!api || !api->flow##_##func || !p->ctx || !task)    \
172             return MPP_OK;                                      \
173         return api->flow##_##func(p->ctx, task);                \
174     }
175 
176 MPP_ENC_RC_FUNC(check, reenc)
177 MPP_ENC_RC_FUNC(frm, start)
178 MPP_ENC_RC_FUNC(frm, end)
179 MPP_ENC_RC_FUNC(hal, start)
180 MPP_ENC_RC_FUNC(hal, end)
181