1 /*
2 * Copyright (c) 2022 Shenzhen Kaihong DID Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "hdi_mpp.h"
17 #include <dlfcn.h>
18 #include <securec.h>
19 #include <hdf_base.h>
20 #include <hdf_log.h>
21 #include "hdi_mpp_config.h"
22 #include "im2d.h"
23 #include "rga.h"
24 #include "rk_vdec_cfg.h"
25
26 #define HDF_LOG_TAG codec_hdi_mpp
27 #define BITWISE_LEFT_SHIFT_WITH_ONE (1 << 20)
28 #define SLEEP_INTERVAL_MICROSECONDS 1000
29 #define BUFFER_GROUP_LIMIT_NUM 24
30 #define DFAULT_ENC_FPS_NUM 24
31 #define DFAULT_ENC_DROP_THD 20
32 #define DFAULT_ENC_GOP_OPERATOR 2
33
34 RKHdiBaseComponent *g_pBaseComponent = NULL;
35
InitComponentSetup(RKHdiEncodeSetup * setup)36 void InitComponentSetup(RKHdiEncodeSetup *setup)
37 {
38 setup->fmt = PIXEL_FORMAT_NONE;
39
40 setup->fps.fpsInNum = DFAULT_ENC_FPS_NUM;
41 setup->fps.fpsInDen = 1;
42 setup->fps.fpsOutNum = DFAULT_ENC_FPS_NUM;
43 setup->fps.fpsOutDen = 1;
44
45 setup->drop.dropMode = MPP_ENC_RC_DROP_FRM_DISABLED;
46 setup->drop.dropThd = DFAULT_ENC_DROP_THD;
47 setup->drop.dropGap = 1;
48
49 setup->rc.rcMode = MPP_ENC_RC_MODE_BUTT;
50
51 setup->gop.gopMode = VID_CODEC_GOPMODE_NORMALP;
52 setup->gop.gopLen = 0;
53 setup->gop.viLen = 0;
54 setup->gop.gop = setup->fps.fpsOutNum * DFAULT_ENC_GOP_OPERATOR;
55 }
56
CodecInit(void)57 int32_t CodecInit(void)
58 {
59 g_pBaseComponent = (RKHdiBaseComponent *)malloc(sizeof(RKHdiBaseComponent));
60 if (g_pBaseComponent == NULL) {
61 HDF_LOGE("%{public}s: malloc failed!", __func__);
62 return HDF_FAILURE;
63 }
64 int32_t ret = memset_s(g_pBaseComponent, sizeof(RKHdiBaseComponent), 0, sizeof(RKHdiBaseComponent));
65 if (ret != EOK) {
66 HDF_LOGE("%{public}s: memset failed, error code: %{public}d", __func__, ret);
67 }
68 InitComponentSetup(&g_pBaseComponent->setup);
69
70 ret = GetMppApi(&g_pBaseComponent->mppApi);
71 if ((ret != HDF_SUCCESS) || (g_pBaseComponent->mppApi == NULL)) {
72 HDF_LOGE("%{public}s: GetMppAPI failed!", __func__);
73 ReleaseMppApi(g_pBaseComponent->mppApi);
74 g_pBaseComponent->mppApi = NULL;
75 free(g_pBaseComponent);
76 g_pBaseComponent = NULL;
77 return HDF_FAILURE;
78 }
79
80 g_pBaseComponent->ctxType = MPP_CTX_BUTT;
81 g_pBaseComponent->codingType = MPP_VIDEO_CodingMax;
82 g_pBaseComponent->frameNum = 0;
83 ret = g_pBaseComponent->mppApi->HdiMppEncCfgInit(&g_pBaseComponent->cfg);
84 if (ret != 0) {
85 HDF_LOGE("%{public}s: config mpp cfg init failed!", __func__);
86 ReleaseMppApi(g_pBaseComponent->mppApi);
87 g_pBaseComponent->mppApi = NULL;
88 free(g_pBaseComponent);
89 g_pBaseComponent = NULL;
90 return HDF_FAILURE;
91 }
92 return HDF_SUCCESS;
93 }
94
CodecDeinit(void)95 int32_t CodecDeinit(void)
96 {
97 ReleaseMppApi(g_pBaseComponent->mppApi);
98 g_pBaseComponent->mppApi = NULL;
99 if (g_pBaseComponent != NULL) {
100 free(g_pBaseComponent);
101 g_pBaseComponent = NULL;
102 }
103 return HDF_SUCCESS;
104 }
105
CodecSetCallback(CODEC_HANDLETYPE handle,CodecCallback * cb,UINTPTR instance)106 int32_t CodecSetCallback(CODEC_HANDLETYPE handle, CodecCallback *cb, UINTPTR instance)
107 {
108 if (cb == NULL) {
109 HDF_LOGE("%{public}s: call back is NULL", __func__);
110 return HDF_FAILURE;
111 }
112
113 g_pBaseComponent->pCallbacks = cb;
114
115 return HDF_SUCCESS;
116 }
117
GetMppCtxType(const char * name)118 MppCtxType GetMppCtxType(const char* name)
119 {
120 char *pos = strstr(name, "decoder");
121 if (pos != NULL) {
122 return MPP_CTX_DEC;
123 }
124
125 pos = strstr(name, "encoder");
126 if (pos != NULL) {
127 return MPP_CTX_ENC;
128 }
129
130 HDF_LOGE("%{public}s: CtxType undefined!", __func__);
131 return MPP_CTX_BUTT;
132 }
133
GetMppCodingType(const char * name)134 MppCodingType GetMppCodingType(const char* name)
135 {
136 char *pos = strstr(name, "avc");
137 if (pos != NULL) {
138 return MPP_VIDEO_CodingAVC;
139 }
140
141 pos = strstr(name, "hevc");
142 if (pos != NULL) {
143 return MPP_VIDEO_CodingHEVC;
144 }
145
146 pos = strstr(name, "mpeg4");
147 if (pos != NULL) {
148 return MPP_VIDEO_CodingMPEG4;
149 }
150
151 pos = strstr(name, "mpeg2");
152 if (pos != NULL) {
153 return MPP_VIDEO_CodingMPEG2;
154 }
155
156 HDF_LOGE("%{public}s: CodingType unsupported!", __func__);
157 return MPP_VIDEO_CodingMax;
158 }
159
CodecCreate(const char * name,CODEC_HANDLETYPE * handle)160 int32_t CodecCreate(const char* name, CODEC_HANDLETYPE *handle)
161 {
162 MPP_RET ret = MPP_OK;
163 MppCtx ctx = NULL;
164 RKMppApi *mppApi = g_pBaseComponent->mppApi;
165 if (name == NULL || mppApi == NULL || handle == NULL) {
166 return HDF_FAILURE;
167 }
168
169 MppCtxType ctxType = GetMppCtxType(name);
170 if (ctxType == MPP_CTX_BUTT) {
171 return HDF_ERR_NOT_SUPPORT;
172 }
173 g_pBaseComponent->ctxType = ctxType;
174 MppCodingType codingType = GetMppCodingType(name);
175 if (codingType == MPP_VIDEO_CodingMax) {
176 return HDF_ERR_NOT_SUPPORT;
177 }
178 g_pBaseComponent->codingType = codingType;
179
180 ret = mppApi->HdiMppCreate(&ctx, &(g_pBaseComponent->mpi));
181 if (ret != MPP_OK) {
182 HDF_LOGE("%{public}s: mpp create failed", __func__);
183 return HDF_FAILURE;
184 }
185 *handle = ctx;
186 g_pBaseComponent->ctx = ctx;
187 g_pBaseComponent->componentName = name;
188 if (g_pBaseComponent->ctxType == MPP_CTX_ENC) {
189 MppPollType timeout = MPP_POLL_BLOCK;
190 ret = g_pBaseComponent->mpi->control(ctx, MPP_SET_OUTPUT_TIMEOUT, &timeout);
191 if (ret != MPP_OK) {
192 HDF_LOGE("%{public}s: mpi control set output timeout failed ret %{public}d", __func__, ret);
193 return HDF_FAILURE;
194 }
195 }
196
197 ret = mppApi->HdiMppInit(ctx, ctxType, codingType);
198 if (ret != MPP_OK) {
199 HDF_LOGE("%{public}s: mpp init failed", __func__);
200 return HDF_FAILURE;
201 }
202
203 return HDF_SUCCESS;
204 }
205
CodecDestroy(CODEC_HANDLETYPE handle)206 int32_t CodecDestroy(CODEC_HANDLETYPE handle)
207 {
208 MPP_RET ret = MPP_OK;
209 MppCtx ctx = handle;
210 RKMppApi *mppApi = g_pBaseComponent->mppApi;
211
212 if (g_pBaseComponent == NULL) {
213 HDF_LOGE("%{public}s: g_pBaseComponent is NULL", __func__);
214 return HDF_FAILURE;
215 }
216
217 if (g_pBaseComponent->cfg != NULL) {
218 mppApi->HdiMppDecCfgDeinit(g_pBaseComponent->cfg);
219 g_pBaseComponent->cfg = NULL;
220 }
221
222 if (g_pBaseComponent->packet != NULL) {
223 mppApi->HdiMppPacketDeinit(&g_pBaseComponent->packet);
224 g_pBaseComponent->packet = NULL;
225 }
226
227 if (g_pBaseComponent->frame != NULL) {
228 mppApi->HdiMppFrameDeinit(&g_pBaseComponent->frame);
229 g_pBaseComponent->frame = NULL;
230 }
231
232 if (g_pBaseComponent->frmBuf != NULL) {
233 mppApi->HdiMppBufferPutWithCaller(g_pBaseComponent->frmBuf, __func__);
234 g_pBaseComponent->frmBuf = NULL;
235 }
236
237 if (g_pBaseComponent->pktBuf != NULL) {
238 mppApi->HdiMppBufferPutWithCaller(g_pBaseComponent->pktBuf, __func__);
239 g_pBaseComponent->pktBuf = NULL;
240 }
241
242 if (g_pBaseComponent->frmGrp != NULL) {
243 mppApi->HdiMppBufferGroupPut(g_pBaseComponent->frmGrp);
244 g_pBaseComponent->frmGrp = NULL;
245 }
246
247 ret = mppApi->HdiMppDestroy(ctx);
248 if (ret != MPP_OK) {
249 HDF_LOGE("%{public}s: mpp destroy failed", __func__);
250 return HDF_FAILURE;
251 }
252
253 if (g_pBaseComponent->ctxType == MPP_CTX_DEC) {
254 HDF_LOGI("%{public}s: dec frame count : %{public}d, error count : %{public}d", __func__,
255 g_pBaseComponent->frameCount, g_pBaseComponent->frameErr);
256 HDF_LOGI("%{public}s: dec max memory %{public}.2f MB", __func__,
257 g_pBaseComponent->maxUsage / (float)BITWISE_LEFT_SHIFT_WITH_ONE);
258 } else if (g_pBaseComponent->ctxType == MPP_CTX_ENC) {
259 HDF_LOGI("%{public}s: enc frame count : %{public}d", __func__, g_pBaseComponent->frameCount);
260 } else {
261 HDF_LOGE("%{public}s: CtxType undefined!", __func__);
262 return HDF_FAILURE;
263 }
264 return HDF_SUCCESS;
265 }
266
SetExtMppParam(Param * param)267 int32_t SetExtMppParam(Param *param)
268 {
269 int32_t ret = HDF_SUCCESS;
270 int32_t paramKey = param->key;
271
272 switch (paramKey) {
273 case KEY_EXT_SPLIT_PARSE_RK:
274 ret = SetParamSplitParse(g_pBaseComponent, param);
275 if (ret != HDF_SUCCESS) {
276 HDF_LOGE("%{public}s: config set split parse failed", __func__);
277 }
278 break;
279 case KEY_EXT_DEC_FRAME_NUM_RK:
280 case KEY_EXT_ENC_FRAME_NUM_RK:
281 ret = SetParamCodecFrameNum(g_pBaseComponent, param);
282 if (ret != HDF_SUCCESS) {
283 HDF_LOGE("%{public}s: config set frame number failed", __func__);
284 }
285 break;
286 case KEY_EXT_SETUP_DROP_MODE_RK:
287 ret = SetParamDrop(g_pBaseComponent, param);
288 break;
289 case KEY_EXT_ENC_VALIDATE_SETUP_RK:
290 ret = ValidateEncSetup(g_pBaseComponent, param);
291 if (ret != HDF_SUCCESS) {
292 HDF_LOGE("%{public}s: config validata setup failed", __func__);
293 }
294 break;
295 case KEY_EXT_ENC_SETUP_AVC_RK:
296 ret = SetParamEncSetupAVC(g_pBaseComponent, param);
297 break;
298 default:
299 HDF_LOGE("%{public}s: param key unsupport, key:%{public}d", __func__, paramKey);
300 return HDF_FAILURE;
301 }
302 return ret;
303 }
304
SetMppParam(Param * param)305 int32_t SetMppParam(Param *param)
306 {
307 int32_t ret = HDF_SUCCESS;
308 int32_t paramKey = param->key;
309
310 switch (paramKey) {
311 case KEY_VIDEO_WIDTH:
312 ret = SetParamWidth(g_pBaseComponent, param);
313 break;
314 case KEY_VIDEO_HEIGHT:
315 ret = SetParamHeight(g_pBaseComponent, param);
316 break;
317 case KEY_PIXEL_FORMAT:
318 ret = SetParamPixleFmt(g_pBaseComponent, param);
319 break;
320 case KEY_VIDEO_STRIDE:
321 ret = SetParamStride(g_pBaseComponent, param);
322 break;
323 case KEY_VIDEO_FRAME_RATE:
324 ret = SetParamFps(g_pBaseComponent, param);
325 break;
326 case KEY_VIDEO_RC_MODE:
327 ret = SetParamRateControl(g_pBaseComponent, param);
328 break;
329 case KEY_VIDEO_GOP_MODE:
330 ret = SetParamGop(g_pBaseComponent, param);
331 break;
332 case KEY_MIMETYPE:
333 ret = SetParamMimeCodecType(g_pBaseComponent, param);
334 break;
335 case KEY_CODEC_TYPE:
336 ret = SetParamCodecType(g_pBaseComponent, param);
337 break;
338 default:
339 ret = SetExtMppParam(param);
340 }
341 return ret;
342 }
343
CodecSetParameter(CODEC_HANDLETYPE handle,Param * params,int32_t paramCnt)344 int32_t CodecSetParameter(CODEC_HANDLETYPE handle, Param *params, int32_t paramCnt)
345 {
346 MppCtx ctx = handle;
347 int32_t ret = HDF_SUCCESS;
348 if (ctx != g_pBaseComponent->ctx) {
349 HDF_LOGE("%{public}s: ctx not match %{public}d", __func__, ctx);
350 return HDF_FAILURE;
351 }
352
353 for (int32_t i = 0; i < paramCnt; i++) {
354 ret = SetMppParam(params + i);
355 if (ret != HDF_SUCCESS) {
356 HDF_LOGE("%{public}s: SetMppParam faild, param key:%{public}d", __func__, params[i].key);
357 return ret;
358 }
359 }
360
361 return HDF_SUCCESS;
362 }
363
GetExtMppParam(Param * param)364 int32_t GetExtMppParam(Param *param)
365 {
366 int32_t ret = HDF_SUCCESS;
367 int32_t paramKey = param->key;
368
369 switch (paramKey) {
370 case KEY_EXT_DEFAULT_CFG_RK:
371 ret = GetDefaultConfig(g_pBaseComponent);
372 if (ret != 0) {
373 HDF_LOGE("%{public}s: config get default config failed", __func__);
374 }
375 break;
376 case KEY_EXT_SPLIT_PARSE_RK:
377 ret = GetParamSplitParse(g_pBaseComponent, param);
378 if (ret != HDF_SUCCESS) {
379 HDF_LOGE("%{public}s: config set split parse failed", __func__);
380 }
381 break;
382 case KEY_EXT_DEC_FRAME_NUM_RK:
383 case KEY_EXT_ENC_FRAME_NUM_RK:
384 ret = GetParamCodecFrameNum(g_pBaseComponent, param);
385 if (ret != HDF_SUCCESS) {
386 HDF_LOGE("%{public}s: config set frame number failed", __func__);
387 }
388 break;
389 case KEY_EXT_SETUP_DROP_MODE_RK:
390 ret = GetParamDrop(g_pBaseComponent, param);
391 break;
392 default:
393 HDF_LOGE("%{public}s: param key unsupport, key:%{public}d", __func__, paramKey);
394 return HDF_FAILURE;
395 }
396 return ret;
397 }
398
GetMppParam(Param * param)399 int32_t GetMppParam(Param *param)
400 {
401 int32_t ret = HDF_SUCCESS;
402 int32_t paramKey = param->key;
403
404 switch (paramKey) {
405 case KEY_BUFFERSIZE:
406 ret = GetParamBufferSize(g_pBaseComponent, param);
407 break;
408 case KEY_VIDEO_WIDTH:
409 ret = GetParamWidth(g_pBaseComponent, param);
410 break;
411 case KEY_VIDEO_HEIGHT:
412 ret = GetParamHeight(g_pBaseComponent, param);
413 break;
414 case KEY_PIXEL_FORMAT:
415 ret = GetParamPixleFmt(g_pBaseComponent, param);
416 break;
417 case KEY_VIDEO_STRIDE:
418 ret = GetParamStride(g_pBaseComponent, param);
419 break;
420 case KEY_VIDEO_FRAME_RATE:
421 ret = GetParamFps(g_pBaseComponent, param);
422 break;
423 case KEY_VIDEO_RC_MODE:
424 ret = GetParamRateControl(g_pBaseComponent, param);
425 break;
426 case KEY_VIDEO_GOP_MODE:
427 ret = GetParamGop(g_pBaseComponent, param);
428 break;
429 case KEY_MIMETYPE:
430 ret = GetParamMimeCodecType(g_pBaseComponent, param);
431 break;
432 case KEY_CODEC_TYPE:
433 ret = GetParamCodecType(g_pBaseComponent, param);
434 break;
435 default:
436 ret = GetExtMppParam(param);
437 }
438 return ret;
439 }
440
CodecGetParameter(CODEC_HANDLETYPE handle,Param * params,int32_t paramCnt)441 int32_t CodecGetParameter(CODEC_HANDLETYPE handle, Param *params, int32_t paramCnt)
442 {
443 int32_t ret = HDF_SUCCESS;
444 MppCtx ctx = handle;
445 if (ctx != g_pBaseComponent->ctx) {
446 HDF_LOGE("%{public}s: ctx not match %{public}d", __func__, ctx);
447 return HDF_FAILURE;
448 }
449
450 for (int32_t i = 0; i < paramCnt; i++) {
451 ret = GetMppParam(params + i);
452 if (ret != HDF_SUCCESS) {
453 HDF_LOGE("%{public}s: GetMppParam faild, param key:%{public}d", __func__, params[i].key);
454 return ret;
455 }
456 }
457
458 return HDF_SUCCESS;
459 }
460
CodecStart(CODEC_HANDLETYPE handle)461 int32_t CodecStart(CODEC_HANDLETYPE handle)
462 {
463 MPP_RET ret = MPP_OK;
464 MppCtx ctx = handle;
465 RKMppApi *mppApi = g_pBaseComponent->mppApi;
466
467 ret = mppApi->HdiMppStart(ctx);
468 if (ret != MPP_OK) {
469 HDF_LOGE("%{public}s: mpp start failed", __func__);
470 return HDF_FAILURE;
471 }
472 return HDF_SUCCESS;
473 }
474
CodecStop(CODEC_HANDLETYPE handle)475 int32_t CodecStop(CODEC_HANDLETYPE handle)
476 {
477 MPP_RET ret = MPP_OK;
478 MppCtx ctx = handle;
479 RKMppApi *mppApi = g_pBaseComponent->mppApi;
480
481 ret = mppApi->HdiMppStop(ctx);
482 if (ret != MPP_OK) {
483 HDF_LOGE("%{public}s: mpp stop failed", __func__);
484 return HDF_FAILURE;
485 }
486 return HDF_SUCCESS;
487 }
488
CodecFlush(CODEC_HANDLETYPE handle,DirectionType directType)489 int32_t CodecFlush(CODEC_HANDLETYPE handle, DirectionType directType)
490 {
491 MPP_RET ret = MPP_OK;
492 MppCtx ctx = handle;
493 switch (directType) {
494 case INPUT_TYPE:
495 case OUTPUT_TYPE:
496 case ALL_TYPE:
497 ret = g_pBaseComponent->mpi->reset(ctx);
498 if (ret != 0) {
499 HDF_LOGE("%{public}s: reset failed", __func__);
500 return HDF_FAILURE;
501 }
502 break;
503 default:
504 HDF_LOGE("%{public}s: directType failed", __func__);
505 return HDF_FAILURE;
506 }
507
508 UINTPTR userData = NULL;
509 EventType event = EVENT_FLUSH_COMPLETE;
510 uint32_t length = 0;
511 int32_t *eventData = NULL;
512 g_pBaseComponent->pCallbacks->OnEvent(userData, event, length, eventData);
513
514 return HDF_SUCCESS;
515 }
516
DecodeInitPacket(MppPacket * pPacket,CodecBuffer * inputData,RK_U32 pkt_eos)517 int32_t DecodeInitPacket(MppPacket *pPacket, CodecBuffer *inputData, RK_U32 pkt_eos)
518 {
519 MPP_RET ret = MPP_OK;
520 RKMppApi *mppApi = g_pBaseComponent->mppApi;
521 uint8_t *inBuffer = (uint8_t *)inputData->buffer[0].buf;
522 uint32_t inBufferSize = inputData->buffer[0].length;
523
524 ret = mppApi->HdiMppPacketInit(pPacket, inBuffer, inBufferSize);
525 if (ret != MPP_OK) {
526 HDF_LOGE("%{public}s: mpp packet_init failed", __func__);
527 return HDF_FAILURE;
528 }
529
530 mppApi->HdiMppPacketSetData(*pPacket, inBuffer);
531 mppApi->HdiMppPacketSetSize(*pPacket, inBufferSize);
532 mppApi->HdiMppPacketSetPos(*pPacket, inBuffer);
533 mppApi->HdiMppPacketSetLength(*pPacket, inBufferSize);
534 // setup eos flag
535 if (pkt_eos != 0) {
536 mppApi->HdiMppPacketSetEos(*pPacket);
537 }
538 return HDF_SUCCESS;
539 }
540
DecodeGetFrame(MppCtx ctx,MppFrame * frame)541 MPP_RET DecodeGetFrame(MppCtx ctx, MppFrame *frame)
542 {
543 MppApi *mpi = g_pBaseComponent->mpi;
544 MPP_RET ret = MPP_OK;
545 RK_S32 retryTimes = 10;
546 while (true) {
547 ret = mpi->decode_get_frame(ctx, frame);
548 if (ret != MPP_ERR_TIMEOUT) {
549 break;
550 }
551 if (retryTimes > 0) {
552 retryTimes--;
553 usleep(SLEEP_INTERVAL_MICROSECONDS);
554 } else {
555 HDF_LOGE("%{public}s: decode_get_frame failed too much time", __func__);
556 break;
557 }
558 }
559 return ret;
560 }
561
HandleDecodeFrameInfoChange(MppFrame frame,MppCtx ctx)562 int32_t HandleDecodeFrameInfoChange(MppFrame frame, MppCtx ctx)
563 {
564 MPP_RET ret = MPP_OK;
565 RKMppApi *mppApi = g_pBaseComponent->mppApi;
566 MppApi *mpi = g_pBaseComponent->mpi;
567 RK_U32 width = mppApi->HdiMppFrameGetWidth(frame);
568 RK_U32 height = mppApi->HdiMppFrameGetHeight(frame);
569 RK_U32 hor_stride = mppApi->HdiMppFrameGetHorStride(frame);
570 RK_U32 ver_stride = mppApi->HdiMppFrameGetVerStride(frame);
571 RK_U32 buf_size = mppApi->HdiMppFrameGetBufferSize(frame);
572
573 HDF_LOGI("%{public}s: decode_get_frame get info changed found", __func__);
574 HDF_LOGI("%{public}s: decoder require buffer w:h [%{public}d:%{public}d]", __func__, width, height);
575 HDF_LOGI("%{public}s: decoder require stride [%{public}d:%{public}d]", __func__, hor_stride, ver_stride);
576 HDF_LOGI("%{public}s: decoder require buf_size %{public}d", __func__, buf_size);
577
578 if (g_pBaseComponent->frmGrp == NULL) {
579 ret = mppApi->HdiMppBufferGroupGet(&g_pBaseComponent->frmGrp,
580 MPP_BUFFER_TYPE_DRM, MPP_BUFFER_INTERNAL, NULL, __func__);
581 if (ret != MPP_OK) {
582 HDF_LOGE("%{public}s: get mpp buffer group failed ret %{public}d", __func__, ret);
583 return HDF_FAILURE;
584 }
585 ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, g_pBaseComponent->frmGrp);
586 if (ret != MPP_OK) {
587 HDF_LOGE("%{public}s: set buffer group failed ret %{public}d", __func__, ret);
588 return HDF_FAILURE;
589 }
590 } else {
591 ret = mppApi->HdiMppBufferGroupClear(g_pBaseComponent->frmGrp);
592 if (ret != MPP_OK) {
593 HDF_LOGE("%{public}s: clear buffer group failed ret %{public}d", __func__, ret);
594 return HDF_FAILURE;
595 }
596 }
597
598 ret = mppApi->HdiMppBufferGroupLimitConfig(g_pBaseComponent->frmGrp, buf_size, BUFFER_GROUP_LIMIT_NUM);
599 if (ret != MPP_OK) {
600 HDF_LOGE("%{public}s: limit buffer group failed ret %{public}d", __func__, ret);
601 return HDF_FAILURE;
602 }
603 ret = mpi->control(ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
604 if (ret != MPP_OK) {
605 HDF_LOGE("%{public}s: info change ready failed ret %{public}d", __func__, ret);
606 return HDF_FAILURE;
607 }
608 return HDF_SUCCESS;
609 }
610
PutDecodeFrameToOutput(MppFrame frame,CodecBuffer * outInfo)611 static IM_STATUS PutDecodeFrameToOutput(MppFrame frame, CodecBuffer *outInfo)
612 {
613 RKMppApi *mppApi = g_pBaseComponent->mppApi;
614 MppBuffer mppBuffer = mppApi->HdiMppFrameGetBuffer(frame);
615 rga_buffer_t src;
616 rga_buffer_t dst;
617 im_rect rect;
618 int32_t width = mppApi->HdiMppFrameGetWidth(frame);
619 int32_t height = mppApi->HdiMppFrameGetHeight(frame);
620
621 int32_t err = memset_s(&src, sizeof(src), 0, sizeof(src));
622 if (err != EOK) {
623 HDF_LOGE("%{public}s: memset_s src failed, error code: %{public}d", __func__, err);
624 return IM_STATUS_FAILED;
625 }
626 memset_s(&dst, sizeof(dst), 0, sizeof(dst));
627 if (err != EOK) {
628 HDF_LOGE("%{public}s: memset_s dst failed, error code: %{public}d", __func__, err);
629 return IM_STATUS_FAILED;
630 }
631
632 src.fd = mppApi->HdiMppBufferGetFdWithCaller(mppBuffer, __func__);
633 src.wstride = mppApi->HdiMppFrameGetHorStride(frame);
634 src.hstride = mppApi->HdiMppFrameGetVerStride(frame);
635 src.width = width;
636 src.height = height;
637 src.format = RK_FORMAT_YCbCr_420_SP;
638 dst.fd = ((BufferHandle *)outInfo->buffer[0].buf)->fd;
639 dst.wstride = mppApi->HdiMppFrameGetHorStride(frame);
640 dst.hstride = mppApi->HdiMppFrameGetVerStride(frame);
641 dst.width = width;
642 dst.height = height;
643 dst.format = RK_FORMAT_YCbCr_420_SP;
644 rect.x = 0;
645 rect.y = 0;
646 rect.width = width;
647 rect.height = height;
648 return imcrop(src, dst, rect);
649 }
650
HandleDecodeFrameOutput(MppFrame frame,int32_t frm_eos,CodecBuffer * outInfo)651 void HandleDecodeFrameOutput(MppFrame frame, int32_t frm_eos, CodecBuffer *outInfo)
652 {
653 RKMppApi *mppApi = g_pBaseComponent->mppApi;
654 RK_U32 err_info = mppApi->HdiMppFrameGetErrinfo(frame);
655 RK_U32 discard = mppApi->HdiMppFrameGetDiscard(frame);
656 g_pBaseComponent->frameCount++;
657
658 if ((err_info | discard) != 0) {
659 g_pBaseComponent->frameErr++;
660 HDF_LOGE("%{public}s: bad output data, err_info: %{public}d", __func__, err_info);
661 return;
662 }
663 if (outInfo == NULL || outInfo->bufferCnt == 0) {
664 HDF_LOGE("%{public}s: outInfo param invalid!", __func__);
665 return;
666 }
667 // have output data
668 if (outInfo->buffer[0].type == BUFFER_TYPE_HANDLE) {
669 IM_STATUS ret = PutDecodeFrameToOutput(frame, outInfo);
670 if (ret != IM_STATUS_SUCCESS) {
671 HDF_LOGE("%{public}s: copy decode output data failed, error code: %{public}d", __func__, ret);
672 }
673 } else {
674 MppBuffer buffer = mppApi->HdiMppFrameGetBuffer(frame);
675 RK_U8 *base = (RK_U8 *)mppApi->HdiMppBufferGetPtrWithCaller(buffer, __func__);
676 RK_U32 bufferSize = mppApi->HdiMppFrameGetBufferSize(frame);
677 uint8_t *outBuffer = (uint8_t *)outInfo->buffer[0].buf;
678 uint32_t outBufferSize = outInfo->buffer[0].capacity;
679 if (outBuffer != NULL && outBufferSize != 0 && base != NULL && bufferSize != 0) {
680 int32_t ret = memcpy_s(outBuffer, outBufferSize, base, outBufferSize);
681 if (ret == EOK) {
682 outInfo->buffer[0].length = bufferSize;
683 } else {
684 HDF_LOGE("%{public}s: copy output data failed, error code: %{public}d", __func__, ret);
685 HDF_LOGE("%{public}s: dst bufferSize:%{public}d, src data len: %{public}d", __func__,
686 outBufferSize, bufferSize);
687 }
688 } else {
689 if (frm_eos == 0) {
690 HDF_LOGE("%{public}s: output data not copy, buffer incorrect!", __func__);
691 }
692 }
693 }
694
695 if (frm_eos != 0) {
696 outInfo->flag |= STREAM_FLAG_EOS;
697 HDF_LOGI("%{public}s: dec reach STREAM_FLAG_EOS, frame count : %{public}d, error count : %{public}d",
698 __func__, g_pBaseComponent->frameCount, g_pBaseComponent->frameErr);
699 }
700 int32_t acquireFd = 1;
701 g_pBaseComponent->pCallbacks->OutputBufferAvailable((UINTPTR)NULL, outInfo, &acquireFd);
702 }
703
HandleDecodedFrame(MppFrame frame,MppCtx ctx,int32_t frm_eos,CodecBuffer * outInfo)704 int32_t HandleDecodedFrame(MppFrame frame, MppCtx ctx, int32_t frm_eos, CodecBuffer *outInfo)
705 {
706 RKMppApi *mppApi = g_pBaseComponent->mppApi;
707 if (frame) {
708 if (mppApi->HdiMppFrameGetInfoChange(frame)) {
709 if (HandleDecodeFrameInfoChange(frame, ctx) != HDF_SUCCESS) {
710 HDF_LOGE("%{public}s: func failed!", __func__);
711 return HDF_FAILURE;
712 }
713 } else {
714 HandleDecodeFrameOutput(frame, frm_eos, outInfo);
715 }
716 mppApi->HdiMppFrameDeinit(&frame);
717 }
718
719 // try get runtime frame memory usage
720 if (g_pBaseComponent->frmGrp) {
721 size_t usage = mppApi->HdiMppBufferGroupUsage(g_pBaseComponent->frmGrp);
722 if (usage > g_pBaseComponent->maxUsage)
723 g_pBaseComponent->maxUsage = usage;
724 }
725 return HDF_SUCCESS;
726 }
727
CodecDecodeGetFrameLoop(MppCtx ctx,RK_U32 pkt_done,RK_U32 pkt_eos,CodecBuffer * outInfo)728 RK_U32 CodecDecodeGetFrameLoop(MppCtx ctx, RK_U32 pkt_done, RK_U32 pkt_eos, CodecBuffer *outInfo)
729 {
730 MPP_RET ret = MPP_OK;
731 RKMppApi *mppApi = g_pBaseComponent->mppApi;
732 RK_U32 frm_eos = 0;
733 MppFrame frame = NULL;
734
735 do {
736 RK_S32 get_frm = 0;
737 ret = DecodeGetFrame(ctx, &frame);
738 if (ret != MPP_OK) {
739 HDF_LOGE("%{public}s: decode_get_frame failed, ret:%{public}d", __func__, ret);
740 break;
741 }
742 if (frame) {
743 frm_eos = mppApi->HdiMppFrameGetEos(frame);
744 get_frm = 1;
745 if (HandleDecodedFrame(frame, ctx, frm_eos, outInfo) != HDF_SUCCESS) {
746 break;
747 }
748 }
749 if (pkt_eos != 0 && pkt_done != 0 && frm_eos == 0) {
750 usleep(SLEEP_INTERVAL_MICROSECONDS);
751 continue;
752 }
753 if (frm_eos) {
754 break;
755 }
756
757 if ((g_pBaseComponent->frameNum > 0 && (g_pBaseComponent->frameCount >= g_pBaseComponent->frameNum)) ||
758 ((g_pBaseComponent->frameNum == 0) && frm_eos != 0)) {
759 break;
760 }
761 if (get_frm) {
762 continue;
763 }
764 break;
765 } while (1);
766
767 return frm_eos;
768 }
769
CodecDecode(CODEC_HANDLETYPE handle,CodecBuffer * inputData,CodecBuffer * outInfo,uint32_t timeoutMs)770 int32_t CodecDecode(CODEC_HANDLETYPE handle, CodecBuffer* inputData, CodecBuffer* outInfo, uint32_t timeoutMs)
771 {
772 MPP_RET ret = MPP_OK;
773 MppCtx ctx = handle;
774 MppApi *mpi = g_pBaseComponent->mpi;
775 MppPacket packet = g_pBaseComponent->packet;
776 RK_U32 loop_end = 0;
777 RK_U32 frm_eos;
778 RK_U32 pkt_done = 0;
779 RK_U32 pkt_eos = (inputData->flag == STREAM_FLAG_EOS) ? 1 : 0;
780
781 if (DecodeInitPacket(&packet, inputData, pkt_eos) != HDF_SUCCESS) {
782 HDF_LOGE("%{public}s: Init packet failed!", __func__);
783 return HDF_FAILURE;
784 }
785
786 do {
787 if (!pkt_done) {
788 ret = mpi->decode_put_packet(ctx, packet);
789 if (MPP_OK == ret) {
790 pkt_done = 1;
791 }
792 }
793
794 frm_eos = CodecDecodeGetFrameLoop(ctx, pkt_done, pkt_eos, outInfo);
795 if ((g_pBaseComponent->frameNum > 0 && (g_pBaseComponent->frameCount >= g_pBaseComponent->frameNum)) ||
796 ((g_pBaseComponent->frameNum == 0) && frm_eos != 0)) {
797 loop_end = 1;
798 break;
799 }
800 if (pkt_done) {
801 break;
802 }
803 usleep(SLEEP_INTERVAL_MICROSECONDS);
804 } while (1);
805 int32_t acquireFd = 1;
806 g_pBaseComponent->pCallbacks->InputBufferAvailable((UINTPTR)NULL, inputData, &acquireFd);
807
808 if (loop_end != 1) {
809 return HDF_FAILURE;
810 }
811 return HDF_SUCCESS;
812 }
813
GetEncodeFrameFromInput(MppFrame frame,MppBuffer mppBuffer,CodecBuffer * inputInfo)814 static IM_STATUS GetEncodeFrameFromInput(MppFrame frame, MppBuffer mppBuffer, CodecBuffer *inputInfo)
815 {
816 RKMppApi *mppApi = g_pBaseComponent->mppApi;
817 rga_buffer_t src;
818 rga_buffer_t dst;
819 im_rect rect;
820 int32_t width = mppApi->HdiMppFrameGetWidth(frame);
821 int32_t height = mppApi->HdiMppFrameGetHeight(frame);
822
823 int32_t err = memset_s(&src, sizeof(src), 0, sizeof(src));
824 if (err != EOK) {
825 HDF_LOGE("%{public}s: memset_s src failed, error code: %{public}d", __func__, err);
826 return IM_STATUS_FAILED;
827 }
828 err = memset_s(&dst, sizeof(dst), 0, sizeof(dst));
829 if (err != EOK) {
830 HDF_LOGE("%{public}s: memset_s dst failed, error code: %{public}d", __func__, err);
831 return IM_STATUS_FAILED;
832 }
833
834 src.fd = ((BufferHandle *)inputInfo->buffer[0].buf)->fd;
835 src.wstride = mppApi->HdiMppFrameGetHorStride(frame);
836 src.hstride = mppApi->HdiMppFrameGetVerStride(frame);
837 src.width = width;
838 src.height = height;
839 src.format = RK_FORMAT_YCbCr_420_SP;
840 dst.fd = mppApi->HdiMppBufferGetFdWithCaller(mppBuffer, __func__);
841 dst.wstride = mppApi->HdiMppFrameGetHorStride(frame);
842 dst.hstride = mppApi->HdiMppFrameGetVerStride(frame);
843 dst.width = width;
844 dst.height = height;
845 dst.format = RK_FORMAT_YCbCr_420_SP;
846 rect.x = 0;
847 rect.y = 0;
848 rect.width = width;
849 rect.height = height;
850 return imcrop(src, dst, rect);
851 }
852
EncodeInitFrame(MppFrame * pFrame,RK_U32 frm_eos,CodecBuffer * inputData)853 int32_t EncodeInitFrame(MppFrame *pFrame, RK_U32 frm_eos, CodecBuffer *inputData)
854 {
855 MPP_RET ret = MPP_OK;
856 RKMppApi *mppApi = g_pBaseComponent->mppApi;
857
858 if (frm_eos != 0) {
859 HDF_LOGI("%{public}s: receive eos frame", __func__);
860 }
861 ret = mppApi->HdiMppFrameInit(pFrame);
862 if (ret != MPP_OK) {
863 HDF_LOGE("%{public}s: mpp_frame_init failed", __func__);
864 return HDF_FAILURE;
865 }
866 mppApi->HdiMppFrameSetWidth(*pFrame, g_pBaseComponent->setup.width);
867 mppApi->HdiMppFrameSetHeight(*pFrame, g_pBaseComponent->setup.height);
868 mppApi->HdiMppFrameSetHorStride(*pFrame, g_pBaseComponent->setup.stride.horStride);
869 mppApi->HdiMppFrameSetVerStride(*pFrame, g_pBaseComponent->setup.stride.verStride);
870 mppApi->HdiMppFrameSetFormat(*pFrame, g_pBaseComponent->fmt);
871 mppApi->HdiMppFrameSetEos(*pFrame, frm_eos);
872
873 if (inputData->buffer[0].type == BUFFER_TYPE_HANDLE) {
874 IM_STATUS status = GetEncodeFrameFromInput(*pFrame, g_pBaseComponent->frmBuf, inputData);
875 if (status == IM_STATUS_SUCCESS) {
876 mppApi->HdiMppFrameSetBuffer(*pFrame, g_pBaseComponent->frmBuf);
877 } else {
878 mppApi->HdiMppFrameDeinit(&pFrame);
879 HDF_LOGE("%{public}s: copy encode input data failed, error code: %{public}d", __func__, ret);
880 return HDF_FAILURE;
881 }
882 } else {
883 uint8_t *buf = NULL;
884 if ((uint8_t *)inputData->buffer[0].buf != NULL && inputData->buffer[0].length > 0) {
885 buf = (uint8_t *)mppApi->HdiMppBufferGetPtrWithCaller(g_pBaseComponent->frmBuf, __func__);
886 if (buf == NULL) {
887 HDF_LOGE("%{public}s: mpp buffer get ptr with caller failed", __func__);
888 mppApi->HdiMppFrameDeinit(&pFrame);
889 return HDF_FAILURE;
890 }
891 uint8_t *inBuffer = (uint8_t *)inputData->buffer[0].buf;
892 uint32_t inBufferSize = inputData->buffer[0].length;
893 int32_t ret = memcpy_s(buf, inBufferSize, inBuffer, inBufferSize);
894 if (ret != EOK) {
895 HDF_LOGE("%{public}s: copy input data failed, error code: %{public}d", __func__, ret);
896 mppApi->HdiMppFrameDeinit(&pFrame);
897 return HDF_FAILURE;
898 }
899 mppApi->HdiMppFrameSetBuffer(*pFrame, g_pBaseComponent->frmBuf);
900 } else {
901 mppApi->HdiMppFrameSetBuffer(*pFrame, NULL);
902 HDF_LOGI("%{public}s: receive empty frame", __func__);
903 }
904 }
905
906 return HDF_SUCCESS;
907 }
908
HandleEncodedPacket(MppPacket packet,RK_U32 pkt_eos,CodecBuffer * outInfo)909 int32_t HandleEncodedPacket(MppPacket packet, RK_U32 pkt_eos, CodecBuffer *outInfo)
910 {
911 RKMppApi *mppApi = g_pBaseComponent->mppApi;
912 void *ptr = mppApi->HdiMppPacketGetPos(packet);
913 size_t len = mppApi->HdiMppPacketGetLength(packet);
914 pkt_eos = mppApi->HdiMppPacketGetEos(packet);
915
916 // call back have out data
917 UINTPTR userData = NULL;
918 int32_t acquireFd = 1;
919 uint8_t *outBuffer = (uint8_t *)outInfo->buffer[0].buf;
920 uint32_t outBufferSize = outInfo->buffer[0].capacity;
921 if (outBuffer != NULL && outBufferSize != 0 && ptr != NULL && len != 0) {
922 int32_t ret = memcpy_s(outBuffer, outBufferSize, ptr, len);
923 if (ret == EOK) {
924 outInfo->buffer[0].length = len;
925 } else {
926 HDF_LOGE("%{public}s: copy output data failed, error code: %{public}d", __func__, ret);
927 HDF_LOGE("%{public}s: dst bufferSize:%{public}d, src data len: %{public}d", __func__, outBufferSize, len);
928 }
929 } else {
930 HDF_LOGE("%{public}s: output data not copy, buffer incorrect!", __func__);
931 }
932 if (pkt_eos != 0) {
933 outInfo->flag |= STREAM_FLAG_EOS;
934 HDF_LOGI("%{public}s: enc reach STREAM_FLAG_EOS, frame count : %{public}d",
935 __func__, g_pBaseComponent->frameCount);
936 }
937 g_pBaseComponent->pCallbacks->OutputBufferAvailable(userData, outInfo, &acquireFd);
938
939 return HDF_SUCCESS;
940 }
941
CodecEncodeGetPacketLoop(MppCtx ctx,CodecBuffer * outInfo)942 RK_U32 CodecEncodeGetPacketLoop(MppCtx ctx, CodecBuffer *outInfo)
943 {
944 MPP_RET ret = MPP_OK;
945 MppApi *mpi = g_pBaseComponent->mpi;
946 RKMppApi *mppApi = g_pBaseComponent->mppApi;
947 MppPacket packet = g_pBaseComponent->packet;
948 RK_U32 eoi = 1;
949 RK_U32 pkt_eos = 0;
950
951 do {
952 ret = mpi->encode_get_packet(ctx, &packet);
953 if (ret != MPP_OK) {
954 HDF_LOGE("%{public}s: mpp encode get packet failed", __func__);
955 return HDF_FAILURE;
956 }
957
958 if (packet) {
959 pkt_eos = mppApi->HdiMppPacketGetEos(packet);
960 HandleEncodedPacket(packet, pkt_eos, outInfo);
961
962 /* for low delay partition encoding */
963 if (mppApi->HdiMppPacketIsPartition(packet)) {
964 eoi = mppApi->HdiMppPacketIsEoi(packet);
965 }
966
967 mppApi->HdiMppPacketDeinit(&packet);
968 g_pBaseComponent->frameCount += eoi;
969
970 if (pkt_eos != 0) {
971 HDF_LOGI("%{public}s: find eos packet", __func__);
972 break;
973 }
974 }
975 } while (!eoi);
976
977 return pkt_eos;
978 }
979
CodecEncode(CODEC_HANDLETYPE handle,CodecBuffer * inputData,CodecBuffer * outInfo,uint32_t timeoutMs)980 int32_t CodecEncode(CODEC_HANDLETYPE handle, CodecBuffer *inputData, CodecBuffer *outInfo, uint32_t timeoutMs)
981 {
982 MPP_RET ret = MPP_OK;
983 MppApi *mpi = g_pBaseComponent->mpi;
984 RKMppApi *mppApi = g_pBaseComponent->mppApi;
985 MppFrame frame = NULL;
986 MppCtx ctx = handle;
987 RK_U32 pkt_eos = 0;
988 RK_U32 loop_end = 0;
989 RK_U32 frm_eos = 0;
990 UINTPTR userData = NULL;
991 int32_t acquireFd = 1;
992
993 if (inputData == NULL || inputData->bufferCnt == 0) {
994 HDF_LOGE("%{public}s: inputData param invalid!", __func__);
995 return HDF_FAILURE;
996 }
997 frm_eos = (inputData->flag == STREAM_FLAG_EOS) ? 1 : 0;
998
999 if (EncodeInitFrame(&frame, frm_eos, inputData) != HDF_SUCCESS) {
1000 return HDF_FAILURE;
1001 }
1002
1003 ret = mpi->encode_put_frame(ctx, frame);
1004 if (ret != MPP_OK) {
1005 HDF_LOGE("%{public}s: mpp encode put frame failed", __func__);
1006 mppApi->HdiMppFrameDeinit(&frame);
1007 return HDF_FAILURE;
1008 }
1009 mppApi->HdiMppFrameDeinit(&frame);
1010 pkt_eos = CodecEncodeGetPacketLoop(ctx, outInfo);
1011
1012 g_pBaseComponent->pCallbacks->InputBufferAvailable(userData, inputData, &acquireFd);
1013 if (g_pBaseComponent->frameNum > 0 && g_pBaseComponent->frameCount >= g_pBaseComponent->frameNum) {
1014 loop_end = 1;
1015 }
1016
1017 if (frm_eos != 0 && pkt_eos != 0) {
1018 loop_end = 1;
1019 }
1020
1021 if (loop_end != 1) {
1022 return HDF_FAILURE;
1023 }
1024 return HDF_SUCCESS;
1025 }
1026
CodecEncodeHeader(CODEC_HANDLETYPE handle,CodecBuffer outInfo,uint32_t timeoutMs)1027 int32_t CodecEncodeHeader(CODEC_HANDLETYPE handle, CodecBuffer outInfo, uint32_t timeoutMs)
1028 {
1029 MPP_RET ret = MPP_OK;
1030 MppCtx ctx = handle;
1031 RKMppApi *mppApi = g_pBaseComponent->mppApi;
1032
1033 MppPacket packet = NULL;
1034
1035 mppApi->HdiMppPacketInitWithBuffer(&packet, g_pBaseComponent->pktBuf);
1036 // NOTE: It is important to clear output packet length!!
1037 mppApi->HdiMppPacketSetLength(packet, 0);
1038
1039 ret = g_pBaseComponent->mpi->control(ctx, MPP_ENC_GET_HDR_SYNC, packet);
1040 if (ret != MPP_OK) {
1041 HDF_LOGE("%{public}s: mpi control enc get extra info failed", __func__);
1042 return HDF_FAILURE;
1043 } else {
1044 void *ptr = mppApi->HdiMppPacketGetPos(packet);
1045 size_t len = mppApi->HdiMppPacketGetLength(packet);
1046
1047 // call back have out data
1048 UINTPTR userData = NULL;
1049 int32_t acquireFd = 1;
1050 uint8_t *outBuffer = (uint8_t *)outInfo.buffer[0].buf;
1051 uint32_t outBufferSize = outInfo.buffer[0].capacity;
1052 outInfo.buffer[0].length = len;
1053 if (outBuffer != NULL && outBufferSize != 0 && ptr != NULL && len != 0) {
1054 int32_t ret = memcpy_s(outBuffer, len, ptr, len);
1055 if (ret != EOK) {
1056 HDF_LOGE("%{public}s: copy output data failed, error code: %{public}d", __func__, ret);
1057 }
1058 }
1059 g_pBaseComponent->pCallbacks->OutputBufferAvailable(userData, &outInfo, &acquireFd);
1060 }
1061
1062 mppApi->HdiMppPacketDeinit(&packet);
1063 return HDF_SUCCESS;
1064 }
1065