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