exynos_omx: multi_thread: Support EOSBehavior.
[GitHub/LineageOS/android_hardware_samsung_slsi_exynos5.git] / exynos_omx / codecs / exynos_codecs / video / exynos5 / mfc_v4l2 / dec / src / ExynosVideoDecoder.c
1 /*
2 *
3 * Copyright 2012 Samsung Electronics S.LSI 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 /*
19 * @file ExynosVideoDecoder.c
20 * @brief
21 * @author Jinsung Yang (jsgood.yang@samsung.com)
22 * @version 1.0.0
23 * @history
24 * 2012.01.15: Initial Version
25 */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <fcntl.h>
32
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <sys/ioctl.h>
36 #include <sys/mman.h>
37 #include <pthread.h>
38
39 #include <sys/poll.h>
40
41 #include "ExynosVideoApi.h"
42 #include "ExynosVideoDec.h"
43 #include "OMX_Core.h"
44
45 /* #define LOG_NDEBUG 0 */
46 #define LOG_TAG "ExynosVideoDecoder"
47 #include <utils/Log.h>
48
49 /*
50 * [Common] __CodingType_To_V4L2PixelFormat
51 */
52 static unsigned int __CodingType_To_V4L2PixelFormat(ExynosVideoCodingType codingType)
53 {
54 unsigned int pixelformat = V4L2_PIX_FMT_H264;
55
56 switch (codingType) {
57 case VIDEO_CODING_AVC:
58 pixelformat = V4L2_PIX_FMT_H264;
59 break;
60 case VIDEO_CODING_MPEG4:
61 pixelformat = V4L2_PIX_FMT_MPEG4;
62 break;
63 case VIDEO_CODING_VP8:
64 pixelformat = V4L2_PIX_FMT_VP8;
65 break;
66 case VIDEO_CODING_H263:
67 pixelformat = V4L2_PIX_FMT_H263;
68 break;
69 case VIDEO_CODING_VC1:
70 pixelformat = V4L2_PIX_FMT_VC1_ANNEX_G;
71 break;
72 case VIDEO_CODING_VC1_RCV:
73 pixelformat = V4L2_PIX_FMT_VC1_ANNEX_L;
74 break;
75 case VIDEO_CODING_MPEG2:
76 pixelformat = V4L2_PIX_FMT_MPEG2;
77 break;
78 default:
79 pixelformat = V4L2_PIX_FMT_H264;
80 break;
81 }
82
83 return pixelformat;
84 }
85
86 /*
87 * [Common] __ColorFormatType_To_V4L2PixelFormat
88 */
89 static unsigned int __ColorFormatType_To_V4L2PixelFormat(ExynosVideoColorFormatType colorFormatType)
90 {
91 unsigned int pixelformat = V4L2_PIX_FMT_NV12M;
92
93 switch (colorFormatType) {
94 case VIDEO_COLORFORMAT_NV12_TILED:
95 pixelformat = V4L2_PIX_FMT_NV12MT_16X16;
96 break;
97 case VIDEO_COLORFORMAT_NV21:
98 pixelformat = V4L2_PIX_FMT_NV21M;
99 break;
100 case VIDEO_COLORFORMAT_NV12:
101 default:
102 pixelformat = V4L2_PIX_FMT_NV12M;
103 break;
104 }
105
106 return pixelformat;
107 }
108
109 /*
110 * [Decoder OPS] Init
111 */
112 static void *MFC_Decoder_Init(int nMemoryType)
113 {
114 ExynosVideoDecContext *pCtx = NULL;
115 pthread_mutex_t *pMutex = NULL;
116 int needCaps = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING);
117
118 pCtx = (ExynosVideoDecContext *)malloc(sizeof(*pCtx));
119 if (pCtx == NULL) {
120 ALOGE("%s: Failed to allocate decoder context buffer", __func__);
121 goto EXIT_ALLOC_FAIL;
122 }
123
124 memset(pCtx, 0, sizeof(*pCtx));
125
126 pCtx->hDec = exynos_v4l2_open_devname(VIDEO_DECODER_NAME, O_RDWR, 0);
127 if (pCtx->hDec < 0) {
128 ALOGE("%s: Failed to open decoder device", __func__);
129 goto EXIT_OPEN_FAIL;
130 }
131
132 if (!exynos_v4l2_querycap(pCtx->hDec, needCaps)) {
133 ALOGE("%s: Failed to querycap", __func__);
134 goto EXIT_QUERYCAP_FAIL;
135 }
136
137 pCtx->bStreamonInbuf = VIDEO_FALSE;
138 pCtx->bStreamonOutbuf = VIDEO_FALSE;
139
140 pCtx->nMemoryType = nMemoryType;
141
142 pMutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
143 if (pMutex == NULL) {
144 ALOGE("%s: Failed to allocate mutex about input buffer", __func__);
145 goto EXIT_QUERYCAP_FAIL;
146 }
147 if (pthread_mutex_init(pMutex, NULL) != 0) {
148 free(pMutex);
149 goto EXIT_QUERYCAP_FAIL;
150 }
151 pCtx->pInMutex = (void*)pMutex;
152
153 pMutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
154 if (pMutex == NULL) {
155 ALOGE("%s: Failed to allocate mutex about output buffer", __func__);
156 goto EXIT_QUERYCAP_FAIL;
157 }
158 if (pthread_mutex_init(pMutex, NULL) != 0) {
159 free(pMutex);
160 goto EXIT_QUERYCAP_FAIL;
161 }
162 pCtx->pOutMutex = (void*)pMutex;
163
164 return (void *)pCtx;
165
166 EXIT_QUERYCAP_FAIL:
167 if (pCtx->pInMutex != NULL) {
168 pthread_mutex_destroy(pCtx->pInMutex);
169 free(pCtx->pInMutex);
170 }
171
172 if (pCtx->pOutMutex != NULL) {
173 pthread_mutex_destroy(pCtx->pOutMutex);
174 free(pCtx->pOutMutex);
175 }
176
177 close(pCtx->hDec);
178
179 EXIT_OPEN_FAIL:
180 free(pCtx);
181
182 EXIT_ALLOC_FAIL:
183 return NULL;
184 }
185
186 /*
187 * [Decoder OPS] Finalize
188 */
189 static ExynosVideoErrorType MFC_Decoder_Finalize(void *pHandle)
190 {
191 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
192 ExynosVideoPlane *pVideoPlane = NULL;
193 pthread_mutex_t *pMutex = NULL;
194 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
195 int i, j;
196
197 if (pCtx == NULL) {
198 ALOGE("%s: Video context info must be supplied", __func__);
199 ret = VIDEO_ERROR_BADPARAM;
200 goto EXIT;
201 }
202
203 if (pCtx->pOutMutex != NULL) {
204 pMutex = (pthread_mutex_t*)pCtx->pOutMutex;
205 pthread_mutex_destroy(pMutex);
206 free(pMutex);
207 pCtx->pOutMutex = NULL;
208 }
209
210 if (pCtx->pInMutex != NULL) {
211 pMutex = (pthread_mutex_t*)pCtx->pInMutex;
212 pthread_mutex_destroy(pMutex);
213 free(pMutex);
214 pCtx->pInMutex = NULL;
215 }
216
217 if (pCtx->bShareInbuf == VIDEO_FALSE) {
218 for (i = 0; i < pCtx->nInbufs; i++) {
219 for (j = 0; j < VIDEO_DECODER_INBUF_PLANES; j++) {
220 pVideoPlane = &pCtx->pInbuf[i].planes[j];
221 if (pVideoPlane->addr != NULL) {
222 munmap(pVideoPlane->addr, pVideoPlane->allocSize);
223 pVideoPlane->addr = NULL;
224 pVideoPlane->allocSize = 0;
225 pVideoPlane->dataSize = 0;
226 }
227
228 pCtx->pInbuf[i].pGeometry = NULL;
229 pCtx->pInbuf[i].bQueued = VIDEO_FALSE;
230 pCtx->pInbuf[i].bRegistered = VIDEO_FALSE;
231 }
232 }
233 }
234
235 if (pCtx->bShareOutbuf == VIDEO_FALSE) {
236 for (i = 0; i < pCtx->nOutbufs; i++) {
237 for (j = 0; j < VIDEO_DECODER_OUTBUF_PLANES; j++) {
238 pVideoPlane = &pCtx->pOutbuf[i].planes[j];
239 if (pVideoPlane->addr != NULL) {
240 munmap(pVideoPlane->addr, pVideoPlane->allocSize);
241 pVideoPlane->addr = NULL;
242 pVideoPlane->allocSize = 0;
243 pVideoPlane->dataSize = 0;
244 }
245
246 pCtx->pOutbuf[i].pGeometry = NULL;
247 pCtx->pOutbuf[i].bQueued = VIDEO_FALSE;
248 pCtx->pOutbuf[i].bRegistered = VIDEO_FALSE;
249 }
250 }
251 }
252
253 if (pCtx->pInbuf != NULL)
254 free(pCtx->pInbuf);
255
256 if (pCtx->pOutbuf != NULL)
257 free(pCtx->pOutbuf);
258
259 if (pCtx->hDec > 0)
260 close(pCtx->hDec);
261
262 free(pCtx);
263
264 EXIT:
265 return ret;
266 }
267
268 /*
269 * [Decoder OPS] Set Frame Tag
270 */
271 static ExynosVideoErrorType MFC_Decoder_Set_FrameTag(
272 void *pHandle,
273 int frameTag)
274 {
275 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
276 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
277
278 if (pCtx == NULL) {
279 ALOGE("%s: Video context info must be supplied", __func__);
280 ret = VIDEO_ERROR_BADPARAM;
281 goto EXIT;
282 }
283
284 if (exynos_v4l2_s_ctrl(pCtx->hDec, V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG, frameTag) != 0) {
285 ret = VIDEO_ERROR_APIFAIL;
286 goto EXIT;
287 }
288
289 EXIT:
290 return ret;
291 }
292
293 /*
294 * [Decoder OPS] Get Frame Tag
295 */
296 static int MFC_Decoder_Get_FrameTag(void *pHandle)
297 {
298 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
299 int frameTag = -1;
300
301 if (pCtx == NULL) {
302 ALOGE("%s: Video context info must be supplied", __func__);
303 goto EXIT;
304 }
305
306 exynos_v4l2_g_ctrl(pCtx->hDec, V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG, &frameTag);
307
308 EXIT:
309 return frameTag;
310 }
311
312 /*
313 * [Decoder OPS] Get Buffer Count
314 */
315 static int MFC_Decoder_Get_ActualBufferCount(void *pHandle)
316 {
317 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
318 int bufferCount = -1;
319
320 if (pCtx == NULL) {
321 ALOGE("%s: Video context info must be supplied", __func__);
322 goto EXIT;
323 }
324
325 exynos_v4l2_g_ctrl(pCtx->hDec, V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, &bufferCount);
326
327 EXIT:
328 return bufferCount;
329 }
330
331 /*
332 * [Decoder OPS] Set Display Delay
333 */
334 static ExynosVideoErrorType MFC_Decoder_Set_DisplayDelay(
335 void *pHandle,
336 int delay)
337 {
338 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
339 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
340
341 if (pCtx == NULL) {
342 ALOGE("%s: Video context info must be supplied", __func__);
343 ret = VIDEO_ERROR_BADPARAM;
344 goto EXIT;
345 }
346
347 if (exynos_v4l2_s_ctrl(pCtx->hDec, V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY, delay) != 0) {
348 ret = VIDEO_ERROR_APIFAIL;
349 goto EXIT;
350 }
351
352 EXIT:
353 return ret;
354 }
355
356 /*
357 * [Decoder OPS] Enable Packed PB
358 */
359 static ExynosVideoErrorType MFC_Decoder_Enable_PackedPB(void *pHandle)
360 {
361 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
362 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
363
364 if (pCtx == NULL) {
365 ALOGE("%s: Video context info must be supplied", __func__);
366 ret = VIDEO_ERROR_BADPARAM;
367 goto EXIT;
368 }
369
370 if (exynos_v4l2_s_ctrl(pCtx->hDec, V4L2_CID_MPEG_MFC51_VIDEO_PACKED_PB, 1) != 0) {
371 ret = VIDEO_ERROR_APIFAIL;
372 goto EXIT;
373 }
374
375 EXIT:
376 return ret;
377 }
378
379 /*
380 * [Decoder OPS] Enable Loop Filter
381 */
382 static ExynosVideoErrorType MFC_Decoder_Enable_LoopFilter(void *pHandle)
383 {
384 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
385 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
386
387 if (pCtx == NULL) {
388 ALOGE("%s: Video context info must be supplied", __func__);
389 ret = VIDEO_ERROR_BADPARAM;
390 goto EXIT;
391 }
392
393 if (exynos_v4l2_s_ctrl(pCtx->hDec, V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER, 1) != 0) {
394 ret = VIDEO_ERROR_APIFAIL;
395 goto EXIT;
396 }
397
398 EXIT:
399 return ret;
400 }
401
402 /*
403 * [Decoder OPS] Enable Slice Mode
404 */
405 static ExynosVideoErrorType MFC_Decoder_Enable_SliceMode(void *pHandle)
406 {
407 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
408 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
409
410 if (pCtx == NULL) {
411 ALOGE("%s: Video context info must be supplied", __func__);
412 ret = VIDEO_ERROR_BADPARAM;
413 goto EXIT;
414 }
415
416 if (exynos_v4l2_s_ctrl(pCtx->hDec, V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE, 1) != 0) {
417 ret = VIDEO_ERROR_APIFAIL;
418 goto EXIT;
419 }
420
421 EXIT:
422 return ret;
423 }
424
425 /*
426 * [Decoder OPS] Enable SEI Parsing
427 */
428 static ExynosVideoErrorType MFC_Decoder_Enable_SEIParsing(void *pHandle)
429 {
430 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
431 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
432
433 if (pCtx == NULL) {
434 ALOGE("%s: Video context info must be supplied", __func__);
435 ret = VIDEO_ERROR_BADPARAM;
436 goto EXIT;
437 }
438
439 if (exynos_v4l2_s_ctrl(pCtx->hDec, V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING, 1) != 0) {
440 ret = VIDEO_ERROR_APIFAIL;
441 goto EXIT;
442 }
443
444 EXIT:
445 return ret;
446 }
447
448 /*
449 * [Decoder OPS] Get Frame Packing information
450 */
451 static ExynosVideoErrorType MFC_Decoder_Get_FramePackingInfo(
452 void *pHandle,
453 ExynosVideoFramePacking *pFramePacking)
454 {
455 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
456 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
457
458 struct v4l2_ext_control ext_ctrl[FRAME_PACK_SEI_INFO_NUM];
459 struct v4l2_ext_controls ext_ctrls;
460
461 int seiAvailable, seiInfo, seiGridPos, i;
462 unsigned int seiArgmtId;
463
464
465 if ((pCtx == NULL) || (pFramePacking == NULL)) {
466 ALOGE("%s: Video context info or FramePacking pointer must be supplied", __func__);
467 ret = VIDEO_ERROR_BADPARAM;
468 goto EXIT;
469 }
470
471 memset(pFramePacking, 0, sizeof(*pFramePacking));
472 memset(ext_ctrl, 0, (sizeof(struct v4l2_ext_control) * FRAME_PACK_SEI_INFO_NUM));
473
474 ext_ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
475 ext_ctrls.count = FRAME_PACK_SEI_INFO_NUM;
476 ext_ctrls.controls = ext_ctrl;
477 ext_ctrl[0].id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_AVAIL;
478 ext_ctrl[1].id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRGMENT_ID;
479 ext_ctrl[2].id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_INFO;
480 ext_ctrl[3].id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_GRID_POS;
481
482 if (exynos_v4l2_g_ext_ctrl(pCtx->hDec, &ext_ctrls) != 0) {
483 ret = VIDEO_ERROR_APIFAIL;
484 goto EXIT;
485 }
486
487 seiAvailable = ext_ctrl[0].value;
488 seiArgmtId = ext_ctrl[1].value;
489 seiInfo = ext_ctrl[2].value;
490 seiGridPos = ext_ctrl[3].value;
491
492 pFramePacking->available = seiAvailable;
493 pFramePacking->arrangement_id = seiArgmtId;
494
495 pFramePacking->arrangement_cancel_flag = OPERATE_BIT(seiInfo, 0x1, 0);
496 pFramePacking->arrangement_type = OPERATE_BIT(seiInfo, 0x3f, 1);
497 pFramePacking->quincunx_sampling_flag = OPERATE_BIT(seiInfo, 0x1, 8);
498 pFramePacking->content_interpretation_type = OPERATE_BIT(seiInfo, 0x3f, 9);
499 pFramePacking->spatial_flipping_flag = OPERATE_BIT(seiInfo, 0x1, 15);
500 pFramePacking->frame0_flipped_flag = OPERATE_BIT(seiInfo, 0x1, 16);
501 pFramePacking->field_views_flag = OPERATE_BIT(seiInfo, 0x1, 17);
502 pFramePacking->current_frame_is_frame0_flag = OPERATE_BIT(seiInfo, 0x1, 18);
503
504 pFramePacking->frame0_grid_pos_x = OPERATE_BIT(seiGridPos, 0xf, 0);
505 pFramePacking->frame0_grid_pos_y = OPERATE_BIT(seiGridPos, 0xf, 4);
506 pFramePacking->frame1_grid_pos_x = OPERATE_BIT(seiGridPos, 0xf, 8);
507 pFramePacking->frame1_grid_pos_y = OPERATE_BIT(seiGridPos, 0xf, 12);
508
509 EXIT:
510 return ret;
511 }
512
513 /*
514 * [Decoder Buffer OPS] Enable Cacheable (Input)
515 */
516 static ExynosVideoErrorType MFC_Decoder_Enable_Cacheable_Inbuf(void *pHandle)
517 {
518 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
519 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
520
521 if (pCtx == NULL) {
522 ALOGE("%s: Video context info must be supplied", __func__);
523 ret = VIDEO_ERROR_BADPARAM;
524 goto EXIT;
525 }
526
527 if (exynos_v4l2_s_ctrl(pCtx->hDec, V4L2_CID_CACHEABLE, 2) != 0) {
528 ret = VIDEO_ERROR_APIFAIL;
529 goto EXIT;
530 }
531
532 EXIT:
533 return ret;
534 }
535
536 /*
537 * [Decoder Buffer OPS] Enable Cacheable (Output)
538 */
539 static ExynosVideoErrorType MFC_Decoder_Enable_Cacheable_Outbuf(void *pHandle)
540 {
541 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
542 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
543
544 if (pCtx == NULL) {
545 ALOGE("%s: Video context info must be supplied", __func__);
546 ret = VIDEO_ERROR_BADPARAM;
547 goto EXIT;
548 }
549
550 if (exynos_v4l2_s_ctrl(pCtx->hDec, V4L2_CID_CACHEABLE, 1) != 0) {
551 ret = VIDEO_ERROR_APIFAIL;
552 goto EXIT;
553 }
554
555 EXIT:
556 return ret;
557 }
558
559 /*
560 * [Decoder Buffer OPS] Set Shareable Buffer (Input)
561 */
562 static ExynosVideoErrorType MFC_Decoder_Set_Shareable_Inbuf(void *pHandle)
563 {
564 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
565 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
566
567 if (pCtx == NULL) {
568 ALOGE("%s: Video context info must be supplied", __func__);
569 ret = VIDEO_ERROR_BADPARAM;
570 goto EXIT;
571 }
572
573 pCtx->bShareInbuf = VIDEO_TRUE;
574
575 EXIT:
576 return ret;
577 }
578
579 /*
580 * [Decoder Buffer OPS] Set Shareable Buffer (Output)
581 */
582 static ExynosVideoErrorType MFC_Decoder_Set_Shareable_Outbuf(void *pHandle)
583 {
584 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
585 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
586
587 if (pCtx == NULL) {
588 ALOGE("%s: Video context info must be supplied", __func__);
589 ret = VIDEO_ERROR_BADPARAM;
590 goto EXIT;
591 }
592
593 pCtx->bShareOutbuf = VIDEO_TRUE;
594
595 EXIT:
596 return ret;
597 }
598
599 /*
600 * [Decoder Buffer OPS] Get Buffer (Input)
601 */
602 static ExynosVideoErrorType MFC_Decoder_Get_Buffer_Inbuf(
603 void *pHandle,
604 int nIndex,
605 ExynosVideoBuffer **pBuffer)
606 {
607 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
608 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
609
610 if (pCtx == NULL) {
611 ALOGE("%s: Video context info must be supplied", __func__);
612 *pBuffer = NULL;
613 ret = VIDEO_ERROR_BADPARAM;
614 goto EXIT;
615 }
616
617 if (pCtx->nInbufs <= nIndex) {
618 *pBuffer = NULL;
619 ret = VIDEO_ERROR_BADPARAM;
620 goto EXIT;
621 }
622
623 *pBuffer = (ExynosVideoBuffer *)&pCtx->pInbuf[nIndex];
624
625 EXIT:
626 return ret;
627 }
628
629 /*
630 * [Decoder Buffer OPS] Get Buffer (Output)
631 */
632 static ExynosVideoErrorType MFC_Decoder_Get_Buffer_Outbuf(
633 void *pHandle,
634 int nIndex,
635 ExynosVideoBuffer **pBuffer)
636 {
637 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
638 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
639
640 if (pCtx == NULL) {
641 ALOGE("%s: Video context info must be supplied", __func__);
642 *pBuffer = NULL;
643 ret = VIDEO_ERROR_BADPARAM;
644 goto EXIT;
645 }
646
647 if (pCtx->nOutbufs <= nIndex) {
648 *pBuffer = NULL;
649 ret = VIDEO_ERROR_BADPARAM;
650 goto EXIT;
651 }
652
653 *pBuffer = (ExynosVideoBuffer *)&pCtx->pOutbuf[nIndex];
654
655 EXIT:
656 return ret;
657 }
658
659 /*
660 * [Decoder Buffer OPS] Set Geometry (Input)
661 */
662 static ExynosVideoErrorType MFC_Decoder_Set_Geometry_Inbuf(
663 void *pHandle,
664 ExynosVideoGeometry *bufferConf)
665 {
666 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
667 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
668
669 struct v4l2_format fmt;
670
671 if (pCtx == NULL) {
672 ALOGE("%s: Video context info must be supplied", __func__);
673 ret = VIDEO_ERROR_BADPARAM;
674 goto EXIT;
675 }
676
677 if (bufferConf == NULL) {
678 ALOGE("%s: Buffer geometry must be supplied", __func__);
679 ret = VIDEO_ERROR_BADPARAM;
680 goto EXIT;
681 }
682
683 memset(&fmt, 0, sizeof(fmt));
684
685 fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
686 fmt.fmt.pix_mp.pixelformat = __CodingType_To_V4L2PixelFormat(bufferConf->eCompressionFormat);
687 fmt.fmt.pix_mp.plane_fmt[0].sizeimage = bufferConf->nSizeImage;
688
689 if (exynos_v4l2_s_fmt(pCtx->hDec, &fmt) != 0) {
690 ret = VIDEO_ERROR_APIFAIL;
691 goto EXIT;
692 }
693
694 memcpy(&pCtx->inbufGeometry, bufferConf, sizeof(pCtx->inbufGeometry));
695
696 EXIT:
697 return ret;
698 }
699
700 /*
701 * [Decoder Buffer OPS] Set Geometry (Output)
702 */
703 static ExynosVideoErrorType MFC_Decoder_Set_Geometry_Outbuf(
704 void *pHandle,
705 ExynosVideoGeometry *bufferConf)
706 {
707 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
708 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
709
710 struct v4l2_format fmt;
711
712 if (pCtx == NULL) {
713 ALOGE("%s: Video context info must be supplied", __func__);
714 ret = VIDEO_ERROR_BADPARAM;
715 goto EXIT;
716 }
717
718 if (bufferConf == NULL) {
719 ALOGE("%s: Buffer geometry must be supplied", __func__);
720 ret = VIDEO_ERROR_BADPARAM;
721 goto EXIT;
722 }
723
724 memset(&fmt, 0, sizeof(fmt));
725
726 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
727 fmt.fmt.pix_mp.pixelformat = __ColorFormatType_To_V4L2PixelFormat(bufferConf->eColorFormat);
728
729 if (exynos_v4l2_s_fmt(pCtx->hDec, &fmt) != 0) {
730 ret = VIDEO_ERROR_APIFAIL;
731 goto EXIT;
732 }
733
734 memcpy(&pCtx->outbufGeometry, bufferConf, sizeof(pCtx->outbufGeometry));
735
736 EXIT:
737 return ret;
738 }
739
740 /*
741 * [Decoder Buffer OPS] Get Geometry (Output)
742 */
743 static ExynosVideoErrorType MFC_Decoder_Get_Geometry_Outbuf(
744 void *pHandle,
745 ExynosVideoGeometry *bufferConf)
746 {
747 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
748 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
749
750 struct v4l2_format fmt;
751 struct v4l2_crop crop;
752
753 if (pCtx == NULL) {
754 ALOGE("%s: Video context info must be supplied", __func__);
755 ret = VIDEO_ERROR_BADPARAM;
756 goto EXIT;
757 }
758
759 if (bufferConf == NULL) {
760 ALOGE("%s: Buffer geometry must be supplied", __func__);
761 ret = VIDEO_ERROR_BADPARAM;
762 goto EXIT;
763 }
764
765 memset(&fmt, 0, sizeof(fmt));
766 memset(&crop, 0, sizeof(crop));
767
768 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
769 if (exynos_v4l2_g_fmt(pCtx->hDec, &fmt) != 0) {
770 ret = VIDEO_ERROR_APIFAIL;
771 goto EXIT;
772 }
773
774 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
775 if (exynos_v4l2_g_crop(pCtx->hDec, &crop) != 0) {
776 ret = VIDEO_ERROR_APIFAIL;
777 goto EXIT;
778 }
779
780 bufferConf->nFrameWidth = fmt.fmt.pix_mp.width;
781 bufferConf->nFrameHeight = fmt.fmt.pix_mp.height;
782
783 bufferConf->cropRect.nTop = crop.c.top;
784 bufferConf->cropRect.nLeft = crop.c.left;
785 bufferConf->cropRect.nWidth = crop.c.width;
786 bufferConf->cropRect.nHeight = crop.c.height;
787
788 EXIT:
789 return ret;
790 }
791
792 /*
793 * [Decoder Buffer OPS] Setup (Input)
794 */
795 static ExynosVideoErrorType MFC_Decoder_Setup_Inbuf(
796 void *pHandle,
797 unsigned int nBufferCount)
798 {
799 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
800 ExynosVideoPlane *pVideoPlane = NULL;
801 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
802
803 struct v4l2_requestbuffers req;
804 struct v4l2_buffer buf;
805 struct v4l2_plane planes[VIDEO_DECODER_INBUF_PLANES];
806 int i;
807
808 if (pCtx == NULL) {
809 ALOGE("%s: Video context info must be supplied", __func__);
810 ret = VIDEO_ERROR_BADPARAM;
811 goto EXIT;
812 }
813
814 if (nBufferCount == 0) {
815 ALOGE("%s: Buffer count must be greater than 0", __func__);
816 ret = VIDEO_ERROR_BADPARAM;
817 goto EXIT;
818 }
819
820 ALOGV("%s: setting up inbufs (%d) shared=%s\n", __func__, nBufferCount,
821 pCtx->bShareInbuf ? "true" : "false");
822
823 memset(&req, 0, sizeof(req));
824
825 req.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
826 req.count = nBufferCount;
827
828 if (pCtx->bShareInbuf == VIDEO_TRUE)
829 req.memory = pCtx->nMemoryType;
830 else
831 req.memory = V4L2_MEMORY_MMAP;
832
833 if (exynos_v4l2_reqbufs(pCtx->hDec, &req) != 0) {
834 ret = VIDEO_ERROR_APIFAIL;
835 goto EXIT;
836 }
837
838 if (req.count != nBufferCount) {
839 ALOGE("%s: asked for %d, got %d\n", __func__, nBufferCount, req.count);
840 ret = VIDEO_ERROR_NOMEM;
841 goto EXIT;
842 }
843
844 pCtx->nInbufs = (int)req.count;
845
846 pCtx->pInbuf = malloc(sizeof(*pCtx->pInbuf) * pCtx->nInbufs);
847 if (pCtx->pInbuf == NULL) {
848 ALOGE("Failed to allocate input buffer context");
849 ret = VIDEO_ERROR_NOMEM;
850 goto EXIT;
851 }
852 memset(pCtx->pInbuf, 0, sizeof(*pCtx->pInbuf) * pCtx->nInbufs);
853
854 memset(&buf, 0, sizeof(buf));
855
856 if (pCtx->bShareInbuf == VIDEO_FALSE) {
857 buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
858 buf.memory = V4L2_MEMORY_MMAP;
859 buf.m.planes = planes;
860 buf.length = VIDEO_DECODER_INBUF_PLANES;
861
862 for (i = 0; i < pCtx->nInbufs; i++) {
863 buf.index = i;
864 if (exynos_v4l2_querybuf(pCtx->hDec, &buf) != 0) {
865 ret = VIDEO_ERROR_APIFAIL;
866 goto EXIT;
867 }
868
869 pVideoPlane = &pCtx->pInbuf[i].planes[0];
870
871 pVideoPlane->addr = mmap(NULL,
872 buf.m.planes[0].length, PROT_READ | PROT_WRITE,
873 MAP_SHARED, pCtx->hDec, buf.m.planes[0].m.mem_offset);
874
875 if (pVideoPlane->addr == MAP_FAILED) {
876 ret = VIDEO_ERROR_MAPFAIL;
877 goto EXIT;
878 }
879
880 pVideoPlane->allocSize = buf.m.planes[0].length;
881 pVideoPlane->dataSize = 0;
882
883 pCtx->pInbuf[i].pGeometry = &pCtx->inbufGeometry;
884 pCtx->pInbuf[i].bQueued = VIDEO_FALSE;
885 pCtx->pInbuf[i].bRegistered = VIDEO_TRUE;
886 }
887 }
888
889 return ret;
890
891 EXIT:
892 if ((pCtx != NULL) && (pCtx->pInbuf != NULL)) {
893 if (pCtx->bShareInbuf == VIDEO_FALSE) {
894 for (i = 0; i < pCtx->nInbufs; i++) {
895 pVideoPlane = &pCtx->pInbuf[i].planes[0];
896 if (pVideoPlane->addr == MAP_FAILED) {
897 pVideoPlane->addr = NULL;
898 break;
899 }
900
901 munmap(pVideoPlane->addr, pVideoPlane->allocSize);
902 }
903 }
904
905 free(pCtx->pInbuf);
906 }
907
908 return ret;
909 }
910
911 /*
912 * [Decoder Buffer OPS] Setup (Output)
913 */
914 static ExynosVideoErrorType MFC_Decoder_Setup_Outbuf(
915 void *pHandle,
916 unsigned int nBufferCount)
917 {
918 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
919 ExynosVideoPlane *pVideoPlane = NULL;
920 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
921
922 struct v4l2_requestbuffers req;
923 struct v4l2_buffer buf;
924 struct v4l2_plane planes[VIDEO_DECODER_OUTBUF_PLANES];
925 int i, j;
926
927 if (pCtx == NULL) {
928 ALOGE("%s: Video context info must be supplied", __func__);
929 ret = VIDEO_ERROR_BADPARAM;
930 goto EXIT;
931 }
932
933 if (nBufferCount == 0) {
934 ALOGE("%s: Buffer count must be greater than 0", __func__);
935 ret = VIDEO_ERROR_BADPARAM;
936 goto EXIT;
937 }
938
939 ALOGV("%s: setting up outbufs (%d) shared=%s\n", __func__, nBufferCount,
940 pCtx->bShareOutbuf ? "true" : "false");
941
942 memset(&req, 0, sizeof(req));
943
944 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
945 req.count = nBufferCount;
946
947 if (pCtx->bShareOutbuf == VIDEO_TRUE)
948 req.memory = pCtx->nMemoryType;
949 else
950 req.memory = V4L2_MEMORY_MMAP;
951
952 if (exynos_v4l2_reqbufs(pCtx->hDec, &req) != 0) {
953 ret = VIDEO_ERROR_APIFAIL;
954 goto EXIT;
955 }
956
957 if (req.count != nBufferCount) {
958 ALOGE("%s: asked for %d, got %d\n", __func__, nBufferCount, req.count);
959 ret = VIDEO_ERROR_NOMEM;
960 goto EXIT;
961 }
962
963 pCtx->nOutbufs = req.count;
964
965 pCtx->pOutbuf = malloc(sizeof(*pCtx->pOutbuf) * pCtx->nOutbufs);
966 if (pCtx->pOutbuf == NULL) {
967 ALOGE("Failed to allocate output buffer context");
968 ret = VIDEO_ERROR_NOMEM;
969 goto EXIT;
970 }
971 memset(pCtx->pOutbuf, 0, sizeof(*pCtx->pOutbuf) * pCtx->nOutbufs);
972
973 memset(&buf, 0, sizeof(buf));
974
975 if (pCtx->bShareOutbuf == VIDEO_FALSE) {
976 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
977 buf.memory = V4L2_MEMORY_MMAP;
978 buf.m.planes = planes;
979 buf.length = VIDEO_DECODER_OUTBUF_PLANES;
980
981 for (i = 0; i < pCtx->nOutbufs; i++) {
982 buf.index = i;
983 if (exynos_v4l2_querybuf(pCtx->hDec, &buf) != 0) {
984 ret = VIDEO_ERROR_APIFAIL;
985 goto EXIT;
986 }
987
988 for (j = 0; j < VIDEO_DECODER_OUTBUF_PLANES; j++) {
989 pVideoPlane = &pCtx->pOutbuf[i].planes[j];
990 pVideoPlane->addr = mmap(NULL,
991 buf.m.planes[j].length, PROT_READ | PROT_WRITE,
992 MAP_SHARED, pCtx->hDec, buf.m.planes[j].m.mem_offset);
993
994 if (pVideoPlane->addr == MAP_FAILED) {
995 ret = VIDEO_ERROR_MAPFAIL;
996 goto EXIT;
997 }
998
999 pVideoPlane->allocSize = buf.m.planes[j].length;
1000 pVideoPlane->dataSize = 0;
1001 }
1002
1003 pCtx->pOutbuf[i].pGeometry = &pCtx->outbufGeometry;
1004 pCtx->pOutbuf[i].bQueued = VIDEO_FALSE;
1005 pCtx->pOutbuf[i].bRegistered = VIDEO_TRUE;
1006 }
1007 }
1008
1009 return ret;
1010
1011 EXIT:
1012 if ((pCtx != NULL) && (pCtx->pOutbuf != NULL)) {
1013 if (pCtx->bShareOutbuf == VIDEO_FALSE) {
1014 for (i = 0; i < pCtx->nOutbufs; i++) {
1015 for (j = 0; j < VIDEO_DECODER_OUTBUF_PLANES; j++) {
1016 pVideoPlane = &pCtx->pOutbuf[i].planes[j];
1017 if (pVideoPlane->addr == MAP_FAILED) {
1018 pVideoPlane->addr = NULL;
1019 break;
1020 }
1021
1022 munmap(pVideoPlane->addr, pVideoPlane->allocSize);
1023 }
1024 }
1025 }
1026
1027 free(pCtx->pOutbuf);
1028 }
1029
1030 return ret;
1031 }
1032
1033 /*
1034 * [Decoder Buffer OPS] Run (Input)
1035 */
1036 static ExynosVideoErrorType MFC_Decoder_Run_Inbuf(void *pHandle)
1037 {
1038 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1039 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
1040
1041 if (pCtx == NULL) {
1042 ALOGE("%s: Video context info must be supplied", __func__);
1043 ret = VIDEO_ERROR_BADPARAM;
1044 goto EXIT;
1045 }
1046
1047 if (pCtx->bStreamonInbuf == VIDEO_FALSE) {
1048 if (exynos_v4l2_streamon(pCtx->hDec, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) != 0) {
1049 ALOGE("%s: Failed to streamon for input buffer", __func__);
1050 ret = VIDEO_ERROR_APIFAIL;
1051 goto EXIT;
1052 }
1053 pCtx->bStreamonInbuf = VIDEO_TRUE;
1054 }
1055
1056 EXIT:
1057 return ret;
1058 }
1059
1060 /*
1061 * [Decoder Buffer OPS] Run (Output)
1062 */
1063 static ExynosVideoErrorType MFC_Decoder_Run_Outbuf(void *pHandle)
1064 {
1065 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1066 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
1067
1068 if (pCtx == NULL) {
1069 ALOGE("%s: Video context info must be supplied", __func__);
1070 ret = VIDEO_ERROR_BADPARAM;
1071 goto EXIT;
1072 }
1073
1074 if (pCtx->bStreamonOutbuf == VIDEO_FALSE) {
1075 if (exynos_v4l2_streamon(pCtx->hDec, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) != 0) {
1076 ALOGE("%s: Failed to streamon for output buffer", __func__);
1077 ret = VIDEO_ERROR_APIFAIL;
1078 goto EXIT;
1079 }
1080 pCtx->bStreamonOutbuf = VIDEO_TRUE;
1081 }
1082
1083 EXIT:
1084 return ret;
1085 }
1086
1087 /*
1088 * [Decoder Buffer OPS] Stop (Input)
1089 */
1090 static ExynosVideoErrorType MFC_Decoder_Stop_Inbuf(void *pHandle)
1091 {
1092 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1093 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
1094 int i = 0;
1095
1096 if (pCtx == NULL) {
1097 ALOGE("%s: Video context info must be supplied", __func__);
1098 ret = VIDEO_ERROR_BADPARAM;
1099 goto EXIT;
1100 }
1101
1102 if (pCtx->bStreamonInbuf == VIDEO_TRUE) {
1103 if (exynos_v4l2_streamoff(pCtx->hDec, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) != 0) {
1104 ALOGE("%s: Failed to streamoff for input buffer", __func__);
1105 ret = VIDEO_ERROR_APIFAIL;
1106 goto EXIT;
1107 }
1108 pCtx->bStreamonInbuf = VIDEO_FALSE;
1109 }
1110
1111 for (i = 0; i < pCtx->nInbufs; i++) {
1112 pCtx->pInbuf[i].bQueued = VIDEO_FALSE;
1113 }
1114
1115 EXIT:
1116 return ret;
1117 }
1118
1119 /*
1120 * [Decoder Buffer OPS] Stop (Output)
1121 */
1122 static ExynosVideoErrorType MFC_Decoder_Stop_Outbuf(void *pHandle)
1123 {
1124 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1125 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
1126 int i = 0;
1127
1128 if (pCtx == NULL) {
1129 ALOGE("%s: Video context info must be supplied", __func__);
1130 ret = VIDEO_ERROR_BADPARAM;
1131 goto EXIT;
1132 }
1133
1134 if (pCtx->bStreamonOutbuf == VIDEO_TRUE) {
1135 if (exynos_v4l2_streamoff(pCtx->hDec, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) != 0) {
1136 ALOGE("%s: Failed to streamoff for output buffer", __func__);
1137 ret = VIDEO_ERROR_APIFAIL;
1138 goto EXIT;
1139 }
1140 pCtx->bStreamonOutbuf = VIDEO_FALSE;
1141 }
1142
1143 for (i = 0; i < pCtx->nOutbufs; i++) {
1144 pCtx->pOutbuf[i].bQueued = VIDEO_FALSE;
1145 }
1146
1147 EXIT:
1148 return ret;
1149 }
1150
1151 /*
1152 * [Decoder Buffer OPS] Wait (Input)
1153 */
1154 static ExynosVideoErrorType MFC_Decoder_Wait_Inbuf(void *pHandle)
1155 {
1156 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1157 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
1158
1159 struct pollfd poll_events;
1160 int poll_state;
1161
1162 if (pCtx == NULL) {
1163 ALOGE("%s: Video context info must be supplied", __func__);
1164 ret = VIDEO_ERROR_BADPARAM;
1165 goto EXIT;
1166 }
1167
1168 poll_events.fd = pCtx->hDec;
1169 poll_events.events = POLLOUT | POLLERR;
1170 poll_events.revents = 0;
1171
1172 do {
1173 poll_state = poll((struct pollfd*)&poll_events, 1, VIDEO_DECODER_POLL_TIMEOUT);
1174 if (poll_state > 0) {
1175 if (poll_events.revents & POLLOUT) {
1176 break;
1177 } else {
1178 ALOGE("%s: Poll return error", __func__);
1179 ret = VIDEO_ERROR_POLL;
1180 break;
1181 }
1182 } else if (poll_state < 0) {
1183 ALOGE("%s: Poll state error", __func__);
1184 ret = VIDEO_ERROR_POLL;
1185 break;
1186 }
1187 } while (poll_state == 0);
1188
1189 EXIT:
1190 return ret;
1191 }
1192
1193 static ExynosVideoErrorType MFC_Decoder_Register_Inbuf(
1194 void *pHandle,
1195 ExynosVideoPlane *planes,
1196 int nPlanes)
1197 {
1198 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1199 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
1200 int nIndex, plane;
1201
1202 if ((pCtx == NULL) || (planes == NULL) || (nPlanes != VIDEO_DECODER_INBUF_PLANES)) {
1203 ALOGE("%s: params must be supplied", __func__);
1204 ret = VIDEO_ERROR_BADPARAM;
1205 goto EXIT;
1206 }
1207
1208 for (nIndex = 0; nIndex < pCtx->nInbufs; nIndex++) {
1209 if (pCtx->pInbuf[nIndex].bRegistered == VIDEO_FALSE) {
1210 for (plane = 0; plane < nPlanes; plane++) {
1211 pCtx->pInbuf[nIndex].planes[plane].addr = planes[plane].addr;
1212 pCtx->pInbuf[nIndex].planes[plane].allocSize = planes[plane].allocSize;
1213 pCtx->pInbuf[nIndex].planes[plane].fd = planes[plane].fd;
1214 ALOGV("%s: registered buf %d (addr=%p alloc_sz=%ld fd=%d)\n", __func__, nIndex,
1215 planes[plane].addr, planes[plane].allocSize, planes[plane].fd);
1216 }
1217 pCtx->pInbuf[nIndex].bRegistered = VIDEO_TRUE;
1218 break;
1219 }
1220 }
1221
1222 if (nIndex == pCtx->nInbufs) {
1223 ALOGE("%s: can not find non-registered input buffer", __func__);
1224 ret = VIDEO_ERROR_NOBUFFERS;
1225 }
1226
1227 EXIT:
1228 return ret;
1229 }
1230
1231 static ExynosVideoErrorType MFC_Decoder_Register_Outbuf(
1232 void *pHandle,
1233 ExynosVideoPlane *planes,
1234 int nPlanes)
1235 {
1236 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1237 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
1238 int nIndex, plane;
1239
1240 if ((pCtx == NULL) || (planes == NULL) || (nPlanes != VIDEO_DECODER_OUTBUF_PLANES)) {
1241 ALOGE("%s: params must be supplied", __func__);
1242 ret = VIDEO_ERROR_BADPARAM;
1243 goto EXIT;
1244 }
1245
1246 for (nIndex = 0; nIndex < pCtx->nOutbufs; nIndex++) {
1247 if (pCtx->pOutbuf[nIndex].bRegistered == VIDEO_FALSE) {
1248 for (plane = 0; plane < nPlanes; plane++) {
1249 pCtx->pOutbuf[nIndex].planes[plane].addr = planes[plane].addr;
1250 pCtx->pOutbuf[nIndex].planes[plane].allocSize = planes[plane].allocSize;
1251 pCtx->pOutbuf[nIndex].planes[plane].fd = planes[plane].fd;
1252 }
1253 pCtx->pOutbuf[nIndex].bRegistered = VIDEO_TRUE;
1254 ALOGV("%s: registered buf %d 0:(addr=%p alloc_sz=%d fd=%d) 1:(addr=%p alloc_sz=%d fd=%d)\n",
1255 __func__, nIndex, planes[0].addr, planes[0].allocSize, planes[0].fd,
1256 planes[1].addr, planes[1].allocSize, planes[1].fd);
1257 break;
1258 }
1259 }
1260
1261 if (nIndex == pCtx->nOutbufs) {
1262 ALOGE("%s: can not find non-registered output buffer", __func__);
1263 ret = VIDEO_ERROR_NOBUFFERS;
1264 }
1265
1266 EXIT:
1267 return ret;
1268 }
1269
1270 static ExynosVideoErrorType MFC_Decoder_Clear_RegisteredBuffer_Inbuf(void *pHandle)
1271 {
1272 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1273 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
1274 int nIndex;
1275
1276 if (pCtx == NULL) {
1277 ALOGE("%s: Video context info must be supplied", __func__);
1278 ret = VIDEO_ERROR_BADPARAM;
1279 goto EXIT;
1280 }
1281
1282 for (nIndex = 0; nIndex < pCtx->nInbufs; nIndex++) {
1283 pCtx->pInbuf[nIndex].planes[0].addr = NULL;
1284 pCtx->pInbuf[nIndex].bRegistered = VIDEO_FALSE;
1285 }
1286
1287 EXIT:
1288 return ret;
1289 }
1290
1291 static ExynosVideoErrorType MFC_Decoder_Clear_RegisteredBuffer_Outbuf(void *pHandle)
1292 {
1293 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1294 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
1295 int nIndex;
1296
1297 if (pCtx == NULL) {
1298 ALOGE("%s: Video context info must be supplied", __func__);
1299 ret = VIDEO_ERROR_BADPARAM;
1300 goto EXIT;
1301 }
1302
1303 for (nIndex = 0; nIndex < pCtx->nOutbufs; nIndex++) {
1304 pCtx->pOutbuf[nIndex].planes[0].addr = NULL;
1305 pCtx->pOutbuf[nIndex].bRegistered = VIDEO_FALSE;
1306 }
1307
1308 EXIT:
1309 return ret;
1310 }
1311
1312 /*
1313 * [Decoder Buffer OPS] Find (Input)
1314 */
1315 static int MFC_Decoder_Find_Inbuf(
1316 void *pHandle,
1317 unsigned char *pBuffer)
1318 {
1319 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1320 int nIndex = -1;
1321
1322 if (pCtx == NULL) {
1323 ALOGE("%s: Video context info must be supplied", __func__);
1324 goto EXIT;
1325 }
1326
1327 for (nIndex = 0; nIndex < pCtx->nInbufs; nIndex++) {
1328 if (pCtx->pInbuf[nIndex].bQueued == VIDEO_FALSE) {
1329 if ((pBuffer == NULL) ||
1330 (pCtx->pInbuf[nIndex].planes[0].addr == pBuffer))
1331 break;
1332 }
1333 }
1334
1335 if (nIndex == pCtx->nInbufs)
1336 nIndex = -1;
1337
1338 EXIT:
1339 return nIndex;
1340 }
1341
1342 /*
1343 * [Decoder Buffer OPS] Find (Outnput)
1344 */
1345 static int MFC_Decoder_Find_Outbuf(
1346 void *pHandle,
1347 unsigned char *pBuffer)
1348 {
1349 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1350 int nIndex = -1;
1351
1352 if (pCtx == NULL) {
1353 ALOGE("%s: Video context info must be supplied", __func__);
1354 goto EXIT;
1355 }
1356
1357 for (nIndex = 0; nIndex < pCtx->nOutbufs; nIndex++) {
1358 if (pCtx->pOutbuf[nIndex].bQueued == VIDEO_FALSE) {
1359 if ((pBuffer == NULL) ||
1360 (pCtx->pOutbuf[nIndex].planes[0].addr == pBuffer))
1361 break;
1362 }
1363 }
1364
1365 if (nIndex == pCtx->nOutbufs)
1366 nIndex = -1;
1367
1368 EXIT:
1369 return nIndex;
1370 }
1371
1372 /*
1373 * [Decoder Buffer OPS] Enqueue (Input)
1374 */
1375 static ExynosVideoErrorType MFC_Decoder_Enqueue_Inbuf(
1376 void *pHandle,
1377 unsigned char *pBuffer[],
1378 unsigned int dataSize[],
1379 int nPlanes,
1380 void *pPrivate)
1381 {
1382 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1383 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
1384 pthread_mutex_t *pMutex = NULL;
1385
1386 struct v4l2_plane planes[VIDEO_DECODER_INBUF_PLANES];
1387 struct v4l2_buffer buf;
1388 int index, i;
1389
1390 if (pCtx == NULL) {
1391 ALOGE("%s: Video context info must be supplied", __func__);
1392 ret = VIDEO_ERROR_BADPARAM;
1393 goto EXIT;
1394 }
1395
1396 if (VIDEO_DECODER_INBUF_PLANES < nPlanes) {
1397 ALOGE("%s: Number of max planes : %d, nPlanes : %d", __func__,
1398 VIDEO_DECODER_INBUF_PLANES, nPlanes);
1399 ret = VIDEO_ERROR_BADPARAM;
1400 goto EXIT;
1401 }
1402
1403 memset(&buf, 0, sizeof(buf));
1404
1405 buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1406 buf.m.planes = planes;
1407 buf.length = VIDEO_DECODER_INBUF_PLANES;
1408
1409 pMutex = (pthread_mutex_t*)pCtx->pInMutex;
1410 pthread_mutex_lock(pMutex);
1411 index = MFC_Decoder_Find_Inbuf(pCtx, pBuffer[0]);
1412 if (index == -1) {
1413 pthread_mutex_unlock(pMutex);
1414 ALOGE("%s: Failed to get index", __func__);
1415 ret = VIDEO_ERROR_NOBUFFERS;
1416 goto EXIT;
1417 }
1418
1419 buf.index = index;
1420 pCtx->pInbuf[buf.index].bQueued = VIDEO_TRUE;
1421 pthread_mutex_unlock(pMutex);
1422
1423 if (pCtx->bShareInbuf == VIDEO_TRUE) {
1424 buf.memory = pCtx->nMemoryType;
1425 for (i = 0; i < nPlanes; i++) {
1426 /* V4L2_MEMORY_USERPTR */
1427 buf.m.planes[i].m.userptr = (unsigned long)pBuffer[i];
1428 /* V4L2_MEMORY_DMABUF */
1429 buf.m.planes[i].m.fd = pCtx->pInbuf[index].planes[i].fd;
1430 buf.m.planes[i].length = pCtx->pInbuf[index].planes[i].allocSize;
1431 buf.m.planes[i].bytesused = dataSize[i];
1432 ALOGV("%s: shared inbuf(%d) plane(%d) addr=%p fd=%d len=%d used=%d\n", __func__,
1433 index, i,
1434 buf.m.planes[i].m.userptr,
1435 buf.m.planes[i].m.fd,
1436 buf.m.planes[i].length,
1437 buf.m.planes[i].bytesused);
1438 }
1439 } else {
1440 buf.memory = V4L2_MEMORY_MMAP;
1441 for (i = 0; i < nPlanes; i++)
1442 buf.m.planes[i].bytesused = dataSize[i];
1443 }
1444
1445 if ((((OMX_BUFFERHEADERTYPE *)pPrivate)->nFlags & OMX_BUFFERFLAG_EOS) == OMX_BUFFERFLAG_EOS) {
1446 buf.flags |= V4L2_BUF_FLAG_LAST_FRAME;
1447 ALOGD("%s: OMX_BUFFERFLAG_EOS => LAST_FRAME: 0x%x", __func__,
1448 !!(buf.flags & V4L2_BUF_FLAG_LAST_FRAME));
1449 }
1450
1451 if (exynos_v4l2_qbuf(pCtx->hDec, &buf) != 0) {
1452 ALOGE("%s: Failed to enqueue input buffer", __func__);
1453 pCtx->pInbuf[buf.index].bQueued = VIDEO_FALSE;
1454 ret = VIDEO_ERROR_APIFAIL;
1455 goto EXIT;
1456 }
1457
1458 pCtx->pInbuf[buf.index].pPrivate = pPrivate;
1459
1460 EXIT:
1461 return ret;
1462 }
1463
1464 /*
1465 * [Decoder Buffer OPS] Enqueue (Output)
1466 */
1467 static ExynosVideoErrorType MFC_Decoder_Enqueue_Outbuf(
1468 void *pHandle,
1469 unsigned char *pBuffer[],
1470 unsigned int dataSize[],
1471 int nPlanes,
1472 void *pPrivate)
1473 {
1474 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1475 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
1476 pthread_mutex_t *pMutex = NULL;
1477
1478 struct v4l2_plane planes[VIDEO_DECODER_OUTBUF_PLANES];
1479 struct v4l2_buffer buf;
1480 int i, index;
1481
1482 if (pCtx == NULL) {
1483 ALOGE("%s: Video context info must be supplied", __func__);
1484 ret = VIDEO_ERROR_BADPARAM;
1485 goto EXIT;
1486 }
1487
1488 if (VIDEO_DECODER_OUTBUF_PLANES < nPlanes) {
1489 ALOGE("%s: Number of max planes : %d, nPlanes : %d", __func__,
1490 VIDEO_DECODER_OUTBUF_PLANES, nPlanes);
1491 ret = VIDEO_ERROR_BADPARAM;
1492 goto EXIT;
1493 }
1494
1495 memset(&buf, 0, sizeof(buf));
1496 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1497 buf.m.planes = planes;
1498 buf.length = VIDEO_DECODER_OUTBUF_PLANES;
1499
1500 pMutex = (pthread_mutex_t*)pCtx->pOutMutex;
1501 pthread_mutex_lock(pMutex);
1502 index = MFC_Decoder_Find_Outbuf(pCtx, pBuffer[0]);
1503 if (index == -1) {
1504 pthread_mutex_unlock(pMutex);
1505 ALOGE("%s: Failed to get index", __func__);
1506 ret = VIDEO_ERROR_NOBUFFERS;
1507 goto EXIT;
1508 }
1509 buf.index = index;
1510 pCtx->pOutbuf[buf.index].bQueued = VIDEO_TRUE;
1511 pthread_mutex_unlock(pMutex);
1512
1513 if (pCtx->bShareOutbuf == VIDEO_TRUE) {
1514 buf.memory = pCtx->nMemoryType;
1515 for (i = 0; i < nPlanes; i++) {
1516 /* V4L2_MEMORY_USERPTR */
1517 buf.m.planes[i].m.userptr = (unsigned long)pBuffer[i];
1518 /* V4L2_MEMORY_DMABUF */
1519 buf.m.planes[i].m.fd = pCtx->pOutbuf[index].planes[i].fd;
1520 buf.m.planes[i].length = pCtx->pOutbuf[index].planes[i].allocSize;
1521 buf.m.planes[i].bytesused = dataSize[i];
1522 ALOGV("%s: shared outbuf(%d) plane=%d addr=%p fd=%d len=%d used=%d\n", __func__,
1523 index, i,
1524 buf.m.planes[i].m.userptr,
1525 buf.m.planes[i].m.fd,
1526 buf.m.planes[i].length,
1527 buf.m.planes[i].bytesused);
1528 }
1529 } else {
1530 ALOGV("%s: non-shared outbuf(%d)\n", __func__, index);
1531 buf.memory = V4L2_MEMORY_MMAP;
1532 }
1533
1534 if (exynos_v4l2_qbuf(pCtx->hDec, &buf) != 0) {
1535 ALOGE("%s: Failed to enqueue output buffer", __func__);
1536 pCtx->pOutbuf[buf.index].bQueued = VIDEO_FALSE;
1537 ret = VIDEO_ERROR_APIFAIL;
1538 goto EXIT;
1539 }
1540
1541 pCtx->pOutbuf[buf.index].pPrivate = pPrivate;
1542
1543 EXIT:
1544 return ret;
1545 }
1546
1547 /*
1548 * [Decoder Buffer OPS] Dequeue (Input)
1549 */
1550 static ExynosVideoBuffer *MFC_Decoder_Dequeue_Inbuf(void *pHandle)
1551 {
1552 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1553 ExynosVideoBuffer *pInbuf = NULL;
1554
1555 struct v4l2_buffer buf;
1556
1557 if (pCtx == NULL) {
1558 ALOGE("%s: Video context info must be supplied", __func__);
1559 goto EXIT;
1560 }
1561
1562 if (pCtx->bStreamonInbuf == VIDEO_FALSE) {
1563 pInbuf = NULL;
1564 goto EXIT;
1565 }
1566
1567 memset(&buf, 0, sizeof(buf));
1568
1569 buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1570
1571 if (pCtx->bShareInbuf == VIDEO_TRUE)
1572 buf.memory = pCtx->nMemoryType;
1573 else
1574 buf.memory = V4L2_MEMORY_MMAP;
1575
1576 if (exynos_v4l2_dqbuf(pCtx->hDec, &buf) != 0) {
1577 pInbuf = NULL;
1578 goto EXIT;
1579 }
1580
1581 pInbuf = &pCtx->pInbuf[buf.index];
1582 pCtx->pInbuf[buf.index].bQueued = VIDEO_FALSE;
1583
1584 if (pCtx->bStreamonInbuf == VIDEO_FALSE)
1585 pInbuf = NULL;
1586
1587 EXIT:
1588 return pInbuf;
1589 }
1590
1591 /*
1592 * [Decoder Buffer OPS] Dequeue (Output)
1593 */
1594 static ExynosVideoBuffer *MFC_Decoder_Dequeue_Outbuf(void *pHandle)
1595 {
1596 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1597 ExynosVideoBuffer *pOutbuf = NULL;
1598
1599 struct v4l2_buffer buf;
1600 int value;
1601
1602 if (pCtx == NULL) {
1603 ALOGE("%s: Video context info must be supplied", __func__);
1604 goto EXIT;
1605 }
1606
1607 if (pCtx->bStreamonOutbuf == VIDEO_FALSE) {
1608 pOutbuf = NULL;
1609 goto EXIT;
1610 }
1611
1612 memset(&buf, 0, sizeof(buf));
1613 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1614
1615 if (pCtx->bShareOutbuf == VIDEO_TRUE)
1616 buf.memory = pCtx->nMemoryType;
1617 else
1618 buf.memory = V4L2_MEMORY_MMAP;
1619
1620 /* HACK: pOutbuf return -1 means DECODING_ONLY for almost cases */
1621 if (exynos_v4l2_dqbuf(pCtx->hDec, &buf) != 0) {
1622 pOutbuf = NULL;
1623 goto EXIT;
1624 }
1625
1626 if (pCtx->bStreamonOutbuf == VIDEO_FALSE) {
1627 pOutbuf = NULL;
1628 goto EXIT;
1629 }
1630
1631 pOutbuf = &pCtx->pOutbuf[buf.index];
1632
1633 exynos_v4l2_g_ctrl(pCtx->hDec, V4L2_CID_MPEG_MFC51_VIDEO_DISPLAY_STATUS, &value);
1634
1635 switch (value) {
1636 case 0:
1637 pOutbuf->displayStatus = VIDEO_FRAME_STATUS_DECODING_ONLY;
1638 break;
1639 case 1:
1640 pOutbuf->displayStatus = VIDEO_FRAME_STATUS_DISPLAY_DECODING;
1641 break;
1642 case 2:
1643 pOutbuf->displayStatus = VIDEO_FRAME_STATUS_DISPLAY_ONLY;
1644 break;
1645 case 3:
1646 pOutbuf->displayStatus = VIDEO_FRAME_STATUS_CHANGE_RESOL;
1647 break;
1648 default:
1649 pOutbuf->displayStatus = VIDEO_FRAME_STATUS_UNKNOWN;
1650 break;
1651 }
1652
1653 switch (buf.flags & (0x7 << 3)) {
1654 case V4L2_BUF_FLAG_KEYFRAME:
1655 pOutbuf->frameType = VIDEO_FRAME_I;
1656 break;
1657 case V4L2_BUF_FLAG_PFRAME:
1658 pOutbuf->frameType = VIDEO_FRAME_P;
1659 break;
1660 case V4L2_BUF_FLAG_BFRAME:
1661 pOutbuf->frameType = VIDEO_FRAME_B;
1662 break;
1663 default:
1664 pOutbuf->frameType = VIDEO_FRAME_OTHERS;
1665 break;
1666 };
1667
1668 pOutbuf->bQueued = VIDEO_FALSE;
1669
1670 EXIT:
1671 return pOutbuf;
1672 }
1673
1674 static ExynosVideoErrorType MFC_Decoder_Clear_Queued_Inbuf(void *pHandle)
1675 {
1676 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1677 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
1678 int i;
1679
1680 if (pCtx == NULL) {
1681 ALOGE("%s: Video context info must be supplied", __func__);
1682 ret = VIDEO_ERROR_BADPARAM;
1683 goto EXIT;
1684 }
1685
1686 for (i = 0; i < pCtx->nInbufs; i++) {
1687 pCtx->pInbuf[i].bQueued = VIDEO_FALSE;
1688 }
1689
1690 EXIT:
1691 return ret;
1692 }
1693
1694 static ExynosVideoErrorType MFC_Decoder_Clear_Queued_Outbuf(void *pHandle)
1695 {
1696 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1697 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
1698 int i;
1699
1700 if (pCtx == NULL) {
1701 ALOGE("%s: Video context info must be supplied", __func__);
1702 ret = VIDEO_ERROR_BADPARAM;
1703 goto EXIT;
1704 }
1705
1706 for (i = 0; i < pCtx->nOutbufs; i++) {
1707 pCtx->pOutbuf[i].bQueued = VIDEO_FALSE;
1708 }
1709
1710 EXIT:
1711 return ret;
1712 }
1713
1714 /*
1715 * [Decoder OPS] Common
1716 */
1717 static ExynosVideoDecOps defDecOps = {
1718 .nSize = 0,
1719 .Init = MFC_Decoder_Init,
1720 .Finalize = MFC_Decoder_Finalize,
1721 .Set_DisplayDelay = MFC_Decoder_Set_DisplayDelay,
1722 .Enable_PackedPB = MFC_Decoder_Enable_PackedPB,
1723 .Enable_LoopFilter = MFC_Decoder_Enable_LoopFilter,
1724 .Enable_SliceMode = MFC_Decoder_Enable_SliceMode,
1725 .Get_ActualBufferCount = MFC_Decoder_Get_ActualBufferCount,
1726 .Set_FrameTag = MFC_Decoder_Set_FrameTag,
1727 .Get_FrameTag = MFC_Decoder_Get_FrameTag,
1728 .Enable_SEIParsing = MFC_Decoder_Enable_SEIParsing,
1729 .Get_FramePackingInfo = MFC_Decoder_Get_FramePackingInfo,
1730 };
1731
1732 /*
1733 * [Decoder Buffer OPS] Input
1734 */
1735 static ExynosVideoDecBufferOps defInbufOps = {
1736 .nSize = 0,
1737 .Enable_Cacheable = MFC_Decoder_Enable_Cacheable_Inbuf,
1738 .Set_Shareable = MFC_Decoder_Set_Shareable_Inbuf,
1739 .Get_Buffer = NULL,
1740 .Set_Geometry = MFC_Decoder_Set_Geometry_Inbuf,
1741 .Get_Geometry = NULL,
1742 .Setup = MFC_Decoder_Setup_Inbuf,
1743 .Run = MFC_Decoder_Run_Inbuf,
1744 .Stop = MFC_Decoder_Stop_Inbuf,
1745 .Enqueue = MFC_Decoder_Enqueue_Inbuf,
1746 .Enqueue_All = NULL,
1747 .Dequeue = MFC_Decoder_Dequeue_Inbuf,
1748 .Register = MFC_Decoder_Register_Inbuf,
1749 .Clear_RegisteredBuffer = MFC_Decoder_Clear_RegisteredBuffer_Inbuf,
1750 .Clear_Queue = MFC_Decoder_Clear_Queued_Inbuf,
1751 };
1752
1753 /*
1754 * [Decoder Buffer OPS] Output
1755 */
1756 static ExynosVideoDecBufferOps defOutbufOps = {
1757 .nSize = 0,
1758 .Enable_Cacheable = MFC_Decoder_Enable_Cacheable_Outbuf,
1759 .Set_Shareable = MFC_Decoder_Set_Shareable_Outbuf,
1760 .Get_Buffer = MFC_Decoder_Get_Buffer_Outbuf,
1761 .Set_Geometry = MFC_Decoder_Set_Geometry_Outbuf,
1762 .Get_Geometry = MFC_Decoder_Get_Geometry_Outbuf,
1763 .Setup = MFC_Decoder_Setup_Outbuf,
1764 .Run = MFC_Decoder_Run_Outbuf,
1765 .Stop = MFC_Decoder_Stop_Outbuf,
1766 .Enqueue = MFC_Decoder_Enqueue_Outbuf,
1767 .Enqueue_All = NULL,
1768 .Dequeue = MFC_Decoder_Dequeue_Outbuf,
1769 .Register = MFC_Decoder_Register_Outbuf,
1770 .Clear_RegisteredBuffer = MFC_Decoder_Clear_RegisteredBuffer_Outbuf,
1771 .Clear_Queue = MFC_Decoder_Clear_Queued_Outbuf,
1772 };
1773
1774 int Exynos_Video_Register_Decoder(
1775 ExynosVideoDecOps *pDecOps,
1776 ExynosVideoDecBufferOps *pInbufOps,
1777 ExynosVideoDecBufferOps *pOutbufOps)
1778 {
1779 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
1780
1781 if ((pDecOps == NULL) || (pInbufOps == NULL) || (pOutbufOps == NULL)) {
1782 ret = VIDEO_ERROR_BADPARAM;
1783 goto EXIT;
1784 }
1785
1786 defDecOps.nSize = sizeof(defDecOps);
1787 defInbufOps.nSize = sizeof(defInbufOps);
1788 defOutbufOps.nSize = sizeof(defOutbufOps);
1789
1790 memcpy((char *)pDecOps + sizeof(pDecOps->nSize), (char *)&defDecOps + sizeof(defDecOps.nSize),
1791 pDecOps->nSize - sizeof(pDecOps->nSize));
1792
1793 memcpy((char *)pInbufOps + sizeof(pInbufOps->nSize), (char *)&defInbufOps + sizeof(defInbufOps.nSize),
1794 pInbufOps->nSize - sizeof(pInbufOps->nSize));
1795
1796 memcpy((char *)pOutbufOps + sizeof(pOutbufOps->nSize), (char *)&defOutbufOps + sizeof(defOutbufOps.nSize),
1797 pOutbufOps->nSize - sizeof(pOutbufOps->nSize));
1798
1799 EXIT:
1800 return ret;
1801 }