xref: /rockchip-linux_mpp/mpp/legacy/vpu_api.cpp (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
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 "vpu_api"
18 
19 #include <string.h>
20 #include <dlfcn.h>
21 #include <unistd.h>
22 
23 #include "mpp_mem.h"
24 #include "mpp_env.h"
25 #include "mpp_debug.h"
26 #include "mpp_common.h"
27 #include "mpp_soc.h"
28 
29 #include "vpu_api.h"
30 #include "vpu_api_legacy.h"
31 #include "vpu_mem_legacy.h"
32 
33 static RK_S32
vpu_api_init(VpuCodecContext * ctx,RK_U8 * extraData,RK_U32 extra_size)34 vpu_api_init(VpuCodecContext *ctx, RK_U8 *extraData, RK_U32 extra_size)
35 {
36     vpu_api_dbg_func("vpu_api_init in, extra_size: %d", extra_size);
37 
38     if (ctx == NULL) {
39         mpp_log("vpu_api_init fail, input invalid");
40         return VPU_API_ERR_UNKNOW;
41     }
42     VpuApiLegacy* api = (VpuApiLegacy*)(ctx->vpuApiObj);
43     if (api == NULL) {
44         mpp_log("vpu_api_init fail, vpu api invalid");
45         return VPU_API_ERR_UNKNOW;
46     }
47 
48     return api->init(ctx, extraData, extra_size);
49 }
50 
51 static RK_S32
vpu_api_decode(VpuCodecContext * ctx,VideoPacket_t * pkt,DecoderOut_t * aDecOut)52 vpu_api_decode(VpuCodecContext *ctx, VideoPacket_t *pkt, DecoderOut_t *aDecOut)
53 {
54     if (ctx == NULL) {
55         mpp_log("vpu_api_decode fail, input invalid");
56         return VPU_API_ERR_UNKNOW;
57     }
58 
59     VpuApiLegacy* api = (VpuApiLegacy*)(ctx->vpuApiObj);
60     if (api == NULL) {
61         mpp_log("vpu_api_decode fail, vpu api invalid");
62         return VPU_API_ERR_UNKNOW;
63     }
64 
65     return api->decode(ctx, pkt, aDecOut);
66 }
vpu_api_sendstream(VpuCodecContext * ctx,VideoPacket_t * pkt)67 static RK_S32 vpu_api_sendstream(VpuCodecContext *ctx, VideoPacket_t *pkt)
68 {
69     if (ctx == NULL) {
70         mpp_log("vpu_api_decode fail, input invalid");
71         return VPU_API_ERR_UNKNOW;
72     }
73 
74     VpuApiLegacy* api = (VpuApiLegacy*)(ctx->vpuApiObj);
75     if (api == NULL) {
76         mpp_log("vpu_api_sendstream fail, vpu api invalid");
77         return VPU_API_ERR_UNKNOW;
78     }
79 
80     return api->decode_sendstream(pkt);
81 }
82 
vpu_api_getframe(VpuCodecContext * ctx,DecoderOut_t * aDecOut)83 static RK_S32 vpu_api_getframe(VpuCodecContext *ctx, DecoderOut_t *aDecOut)
84 {
85     if (ctx == NULL) {
86         mpp_log("vpu_api_decode fail, input invalid");
87         return VPU_API_ERR_UNKNOW;
88     }
89 
90     VpuApiLegacy* api = (VpuApiLegacy*)(ctx->vpuApiObj);
91     if (api == NULL) {
92         mpp_log("vpu_api_getframe fail, vpu api invalid");
93         return VPU_API_ERR_UNKNOW;
94     }
95 
96     return api->decode_getoutframe(ctx, aDecOut);
97 }
98 
99 static RK_S32
vpu_api_sendframe(VpuCodecContext * ctx,EncInputStream_t * aEncInStrm)100 vpu_api_sendframe(VpuCodecContext *ctx, EncInputStream_t *aEncInStrm)
101 {
102     if (ctx == NULL) {
103         mpp_log("vpu_api_decode fail, input invalid");
104         return VPU_API_ERR_UNKNOW;
105     }
106 
107     VpuApiLegacy* api = (VpuApiLegacy*)(ctx->vpuApiObj);
108     if (api == NULL) {
109         mpp_log("vpu_api_sendframe fail, vpu api invalid");
110         return VPU_API_ERR_UNKNOW;
111     }
112 
113     return api->encoder_sendframe(ctx, aEncInStrm);
114 }
115 
vpu_api_getstream(VpuCodecContext * ctx,EncoderOut_t * aEncOut)116 static RK_S32 vpu_api_getstream(VpuCodecContext *ctx, EncoderOut_t *aEncOut)
117 {
118     if (ctx == NULL) {
119         mpp_log("vpu_api_decode fail, input invalid");
120         return VPU_API_ERR_UNKNOW;
121     }
122 
123     VpuApiLegacy* api = (VpuApiLegacy*)(ctx->vpuApiObj);
124     if (api == NULL) {
125         mpp_log("vpu_api_getframe fail, vpu api invalid");
126         return VPU_API_ERR_UNKNOW;
127     }
128 
129     return api->encoder_getstream(ctx, aEncOut);
130 }
131 
132 static RK_S32
vpu_api_encode(VpuCodecContext * ctx,EncInputStream_t * aEncInStrm,EncoderOut_t * aEncOut)133 vpu_api_encode(VpuCodecContext *ctx, EncInputStream_t *aEncInStrm,
134                EncoderOut_t *aEncOut)
135 {
136     if (ctx == NULL) {
137         mpp_log("vpu_api_encode fail, input invalid");
138         return VPU_API_ERR_UNKNOW;
139     }
140 
141     VpuApiLegacy* api = (VpuApiLegacy*)(ctx->vpuApiObj);
142     if (api == NULL) {
143         mpp_log("vpu_api_encode fail, vpu api invalid");
144         return VPU_API_ERR_UNKNOW;
145     }
146 
147     return api->encode(ctx, aEncInStrm, aEncOut);
148 }
149 
vpu_api_flush(VpuCodecContext * ctx)150 static RK_S32 vpu_api_flush(VpuCodecContext *ctx)
151 {
152 
153     if (ctx == NULL) {
154         mpp_log("vpu_api_encode fail, input invalid");
155         return VPU_API_ERR_UNKNOW;
156     }
157 
158     VpuApiLegacy* api = (VpuApiLegacy*)(ctx->vpuApiObj);
159     if (api == NULL) {
160         mpp_log("vpu_api_flush fail, vpu api invalid");
161         return VPU_API_ERR_UNKNOW;
162     }
163 
164     return api->flush(ctx);
165 }
166 
167 static RK_S32
vpu_api_control(VpuCodecContext * ctx,VPU_API_CMD cmdType,void * param)168 vpu_api_control(VpuCodecContext *ctx, VPU_API_CMD cmdType, void *param)
169 {
170     if (ctx == NULL) {
171         mpp_log("vpu_api_decode fail, input invalid");
172         return VPU_API_ERR_UNKNOW;
173     }
174 
175     VpuApiLegacy* api = (VpuApiLegacy*)(ctx->vpuApiObj);
176     if (api == NULL) {
177         mpp_log("vpu_api_decode fail, vpu api invalid");
178         return VPU_API_ERR_UNKNOW;
179     }
180 
181     vpu_api_dbg_func("enter\n");
182     switch (cmdType) {
183     case VPU_API_SET_VPUMEM_CONTEXT: {
184         vpu_display_mem_pool_impl *p_mempool =
185             (vpu_display_mem_pool_impl *)param;
186 
187         param = (void*)p_mempool->group;
188         break;
189     }
190     default: {
191         break;
192     }
193     }
194 
195     vpu_api_dbg_func("pass to mpi\n");
196     return api->control(ctx, cmdType, param);
197 }
198 
199 static const char *codec_paths[] = {
200     "/vendor/lib/librk_vpuapi.so",
201     "/system/lib/librk_vpuapi.so",
202     "/system/lib/librk_on2.so",
203     "/usr/lib/librk_codec.so",
204 };
205 
206 class VpulibDlsym
207 {
208 public:
209     void *rkapi_hdl;
210     RK_S32 (*rkvpu_open_cxt)(VpuCodecContext **ctx);
211     RK_S32 (*rkvpu_close_cxt)(VpuCodecContext **ctx);
VpulibDlsym()212     VpulibDlsym() :
213         rkapi_hdl(NULL),
214         rkvpu_open_cxt(NULL),
215         rkvpu_close_cxt(NULL) {
216         RK_U32 i;
217 
218         for (i = 0; i < MPP_ARRAY_ELEMS(codec_paths); i++) {
219             rkapi_hdl = dlopen(codec_paths[i], RTLD_LAZY | RTLD_GLOBAL);
220             if (rkapi_hdl)
221                 break;
222         }
223 
224         if (rkapi_hdl) {
225             rkvpu_open_cxt  = (RK_S32 (*)(VpuCodecContext **ctx))
226                               dlsym(rkapi_hdl, "vpu_open_context");
227             rkvpu_close_cxt = (RK_S32 (*)(VpuCodecContext **ctx))
228                               dlsym(rkapi_hdl, "vpu_close_context");
229             mpp_log("dlopen vpu lib %s success\n", codec_paths[i]);
230         }
231     }
232 
~VpulibDlsym()233     ~VpulibDlsym() {
234         if (rkapi_hdl) {
235             dlclose(rkapi_hdl);
236             rkapi_hdl = NULL;
237         }
238     }
239 };
240 
241 static VpulibDlsym gVpulib;
242 
check_orign_vpu()243 static RK_S32 check_orign_vpu()
244 {
245     return (gVpulib.rkapi_hdl) ? (MPP_OK) : (MPP_NOK);
246 }
247 
open_orign_vpu(VpuCodecContext ** ctx)248 static RK_S32 open_orign_vpu(VpuCodecContext **ctx)
249 {
250     if (gVpulib.rkvpu_open_cxt && ctx) {
251         return (gVpulib.rkvpu_open_cxt)(ctx);
252     }
253     return MPP_NOK;
254 }
255 
close_orign_vpu(VpuCodecContext ** ctx)256 static RK_S32 close_orign_vpu(VpuCodecContext **ctx)
257 {
258     if (gVpulib.rkvpu_close_cxt && ctx) {
259         return (gVpulib.rkvpu_close_cxt)(ctx);
260     }
261     return MPP_NOK;
262 }
263 
264 /*
265  * old libvpu path will input a NULL pointer in *ctx
266  * new libvpu path will input non-NULL pointer in *ctx
267  */
vpu_open_context(VpuCodecContext ** ctx)268 RK_S32 vpu_open_context(VpuCodecContext **ctx)
269 {
270     VpuCodecContext *s = *ctx;
271     RK_S32 ret = -1;
272     RK_U32 force_original = 0;
273     RK_U32 force_mpp_mode = 0;
274     RK_U32 use_mpp = 0;
275 
276     CODEC_TYPE codecType = CODEC_NONE;
277     OMX_RK_VIDEO_CODINGTYPE videoCoding = OMX_RK_VIDEO_CodingUnused;
278     RK_U32 width = 0;
279     RK_U32 height = 0;
280     void  *extradata = NULL;
281     RK_S32 extradata_size = 0;
282     EXtraCfg_t extra_cfg;
283     memset(&extra_cfg, 0, sizeof(EXtraCfg_t));
284 
285     mpp_env_get_u32("vpu_api_debug", &vpu_api_debug, 0);
286     vpu_api_dbg_func("enter\n");
287 
288     mpp_env_get_u32("use_original", &force_original, 0);
289     mpp_env_get_u32("use_mpp_mode", &force_mpp_mode, 0);
290 
291     /* if there is no original vpuapi library force to mpp path */
292     if (check_orign_vpu())
293         force_mpp_mode = 1;
294 
295     if (force_original) {
296         /* force mpp mode here */
297         use_mpp = 0;
298     } else if (force_mpp_mode) {
299         /* force mpp mode here */
300         use_mpp = 1;
301     } else if (!access("/dev/mpp_service", F_OK)) {
302         /* if mpp_service exist, force mpp mode */
303         use_mpp = 1;
304     } else if (!!access("/dev/rkvdec", F_OK)) {
305         /* if there is no rkvdec it means the platform must be vpu1 */
306         if (s && s->videoCoding == OMX_RK_VIDEO_CodingHEVC &&
307             (!access("/dev/hevc-service", F_OK)
308              || !access("/dev/hevc_service", F_OK))) {
309             /* if this is a hevc request and exist hevc_service for decoding use mpp */
310             use_mpp = 1;
311         } else {
312             /* otherwise use original vpuapi path */
313             use_mpp = 0;
314         }
315     } else if (NULL == s) {
316         /* caller is original vpuapi path. Force use original vpuapi path */
317         use_mpp = 0;
318     } else {
319         if (s->videoCoding == OMX_RK_VIDEO_CodingAVC
320             && s->codecType == CODEC_DECODER && s->width <= 1920
321             && s->height <= 1088 && !s->extra_cfg.mpp_mode
322             && mpp_get_soc_type() != ROCKCHIP_SOC_RK3399) {
323             /* H.264 smaller than 1080p use original vpuapi library for better error process */
324             // NOTE: rk3399 need better performance
325             use_mpp = 0;
326         } else {
327             MppCtxType type = (s->codecType == CODEC_DECODER) ? (MPP_CTX_DEC) :
328                               (s->codecType == CODEC_ENCODER)
329                               ? (MPP_CTX_ENC) : (MPP_CTX_BUTT);
330             MppCodingType coding = (MppCodingType)s->videoCoding;
331 
332             if (MPP_OK == mpp_check_support_format(type, coding)) {
333                 /* If current mpp can support this format use mpp */
334                 use_mpp = 1;
335             } else {
336                 /* unsupport format use vpuapi library */
337                 use_mpp = 0;
338             }
339         }
340     }
341 
342     /*
343      * No matter what is the old context just release it.
344      * But we need to save to pre-configured parameter
345      */
346     if (s) {
347         codecType       = s->codecType;
348         videoCoding     = s->videoCoding;
349         width           = s->width;
350         height          = s->height;
351         extradata       = s->extradata;
352         extradata_size  = s->extradata_size;
353         extra_cfg       = s->extra_cfg;
354 
355         free(s);
356         s = NULL;
357     }
358 
359     if (!use_mpp) {
360         vpu_api_dbg_func("use vpuapi path\n");
361 
362         ret = open_orign_vpu(&s);
363         if (!ret && s) {
364             // for safety
365             s->extra_cfg.ori_vpu = 1;
366             extra_cfg.ori_vpu = 1;
367         }
368     } else {
369         vpu_api_dbg_func("use mpp path\n");
370 
371         s = mpp_calloc(VpuCodecContext, 1);
372         if (s) {
373             s->enableparsing = 1;
374 
375             VpuApiLegacy* api = new VpuApiLegacy();
376 
377             if (api) {
378                 s->vpuApiObj = (void*)api;
379                 s->init = vpu_api_init;
380                 s->decode = vpu_api_decode;
381                 s->encode = vpu_api_encode;
382                 s->flush = vpu_api_flush;
383                 s->control = vpu_api_control;
384                 s->decode_sendstream = vpu_api_sendstream;
385                 s->decode_getframe = vpu_api_getframe;
386                 s->encoder_sendframe = vpu_api_sendframe;
387                 s->encoder_getstream = vpu_api_getstream;
388 
389                 s->extra_cfg.ori_vpu = 0;
390                 extra_cfg.ori_vpu = 0;
391 
392                 ret = 0;
393             } else {
394                 mpp_err("Vpu api object has not been properly allocated");
395                 mpp_free(s);
396                 s = NULL;
397             }
398         } else {
399             mpp_err("Input context has not been properly allocated");
400         }
401     }
402 
403     if (s) {
404         s->codecType        = codecType;
405         s->videoCoding      = videoCoding;
406         s->width            = width;
407         s->height           = height;
408         s->extradata        = extradata;
409         s->extradata_size   = extradata_size;
410         s->extra_cfg        = extra_cfg;
411     }
412     *ctx = s;
413 
414     vpu_api_dbg_func("leave\n");
415     return ret;
416 }
417 
vpu_close_context(VpuCodecContext ** ctx)418 RK_S32 vpu_close_context(VpuCodecContext **ctx)
419 {
420     vpu_api_dbg_func("enter\n");
421     VpuCodecContext *s = *ctx;
422     RK_S32 ret = -1;
423     RK_U32 force_original = 0;
424 
425     mpp_env_get_u32("force_original", &force_original, 0);
426 
427     if (s) {
428         if (s->extra_cfg.ori_vpu) {
429             ret = close_orign_vpu(ctx);
430             mpp_log("org vpu_close_context ok");
431         } else {
432             if (s->flush)
433                 s->flush(s);
434 
435             VpuApiLegacy* api = (VpuApiLegacy*)(s->vpuApiObj);
436             if (s->vpuApiObj) {
437                 delete api;
438                 s->vpuApiObj = NULL;
439             }
440 
441             if (s->extradata_size > 0) {
442                 s->extradata_size = 0;
443                 s->extradata = NULL;
444             }
445 
446             if (s->private_data)
447                 mpp_free(s->private_data);
448 
449             mpp_free(s);
450             ret = 0;
451         }
452 
453         *ctx = s = NULL;
454     }
455 
456     vpu_api_dbg_func("leave\n");
457 
458     return ret;
459 }
460