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