blob: 2a4bf6f604e4c1798f8f4fb8660c0ceaf657190d [file] [log] [blame]
Jiho Chang20d3e6e2012-03-24 03:43:08 +09001/*
2 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com/
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22/*
23 * @file ExynosVideoDecoder.c
24 * @brief
25 * @author Jinsung Yang (jsgood.yang@samsung.com)
26 * @version 1.0.0
27 * @history
28 * 2012.01.15: Initial Version
29 */
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <unistd.h>
34#include <string.h>
35#include <fcntl.h>
36
37#include <sys/types.h>
38#include <sys/stat.h>
39#include <sys/ioctl.h>
40#include <sys/mman.h>
41
42#include <sys/poll.h>
43
44#include "ExynosVideoApi.h"
45#include "ExynosVideoDec.h"
46#include "exynos_v4l2.h"
47
48/* #define LOG_NDEBUG 0 */
49#define LOG_TAG "ExynosVideoDecoder"
50#include <utils/Log.h>
51
52/*
53 * [Common] __CodingType_To_V4L2PixelFormat
54 */
55static unsigned int __CodingType_To_V4L2PixelFormat(ExynosVideoCodingType codingType)
56{
57 unsigned int pixelformat = V4L2_PIX_FMT_H264;
58
59 switch (codingType) {
60 case VIDEO_CODING_AVC:
61 pixelformat = V4L2_PIX_FMT_H264;
62 break;
63 case VIDEO_CODING_MPEG4:
64 pixelformat = V4L2_PIX_FMT_MPEG4;
65 break;
66 case VIDEO_CODING_VP8:
67 pixelformat = V4L2_PIX_FMT_VP8;
68 break;
69 case VIDEO_CODING_H263:
70 pixelformat = V4L2_PIX_FMT_H263;
71 break;
72 case VIDEO_CODING_VC1:
73 pixelformat = V4L2_PIX_FMT_VC1_ANNEX_G;
74 break;
75 case VIDEO_CODING_VC1_RCV:
76 pixelformat = V4L2_PIX_FMT_VC1_ANNEX_L;
77 break;
78 case VIDEO_CODING_MPEG2:
79 pixelformat = V4L2_PIX_FMT_MPEG1;
80 break;
81 default:
82 pixelformat = V4L2_PIX_FMT_H264;
83 break;
84 }
85
86 return pixelformat;
87}
88
89/*
90 * [Common] __ColorFormatType_To_V4L2PixelFormat
91 */
92static unsigned int __ColorFormatType_To_V4L2PixelFormat(ExynosVideoColorFormatType colorFormatType)
93{
94 unsigned int pixelformat = V4L2_PIX_FMT_NV12M;
95
96 switch (colorFormatType) {
97 case VIDEO_COLORFORMAT_NV12_TILED:
98 pixelformat = V4L2_PIX_FMT_NV12MT_16X16;
99 break;
100 case VIDEO_COLORFORMAT_NV21:
101 pixelformat = V4L2_PIX_FMT_NV21M;
102 break;
103 case VIDEO_COLORFORMAT_NV12:
104 default:
105 pixelformat = V4L2_PIX_FMT_NV12M;
106 break;
107 }
108
109 return pixelformat;
110}
111
112/*
113 * [Decoder OPS] Init
114 */
115static void *MFC_Decoder_Init(void)
116{
117 ExynosVideoDecContext *pCtx = NULL;
118 int needCaps = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING);
119
120 pCtx = (ExynosVideoDecContext *)malloc(sizeof(*pCtx));
121 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700122 ALOGE("%s: Failed to allocate decoder context buffer", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900123 goto EXIT_ALLOC_FAIL;
124 }
125
126 memset(pCtx, 0, sizeof(*pCtx));
127
128 pCtx->hDec = exynos_v4l2_open_devname(VIDEO_DECODER_NAME, O_RDWR | O_NONBLOCK, 0);
129 if (pCtx->hDec < 0) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700130 ALOGE("%s: Failed to open decoder device", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900131 goto EXIT_OPEN_FAIL;
132 }
133
134 if (!exynos_v4l2_querycap(pCtx->hDec, needCaps)) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700135 ALOGE("%s: Failed to querycap", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900136 goto EXIT_QUERYCAP_FAIL;
137 }
138
139 pCtx->bStreamonInbuf = VIDEO_FALSE;
140 pCtx->bStreamonOutbuf = VIDEO_FALSE;
141
142 return (void *)pCtx;
143
144EXIT_QUERYCAP_FAIL:
145 close(pCtx->hDec);
146
147EXIT_OPEN_FAIL:
148 free(pCtx);
149 pCtx = NULL;
150
151EXIT_ALLOC_FAIL:
152 return NULL;
153}
154
155/*
156 * [Decoder OPS] Finalize
157 */
158static ExynosVideoErrorType MFC_Decoder_Finalize(void *pHandle)
159{
160 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
161 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
162 ExynosVideoPlane *pVideoPlane;
163
164 int i, j;
165
166 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700167 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900168 ret = VIDEO_ERROR_BADPARAM;
169 goto EXIT;
170 }
171
172 if (pCtx->bShareInbuf == VIDEO_FALSE) {
173 for (i = 0; i < pCtx->nInbufs; i++) {
174 for (j = 0; j < VIDEO_DECODER_INBUF_PLANES; j++) {
175 pVideoPlane = &pCtx->pInbuf[i].planes[j];
176 if (pVideoPlane->addr != NULL) {
177 munmap(pVideoPlane->addr, pVideoPlane->allocSize);
178 pVideoPlane->addr = NULL;
179 pVideoPlane->allocSize = 0;
180 pVideoPlane->dataSize = 0;
181 }
182
183 pCtx->pInbuf[i].pGeometry = NULL;
184 pCtx->pInbuf[i].bQueued = VIDEO_FALSE;
185 }
186 }
187 }
188
189 if (pCtx->bShareOutbuf == VIDEO_FALSE) {
190 for (i = 0; i < pCtx->nOutbufs; i++) {
191 for (j = 0; j < VIDEO_DECODER_OUTBUF_PLANES; j++) {
192 pVideoPlane = &pCtx->pOutbuf[i].planes[j];
193 if (pVideoPlane->addr != NULL) {
194 munmap(pVideoPlane->addr, pVideoPlane->allocSize);
195 pVideoPlane->addr = NULL;
196 pVideoPlane->allocSize = 0;
197 pVideoPlane->dataSize = 0;
198 }
199
200 pCtx->pOutbuf[i].pGeometry = NULL;
201 pCtx->pOutbuf[i].bQueued = VIDEO_FALSE;
202 }
203 }
204 }
205
206 if (pCtx->pInbuf != NULL)
207 free(pCtx->pInbuf);
208
209 if (pCtx->pOutbuf != NULL)
210 free(pCtx->pOutbuf);
211
212 if (pCtx->hDec > 0)
213 close(pCtx->hDec);
214
215 free(pCtx);
216
217EXIT:
218 return ret;
219}
220
221/*
222 * [Decoder OPS] Set Frame Tag
223 */
224static ExynosVideoErrorType MFC_Decoder_Set_FrameTag(
225 void *pHandle,
226 int frameTag)
227{
228 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
229 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
230
231 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700232 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900233 ret = VIDEO_ERROR_BADPARAM;
234 goto EXIT;
235 }
236
237 if (exynos_v4l2_s_ctrl(pCtx->hDec, V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG, frameTag)) {
238 ret = VIDEO_ERROR_APIFAIL;
239 goto EXIT;
240 }
241
242EXIT:
243 return ret;
244}
245
246/*
247 * [Decoder OPS] Get Frame Tag
248 */
249static int MFC_Decoder_Get_FrameTag(void *pHandle)
250{
251 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
252 int frameTag = -1;
253
254 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700255 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900256 goto EXIT;
257 }
258
259 exynos_v4l2_g_ctrl(pCtx->hDec, V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG, &frameTag);
260
261EXIT:
262 return frameTag;
263}
264
265/*
266 * [Decoder OPS] Get Buffer Count
267 */
268static int MFC_Decoder_Get_ActualBufferCount(void *pHandle)
269{
270 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
271 int bufferCount = -1;
272
273 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700274 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900275 goto EXIT;
276 }
277
278 exynos_v4l2_g_ctrl(pCtx->hDec, V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, &bufferCount);
279
280EXIT:
281 return bufferCount;
282}
283
284/*
285 * [Decoder OPS] Set Cacheable
286 */
287static ExynosVideoErrorType MFC_Decoder_Enable_Cacheable(void *pHandle)
288{
289 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
290 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
291
292 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700293 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900294 ret = VIDEO_ERROR_BADPARAM;
295 goto EXIT;
296 }
297
298 if (exynos_v4l2_s_ctrl(pCtx->hDec, V4L2_CID_CACHEABLE, 1)) {
299 ret = VIDEO_ERROR_APIFAIL;
300 goto EXIT;
301 }
302
303EXIT:
304 return ret;
305}
306
307/*
308 * [Decoder OPS] Set Display Delay
309 */
310static ExynosVideoErrorType MFC_Decoder_Set_DisplayDelay(
311 void *pHandle,
312 int delay)
313{
314 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
315 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
316
317 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700318 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900319 ret = VIDEO_ERROR_BADPARAM;
320 goto EXIT;
321 }
322
323 if (exynos_v4l2_s_ctrl(pCtx->hDec, V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY, delay)) {
324 ret = VIDEO_ERROR_APIFAIL;
325 goto EXIT;
326 }
327
328EXIT:
329 return ret;
330}
331
332/*
333 * [Decoder OPS] Enable Packed PB
334 */
335static ExynosVideoErrorType MFC_Decoder_Enable_PackedPB(void *pHandle)
336{
337 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
338 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
339
340 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700341 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900342 ret = VIDEO_ERROR_BADPARAM;
343 goto EXIT;
344 }
345
346 if (exynos_v4l2_s_ctrl(pCtx->hDec, V4L2_CID_MPEG_MFC51_VIDEO_PACKED_PB, 1)) {
347 ret = VIDEO_ERROR_APIFAIL;
348 goto EXIT;
349 }
350
351EXIT:
352 return ret;
353}
354
355/*
356 * [Decoder OPS] Enable Loop Filter
357 */
358static ExynosVideoErrorType MFC_Decoder_Enable_LoopFilter(void *pHandle)
359{
360 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
361 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
362
363 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700364 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900365 ret = VIDEO_ERROR_BADPARAM;
366 goto EXIT;
367 }
368
369 if (exynos_v4l2_s_ctrl(pCtx->hDec, V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER, 1)) {
370 ret = VIDEO_ERROR_APIFAIL;
371 goto EXIT;
372 }
373
374EXIT:
375 return ret;
376}
377
378/*
379 * [Decoder OPS] Enable Slice Mode
380 */
381static ExynosVideoErrorType MFC_Decoder_Enable_SliceMode(void *pHandle)
382{
383 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
384 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
385
386 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700387 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900388 ret = VIDEO_ERROR_BADPARAM;
389 goto EXIT;
390 }
391
392 if (exynos_v4l2_s_ctrl(pCtx->hDec, V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE, 1)) {
393 ret = VIDEO_ERROR_APIFAIL;
394 goto EXIT;
395 }
396
397EXIT:
398 return ret;
399}
400
401/*
402 * [Decoder Buffer OPS] Set Shareable Buffer (Input)
403 */
404static ExynosVideoErrorType MFC_Decoder_Set_Shareable_Inbuf(void *pHandle)
405{
406 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
407 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
408
409 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700410 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900411 ret = VIDEO_ERROR_BADPARAM;
412 goto EXIT;
413 }
414
415 pCtx->bShareInbuf = VIDEO_TRUE;
416
417EXIT:
418 return ret;
419}
420
421/*
422 * [Decoder Buffer OPS] Set Shareable Buffer (Output)
423 */
424static ExynosVideoErrorType MFC_Decoder_Set_Shareable_Outbuf(void *pHandle)
425{
426 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
427 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
428
429 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700430 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900431 ret = VIDEO_ERROR_BADPARAM;
432 goto EXIT;
433 }
434
435 pCtx->bShareOutbuf = VIDEO_TRUE;
436
437EXIT:
438 return ret;
439}
440
441/*
442 * [Decoder Buffer OPS] Get Buffer Info (Input)
443 */
444static ExynosVideoErrorType MFC_Decoder_Get_BufferInfo_Inbuf(
445 void *pHandle,
446 int nIndex,
447 ExynosVideoBuffer *pBuffer)
448{
449 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
450 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
451
452 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700453 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900454 ret = VIDEO_ERROR_NOBUFFERS;
455 goto EXIT;
456 }
457
458 memcpy(pBuffer, &pCtx->pInbuf[nIndex], sizeof(*pBuffer));
459
460EXIT:
461 return ret;
462}
463
464/*
465 * [Decoder Buffer OPS] Get Buffer Info (Output)
466 */
467static ExynosVideoErrorType MFC_Decoder_Get_BufferInfo_Outbuf(
468 void *pHandle,
469 int nIndex,
470 ExynosVideoBuffer *pBuffer)
471{
472 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
473 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
474
475 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700476 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900477 ret = VIDEO_ERROR_NOBUFFERS;
478 goto EXIT;
479 }
480
481 memcpy(pBuffer, &pCtx->pOutbuf[nIndex], sizeof(*pBuffer));
482
483EXIT:
484 return ret;
485}
486
487/*
488 * [Decoder Buffer OPS] Set Geometry (Input)
489 */
490static ExynosVideoErrorType MFC_Decoder_Set_Geometry_Inbuf(
491 void *pHandle,
492 ExynosVideoGeometry *bufferConf)
493{
494 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
495 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
496
497 struct v4l2_format fmt;
498
499 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700500 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900501 ret = VIDEO_ERROR_BADPARAM;
502 goto EXIT;
503 }
504
505 if (bufferConf == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700506 ALOGE("%s: Buffer geometry must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900507 ret = VIDEO_ERROR_BADPARAM;
508 goto EXIT;
509 }
510
511 memset(&fmt, 0, sizeof(fmt));
512
513 fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
514 fmt.fmt.pix_mp.pixelformat = __CodingType_To_V4L2PixelFormat(bufferConf->eCompressionFormat);
515 fmt.fmt.pix_mp.plane_fmt[0].sizeimage = bufferConf->nSizeImage;
516
517 if (exynos_v4l2_s_fmt(pCtx->hDec, &fmt)) {
518 ret = VIDEO_ERROR_APIFAIL;
519 goto EXIT;
520 }
521
522 memcpy(&pCtx->inbufGeometry, bufferConf, sizeof(pCtx->inbufGeometry));
523
524EXIT:
525 return ret;
526}
527
528/*
529 * [Decoder Buffer OPS] Set Geometry (Output)
530 */
531static ExynosVideoErrorType MFC_Decoder_Set_Geometry_Outbuf(
532 void *pHandle,
533 ExynosVideoGeometry *bufferConf)
534{
535 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
536 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
537
538 struct v4l2_format fmt;
539
540 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700541 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900542 ret = VIDEO_ERROR_BADPARAM;
543 goto EXIT;
544 }
545
546 if (bufferConf == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700547 ALOGE("%s: Buffer geometry must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900548 ret = VIDEO_ERROR_BADPARAM;
549 goto EXIT;
550 }
551
552 memset(&fmt, 0, sizeof(fmt));
553
554 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
555 fmt.fmt.pix_mp.pixelformat = __ColorFormatType_To_V4L2PixelFormat(bufferConf->eColorFormat);
556
557 if (exynos_v4l2_s_fmt(pCtx->hDec, &fmt)) {
558 ret = VIDEO_ERROR_APIFAIL;
559 goto EXIT;
560 }
561
562 memcpy(&pCtx->outbufGeometry, bufferConf, sizeof(pCtx->outbufGeometry));
563
564EXIT:
565 return ret;
566}
567
568/*
569 * [Decoder Buffer OPS] Get Geometry (Output)
570 */
571static ExynosVideoErrorType MFC_Decoder_Get_Geometry_Outbuf(
572 void *pHandle,
573 ExynosVideoGeometry *bufferConf)
574{
575 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
576 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
577
578 struct v4l2_format fmt;
579 struct v4l2_crop crop;
580
581 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700582 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900583 ret = VIDEO_ERROR_BADPARAM;
584 goto EXIT;
585 }
586
587 if (bufferConf == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700588 ALOGE("%s: Buffer geometry must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900589 ret = VIDEO_ERROR_BADPARAM;
590 goto EXIT;
591 }
592
593 memset(&fmt, 0, sizeof(fmt));
594 memset(&crop, 0, sizeof(crop));
595
596 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
597 if (exynos_v4l2_g_fmt(pCtx->hDec, &fmt)) {
598 ret = VIDEO_ERROR_APIFAIL;
599 goto EXIT;
600 }
601
602 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
603 if (exynos_v4l2_g_crop(pCtx->hDec, &crop)) {
604 ret = VIDEO_ERROR_APIFAIL;
605 goto EXIT;
606 }
607
608 bufferConf->nFrameWidth = fmt.fmt.pix_mp.width;
609 bufferConf->nFrameHeight = fmt.fmt.pix_mp.height;
610
611 bufferConf->cropRect.nTop = crop.c.top;
612 bufferConf->cropRect.nLeft = crop.c.left;
613 bufferConf->cropRect.nWidth = crop.c.width;
614 bufferConf->cropRect.nHeight = crop.c.height;
615
616EXIT:
617 return ret;
618}
619
620/*
621 * [Decoder Buffer OPS] Setup (Input)
622 */
623static ExynosVideoErrorType MFC_Decoder_Setup_Inbuf(
624 void *pHandle,
625 unsigned int nBufferCount)
626{
627 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
628 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
629 ExynosVideoPlane *pVideoPlane;
630
631 struct v4l2_requestbuffers req;
632 struct v4l2_buffer buf;
633 struct v4l2_plane planes[VIDEO_DECODER_INBUF_PLANES];
634 int i;
635
636 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700637 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900638 ret = VIDEO_ERROR_BADPARAM;
639 goto EXIT;
640 }
641
642 if (nBufferCount == 0) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700643 ALOGE("%s: Buffer count must be greater than 0", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900644 ret = VIDEO_ERROR_BADPARAM;
645 goto EXIT;
646 }
647
648 memset(&req, 0, sizeof(req));
649
650 req.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
651 req.count = nBufferCount;
652
653 if (pCtx->bShareInbuf == VIDEO_TRUE)
654 req.memory = V4L2_MEMORY_USERPTR;
655 else
656 req.memory = V4L2_MEMORY_MMAP;
657
658 if (exynos_v4l2_reqbufs(pCtx->hDec, &req)) {
659 ret = VIDEO_ERROR_APIFAIL;
660 goto EXIT;
661 }
662
663 pCtx->nInbufs = (int)req.count;
664
665 pCtx->pInbuf = malloc(sizeof(*pCtx->pInbuf) * pCtx->nInbufs);
666 if (pCtx->pInbuf == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700667 ALOGE("Failed to allocate input buffer context");
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900668 ret = VIDEO_ERROR_NOMEM;
669 goto EXIT;
670 }
671 memset(pCtx->pInbuf, 0, sizeof(*pCtx->pInbuf) * pCtx->nInbufs);
672
673 memset(&buf, 0, sizeof(buf));
674
675 if (pCtx->bShareInbuf == VIDEO_FALSE) {
676 buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
677 buf.memory = V4L2_MEMORY_MMAP;
678 buf.m.planes = planes;
679 buf.length = VIDEO_DECODER_INBUF_PLANES;
680
681 for (i = 0; i < pCtx->nInbufs; i++) {
682 buf.index = i;
683 if (exynos_v4l2_querybuf(pCtx->hDec, &buf)) {
684 ret = VIDEO_ERROR_APIFAIL;
685 goto EXIT;
686 }
687
688 pVideoPlane = &pCtx->pInbuf[i].planes[0];
689
690 pVideoPlane->addr = mmap(NULL,
691 buf.m.planes[0].length, PROT_READ | PROT_WRITE,
692 MAP_SHARED, pCtx->hDec, buf.m.planes[0].m.mem_offset);
693
694 if (pVideoPlane->addr == MAP_FAILED) {
695 ret = VIDEO_ERROR_MAPFAIL;
696 goto EXIT;
697 }
698
699 pVideoPlane->allocSize = buf.m.planes[0].length;
700 pVideoPlane->dataSize = 0;
701
702 pCtx->pInbuf[i].pGeometry = &pCtx->inbufGeometry;
703 pCtx->pInbuf[i].bQueued = VIDEO_TRUE;
704 }
705 }
706
707 return ret;
708
709EXIT:
710 if (pCtx->bShareInbuf == VIDEO_FALSE) {
711 for (i = 0; i < pCtx->nInbufs; i++) {
712 pVideoPlane = &pCtx->pInbuf[i].planes[0];
713 if (pVideoPlane->addr == MAP_FAILED) {
714 pVideoPlane->addr = NULL;
715 break;
716 }
717
718 munmap(pVideoPlane->addr, pVideoPlane->allocSize);
719 pVideoPlane->allocSize = 0;
720 pVideoPlane->dataSize = 0;
721
722 pCtx->pInbuf[i].pGeometry = NULL;
723 pCtx->pInbuf[i].bQueued = VIDEO_FALSE;
724 }
725 }
726
727 return ret;
728}
729
730/*
731 * [Decoder Buffer OPS] Setup (Output)
732 */
733static ExynosVideoErrorType MFC_Decoder_Setup_Outbuf(
734 void *pHandle,
735 unsigned int nBufferCount)
736{
737 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
738 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
739 ExynosVideoPlane *pVideoPlane;
740
741 struct v4l2_requestbuffers req;
742 struct v4l2_buffer buf;
743 struct v4l2_plane planes[VIDEO_DECODER_OUTBUF_PLANES];
744 int i, j;
745
746 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700747 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900748 ret = VIDEO_ERROR_BADPARAM;
749 goto EXIT;
750 }
751
752 if (nBufferCount == 0) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700753 ALOGE("%s: Buffer count must be greater than 0", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900754 ret = VIDEO_ERROR_BADPARAM;
755 goto EXIT;
756 }
757
758 memset(&req, 0, sizeof(req));
759
760 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
761 req.count = nBufferCount;
762
763 if (pCtx->bShareOutbuf == VIDEO_TRUE)
764 req.memory = V4L2_MEMORY_USERPTR;
765 else
766 req.memory = V4L2_MEMORY_MMAP;
767
768 if (exynos_v4l2_reqbufs(pCtx->hDec, &req)) {
769 ret = VIDEO_ERROR_APIFAIL;
770 goto EXIT;
771 }
772
773 pCtx->nOutbufs = req.count;
774
775 pCtx->pOutbuf = malloc(sizeof(*pCtx->pOutbuf) * pCtx->nOutbufs);
776 if (pCtx->pOutbuf == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700777 ALOGE("Failed to allocate output buffer context");
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900778 ret = VIDEO_ERROR_NOMEM;
779 goto EXIT;
780 }
781 memset(pCtx->pOutbuf, 0, sizeof(*pCtx->pOutbuf) * pCtx->nOutbufs);
782
783 memset(&buf, 0, sizeof(buf));
784
785 if (pCtx->bShareOutbuf == VIDEO_FALSE) {
786 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
787 buf.memory = V4L2_MEMORY_MMAP;
788 buf.m.planes = planes;
789 buf.length = VIDEO_DECODER_OUTBUF_PLANES;
790
791 for (i = 0; i < pCtx->nOutbufs; i++) {
792 buf.index = i;
793 if (exynos_v4l2_querybuf(pCtx->hDec, &buf)) {
794 ret = VIDEO_ERROR_APIFAIL;
795 goto EXIT;
796 }
797
798 for (j = 0; j < VIDEO_DECODER_OUTBUF_PLANES; j++) {
799 pVideoPlane = &pCtx->pOutbuf[i].planes[j];
800 pVideoPlane->addr = mmap(NULL,
801 buf.m.planes[j].length, PROT_READ | PROT_WRITE,
802 MAP_SHARED, pCtx->hDec, buf.m.planes[j].m.mem_offset);
803
804 if (pVideoPlane->addr == MAP_FAILED) {
805 ret = VIDEO_ERROR_MAPFAIL;
806 goto EXIT;
807 }
808
809 pVideoPlane->allocSize = buf.m.planes[j].length;
810 pVideoPlane->dataSize = 0;
811 }
812
813 pCtx->pOutbuf[i].pGeometry = &pCtx->outbufGeometry;
814 pCtx->pOutbuf[i].bQueued = VIDEO_FALSE;
815 }
816 }
817
818 return ret;
819
820EXIT:
821 if (pCtx->bShareOutbuf == VIDEO_FALSE) {
822 for (i = 0; i < pCtx->nOutbufs; i++) {
823 for (j = 0; j < VIDEO_DECODER_OUTBUF_PLANES; j++) {
824 pVideoPlane = &pCtx->pOutbuf[i].planes[j];
825 if (pVideoPlane->addr == MAP_FAILED) {
826 pVideoPlane->addr = NULL;
827 break;
828 }
829
830 munmap(pVideoPlane->addr, pVideoPlane->allocSize);
831 pVideoPlane->allocSize = 0;
832 pVideoPlane->dataSize = 0;
833 }
834
835 pCtx->pOutbuf[i].pGeometry = NULL;
836 pCtx->pOutbuf[i].bQueued = VIDEO_FALSE;
837 }
838 }
839
840 return ret;
841}
842
843/*
844 * [Decoder Buffer OPS] Run (Input)
845 */
846static ExynosVideoErrorType MFC_Decoder_Run_Inbuf(void *pHandle)
847{
848 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
849 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
850
851 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700852 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900853 ret = VIDEO_ERROR_BADPARAM;
854 goto EXIT;
855 }
856
857 if (pCtx->bStreamonInbuf == VIDEO_FALSE) {
858 if (exynos_v4l2_streamon(pCtx->hDec, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700859 ALOGE("%s: Failed to streamon for input buffer", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900860 ret = VIDEO_ERROR_APIFAIL;
861 goto EXIT;
862 }
863 pCtx->bStreamonInbuf = VIDEO_TRUE;
864 }
865
866EXIT:
867 return ret;
868}
869
870/*
871 * [Decoder Buffer OPS] Run (Output)
872 */
873static ExynosVideoErrorType MFC_Decoder_Run_Outbuf(void *pHandle)
874{
875 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
876 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
877
878 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700879 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900880 ret = VIDEO_ERROR_BADPARAM;
881 goto EXIT;
882 }
883
884 if (pCtx->bStreamonOutbuf == VIDEO_FALSE) {
885 if (exynos_v4l2_streamon(pCtx->hDec, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700886 ALOGE("%s: Failed to streamon for output buffer", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900887 ret = VIDEO_ERROR_APIFAIL;
888 goto EXIT;
889 }
890 pCtx->bStreamonOutbuf = VIDEO_TRUE;
891 }
892
893EXIT:
894 return ret;
895}
896
897/*
898 * [Decoder Buffer OPS] Stop (Input)
899 */
900static ExynosVideoErrorType MFC_Decoder_Stop_Inbuf(void *pHandle)
901{
902 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
903 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
904
905 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700906 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900907 ret = VIDEO_ERROR_BADPARAM;
908 goto EXIT;
909 }
910
911 if (pCtx->bStreamonInbuf == VIDEO_TRUE) {
912 if (exynos_v4l2_streamoff(pCtx->hDec, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700913 ALOGE("%s: Failed to streamoff for input buffer", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900914 ret = VIDEO_ERROR_APIFAIL;
915 goto EXIT;
916 }
917 pCtx->bStreamonInbuf = VIDEO_FALSE;
918 }
919
920EXIT:
921 return ret;
922}
923
924/*
925 * [Decoder Buffer OPS] Stop (Output)
926 */
927static ExynosVideoErrorType MFC_Decoder_Stop_Outbuf(void *pHandle)
928{
929 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
930 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
931
932 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700933 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900934 ret = VIDEO_ERROR_BADPARAM;
935 goto EXIT;
936 }
937
938 if (pCtx->bStreamonOutbuf == VIDEO_TRUE) {
939 if (exynos_v4l2_streamoff(pCtx->hDec, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700940 ALOGE("%s: Failed to streamoff for output buffer", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900941 ret = VIDEO_ERROR_APIFAIL;
942 goto EXIT;
943 }
944 pCtx->bStreamonOutbuf = VIDEO_FALSE;
945 }
946
947EXIT:
948 return ret;
949}
950
951/*
952 * [Decoder Buffer OPS] Wait (Input)
953 */
954static ExynosVideoErrorType MFC_Decoder_Wait_Inbuf(void *pHandle)
955{
956 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
957 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
958
959 struct pollfd poll_events;
960 int poll_state;
961
962 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700963 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900964 ret = VIDEO_ERROR_BADPARAM;
965 goto EXIT;
966 }
967
968 poll_events.fd = pCtx->hDec;
969 poll_events.events = POLLOUT | POLLERR;
970 poll_events.revents = 0;
971
972 do {
973 poll_state = poll((struct pollfd*)&poll_events, 1, VIDEO_DECODER_POLL_TIMEOUT);
974 if (poll_state > 0) {
975 if (poll_events.revents & POLLOUT) {
976 break;
977 } else {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700978 ALOGE("%s: Poll return error", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900979 ret = VIDEO_ERROR_POLL;
980 break;
981 }
982 } else if (poll_state < 0) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -0700983 ALOGE("%s: Poll state error", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +0900984 ret = VIDEO_ERROR_POLL;
985 break;
986 }
987 } while (poll_state == 0);
988
989EXIT:
990 return ret;
991}
992
993/*
994 * [Decoder Buffer OPS] Find (Input)
995 */
996static int MFC_Decoder_Find_Inbuf(
997 void *pHandle,
998 unsigned char *pBuffer)
999{
1000 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1001 int nIndex = -1;
1002
1003 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -07001004 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +09001005 nIndex = -1;
1006 goto EXIT;
1007 }
1008
1009 if (pBuffer == NULL) {
1010 for (nIndex = 0; nIndex < pCtx->nInbufs; nIndex++) {
1011 if (pCtx->pInbuf[nIndex].bQueued == VIDEO_FALSE)
1012 break;
1013 }
1014 } else {
1015 for (nIndex = 0; nIndex < pCtx->nInbufs; nIndex++) {
1016 if (pCtx->pInbuf[nIndex].planes[0].addr == pBuffer)
1017 break;
1018 }
1019 }
1020
1021 if (nIndex == pCtx->nInbufs) {
1022 nIndex = -1;
1023 goto EXIT;
1024 }
1025
1026EXIT:
1027 return nIndex;
1028}
1029
1030/*
1031 * [Decoder Buffer OPS] Find (Outnput)
1032 */
1033static int MFC_Decoder_Find_Outbuf(
1034 void *pHandle,
1035 unsigned char *pBuffer)
1036{
1037 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1038 int nIndex = -1;
1039
1040 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -07001041 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +09001042 nIndex = -1;
1043 goto EXIT;
1044 }
1045
1046 if (pBuffer == NULL) {
1047 for (nIndex = 0; nIndex < pCtx->nOutbufs; nIndex++) {
1048 if (pCtx->pOutbuf[nIndex].bQueued == VIDEO_FALSE)
1049 break;
1050 }
1051 } else {
1052 for (nIndex = 0; nIndex < pCtx->nOutbufs; nIndex++) {
1053 if (pCtx->pOutbuf[nIndex].planes[0].addr == pBuffer)
1054 break;
1055 }
1056 }
1057
1058 if (nIndex == pCtx->nOutbufs) {
1059 nIndex = -1;
1060 goto EXIT;
1061 }
1062
1063EXIT:
1064 return nIndex;
1065}
1066
1067/*
1068 * [Decoder Buffer OPS] Enqueue (Input)
1069 */
1070static ExynosVideoErrorType MFC_Decoder_Enqueue_Inbuf(
1071 void *pHandle,
1072 unsigned char *pBuffer[],
1073 unsigned int dataSize[],
1074 int nPlanes,
1075 void *pPrivate)
1076{
1077 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1078 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
1079
1080 struct v4l2_plane planes[VIDEO_DECODER_INBUF_PLANES];
1081 struct v4l2_buffer buf;
1082 int index, i;
1083
1084 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -07001085 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +09001086 ret = VIDEO_ERROR_BADPARAM;
1087 goto EXIT;
1088 }
1089
1090 memset(&buf, 0, sizeof(buf));
1091
1092 buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1093 buf.m.planes = planes;
1094 buf.length = VIDEO_DECODER_INBUF_PLANES;
1095
1096 if ((pCtx->bShareInbuf == VIDEO_TRUE) || (pBuffer == NULL))
1097 index = MFC_Decoder_Find_Inbuf(pCtx, NULL);
1098 else
1099 index = MFC_Decoder_Find_Inbuf(pCtx, pBuffer[0]);
1100
1101 if (index == -1) {
1102 ret = VIDEO_ERROR_NOBUFFERS;
1103 goto EXIT;
1104 }
1105
1106 buf.index = index;
1107
1108 if (pCtx->bShareInbuf == VIDEO_TRUE) {
1109 buf.memory = V4L2_MEMORY_USERPTR;
1110 for (i = 0; i < nPlanes; i++) {
1111 buf.m.planes[i].m.userptr = (unsigned long)pBuffer[i];
1112 buf.m.planes[i].length = VIDEO_DECODER_INBUF_SIZE;
1113 buf.m.planes[i].bytesused = dataSize[i];
1114 pCtx->pInbuf[buf.index].planes[i].addr = pBuffer[i];
1115 }
1116 } else {
1117 buf.memory = V4L2_MEMORY_MMAP;
1118 for (i = 0; i < nPlanes; i++)
1119 buf.m.planes[i].bytesused = dataSize[i];
1120 }
1121
1122 if (exynos_v4l2_qbuf(pCtx->hDec, &buf)) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -07001123 ALOGE("%s: Failed to enqueue input buffer", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +09001124 ret = VIDEO_ERROR_APIFAIL;
1125 goto EXIT;
1126 }
1127
1128 pCtx->pInbuf[buf.index].pPrivate = pPrivate;
1129 pCtx->pInbuf[buf.index].bQueued = VIDEO_TRUE;
1130
1131EXIT:
1132 return ret;
1133}
1134
1135/*
1136 * [Decoder Buffer OPS] Enqueue (Output)
1137 */
1138static ExynosVideoErrorType MFC_Decoder_Enqueue_Outbuf(
1139 void *pHandle,
1140 unsigned char *pBuffer[],
1141 unsigned int dataSize[],
1142 int nPlanes,
1143 void *pPrivate)
1144{
1145 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1146 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
1147
1148 struct v4l2_plane planes[VIDEO_DECODER_OUTBUF_PLANES];
1149 struct v4l2_buffer buf;
1150 int i, index;
1151
1152 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -07001153 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +09001154 ret = VIDEO_ERROR_BADPARAM;
1155 goto EXIT;
1156 }
1157
1158 memset(&buf, 0, sizeof(buf));
1159
1160 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1161 buf.m.planes = planes;
1162 buf.length = VIDEO_DECODER_OUTBUF_PLANES;
1163
1164 if ((pCtx->bShareOutbuf == VIDEO_TRUE) || (pBuffer == NULL))
1165 index = MFC_Decoder_Find_Outbuf(pCtx, NULL);
1166 else
1167 index = MFC_Decoder_Find_Outbuf(pCtx, pBuffer[0]);
1168
1169 if (index == -1) {
1170 ret = VIDEO_ERROR_NOBUFFERS;
1171 goto EXIT;
1172 }
1173
1174 buf.index = index;
1175
1176 if (pCtx->bShareOutbuf == VIDEO_TRUE) {
1177 buf.memory = V4L2_MEMORY_USERPTR;
1178 for (i = 0; i < nPlanes; i++) {
1179 buf.m.planes[i].m.userptr = (unsigned long)pBuffer[i];
1180 buf.m.planes[i].length = dataSize[i];
1181 buf.m.planes[i].bytesused = dataSize[i];
1182 pCtx->pOutbuf[buf.index].planes[i].addr = pBuffer[i];
1183 }
1184 } else {
1185 buf.memory = V4L2_MEMORY_MMAP;
1186 }
1187
1188 if (exynos_v4l2_qbuf(pCtx->hDec, &buf)) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -07001189 ALOGE("%s: Failed to enqueue output buffer", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +09001190 ret = VIDEO_ERROR_APIFAIL;
1191 goto EXIT;
1192 }
1193
1194 pCtx->pOutbuf[buf.index].pPrivate = pPrivate;
1195 pCtx->pOutbuf[buf.index].bQueued = VIDEO_TRUE;
1196
1197EXIT:
1198 return ret;
1199}
1200
1201/*
1202 * [Decoder Buffer OPS] Dequeue (Input)
1203 */
1204static ExynosVideoBuffer *MFC_Decoder_Dequeue_Inbuf(void *pHandle)
1205{
1206 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1207 ExynosVideoBuffer *pOutbuf = NULL;
1208
1209 struct v4l2_buffer buf;
1210
1211 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -07001212 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +09001213 pOutbuf = NULL;
1214 goto EXIT;
1215 }
1216
1217 if (pCtx->bStreamonInbuf == VIDEO_FALSE) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -07001218 ALOGE("%s: Input buffer stream is off", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +09001219 goto EXIT;
1220 }
1221
1222 if (MFC_Decoder_Wait_Inbuf(pCtx) != VIDEO_ERROR_NONE) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -07001223 ALOGE("%s: Failed to poll for input buffer", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +09001224 pOutbuf = NULL;
1225 goto EXIT;
1226 }
1227
1228 memset(&buf, 0, sizeof(buf));
1229
1230 buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1231
1232 if (pCtx->bShareInbuf == VIDEO_TRUE)
1233 buf.memory = V4L2_MEMORY_USERPTR;
1234 else
1235 buf.memory = V4L2_MEMORY_MMAP;
1236
1237 if (exynos_v4l2_dqbuf(pCtx->hDec, &buf) == 0) {
1238 pCtx->pInbuf[buf.index].bQueued = VIDEO_FALSE;
1239 pOutbuf = &pCtx->pInbuf[buf.index];
1240 } else {
Dima Zavin4a7b2d32012-04-02 23:43:51 -07001241 ALOGE("%s: Failed to dequeue input buffer", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +09001242 pOutbuf = NULL;
1243 goto EXIT;
1244 }
1245
1246EXIT:
1247 return pOutbuf;
1248}
1249
1250/*
1251 * [Decoder Buffer OPS] Enqueue All (Output)
1252 */
1253static ExynosVideoErrorType MFC_Decoder_Enqueue_All_Outbuf(void *pHandle)
1254{
1255 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1256 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
1257
1258 int i;
1259
1260 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -07001261 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +09001262 ret = VIDEO_ERROR_BADPARAM;
1263 goto EXIT;
1264 }
1265
1266 for (i = 0; i < pCtx->nOutbufs; i++)
1267 MFC_Decoder_Enqueue_Outbuf(pCtx, NULL, NULL, 0, NULL);
1268
1269EXIT:
1270 return ret;
1271}
1272
1273/*
1274 * [Decoder Buffer OPS] Dequeue (Output)
1275 */
1276static ExynosVideoBuffer *MFC_Decoder_Dequeue_Outbuf(void *pHandle)
1277{
1278 ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
1279 ExynosVideoBuffer *pOutbuf = NULL;
1280
1281 struct v4l2_buffer buf;
1282 int value;
1283
1284 if (pCtx == NULL) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -07001285 ALOGE("%s: Video context info must be supplied", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +09001286 pOutbuf = NULL;
1287 goto EXIT;
1288 }
1289
1290 if (pCtx->bStreamonOutbuf == VIDEO_FALSE) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -07001291 ALOGE("%s: Output buffer stream is off", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +09001292 goto EXIT;
1293 }
1294
1295 memset(&buf, 0, sizeof(buf));
1296
1297 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1298
1299 if (pCtx->bShareOutbuf == VIDEO_TRUE)
1300 buf.memory = V4L2_MEMORY_USERPTR;
1301 else
1302 buf.memory = V4L2_MEMORY_MMAP;
1303
1304 /* HACK: pOutbuf return -1 means DECODING_ONLY for almost cases */
1305 if (exynos_v4l2_dqbuf(pCtx->hDec, &buf)) {
Dima Zavin4a7b2d32012-04-02 23:43:51 -07001306 ALOGW("%s: Failed to dequeue output buffer or DECODING_ONLY", __func__);
Jiho Chang20d3e6e2012-03-24 03:43:08 +09001307 pOutbuf = NULL;
1308 goto EXIT;
1309 }
1310
1311 pOutbuf = &pCtx->pOutbuf[buf.index];
1312
1313 exynos_v4l2_g_ctrl(pCtx->hDec, V4L2_CID_MPEG_MFC51_VIDEO_DISPLAY_STATUS, &value);
1314
1315 switch (value) {
1316 case 0:
1317 pOutbuf->displayStatus = VIDEO_FRAME_STATUS_DECODING_ONLY;
1318 break;
1319 case 1:
1320 pOutbuf->displayStatus = VIDEO_FRAME_STATUS_DISPLAY_DECODING;
1321 break;
1322 case 2:
1323 pOutbuf->displayStatus = VIDEO_FRAME_STATUS_DISPLAY_ONLY;
1324 break;
1325 case 3:
1326 pOutbuf->displayStatus = VIDEO_FRAME_STATUS_CHANGE_RESOL;
1327 break;
1328 default:
1329 pOutbuf->displayStatus = VIDEO_FRAME_STATUS_UNKNOWN;
1330 break;
1331 }
1332
1333 switch (buf.flags & (0x7 << 3)) {
1334 case V4L2_BUF_FLAG_KEYFRAME:
1335 pOutbuf->frameType = VIDEO_FRAME_I;
1336 break;
1337 case V4L2_BUF_FLAG_PFRAME:
1338 pOutbuf->frameType = VIDEO_FRAME_P;
1339 break;
1340 case V4L2_BUF_FLAG_BFRAME:
1341 pOutbuf->frameType = VIDEO_FRAME_B;
1342 break;
1343 default:
1344 pOutbuf->frameType = VIDEO_FRAME_OTHERS;
1345 break;
1346 };
1347
1348 pOutbuf->bQueued = VIDEO_FALSE;
1349
1350EXIT:
1351 return pOutbuf;
1352}
1353
1354/*
1355 * [Decoder OPS] Common
1356 */
1357static ExynosVideoDecOps defDecOps = {
1358 .nSize = 0,
1359 .Init = MFC_Decoder_Init,
1360 .Finalize = MFC_Decoder_Finalize,
1361 .Enable_Cacheable = MFC_Decoder_Enable_Cacheable,
1362 .Set_DisplayDelay = MFC_Decoder_Set_DisplayDelay,
1363 .Enable_PackedPB = MFC_Decoder_Enable_PackedPB,
1364 .Enable_LoopFilter = MFC_Decoder_Enable_LoopFilter,
1365 .Enable_SliceMode = MFC_Decoder_Enable_SliceMode,
1366 .Get_ActualBufferCount = MFC_Decoder_Get_ActualBufferCount,
1367 .Set_FrameTag = MFC_Decoder_Set_FrameTag,
1368 .Get_FrameTag = MFC_Decoder_Get_FrameTag,
1369};
1370
1371/*
1372 * [Decoder Buffer OPS] Input
1373 */
1374static ExynosVideoDecBufferOps defInbufOps = {
1375 .nSize = 0,
1376 .Set_Shareable = MFC_Decoder_Set_Shareable_Inbuf,
1377 .Get_BufferInfo = MFC_Decoder_Get_BufferInfo_Inbuf,
1378 .Set_Geometry = MFC_Decoder_Set_Geometry_Inbuf,
1379 .Get_Geometry = NULL,
1380 .Setup = MFC_Decoder_Setup_Inbuf,
1381 .Run = MFC_Decoder_Run_Inbuf,
1382 .Stop = MFC_Decoder_Stop_Inbuf,
1383 .Enqueue = MFC_Decoder_Enqueue_Inbuf,
1384 .Enqueue_All = NULL,
1385 .Dequeue = MFC_Decoder_Dequeue_Inbuf,
1386};
1387
1388/*
1389 * [Decoder Buffer OPS] Output
1390 */
1391static ExynosVideoDecBufferOps defOutbufOps = {
1392 .nSize = 0,
1393 .Set_Shareable = MFC_Decoder_Set_Shareable_Outbuf,
1394 .Get_BufferInfo = MFC_Decoder_Get_BufferInfo_Outbuf,
1395 .Set_Geometry = MFC_Decoder_Set_Geometry_Outbuf,
1396 .Get_Geometry = MFC_Decoder_Get_Geometry_Outbuf,
1397 .Setup = MFC_Decoder_Setup_Outbuf,
1398 .Run = MFC_Decoder_Run_Outbuf,
1399 .Stop = MFC_Decoder_Stop_Outbuf,
1400 .Enqueue = MFC_Decoder_Enqueue_Outbuf,
1401 .Enqueue_All = MFC_Decoder_Enqueue_All_Outbuf,
1402 .Dequeue = MFC_Decoder_Dequeue_Outbuf,
1403};
1404
1405int Exynos_Video_Register_Decoder(
1406 ExynosVideoDecOps *pDecOps,
1407 ExynosVideoDecBufferOps *pInbufOps,
1408 ExynosVideoDecBufferOps *pOutbufOps)
1409{
1410 ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
1411
1412 if ((pDecOps == NULL) || (pInbufOps == NULL) || (pOutbufOps == NULL)) {
1413 ret = VIDEO_ERROR_BADPARAM;
1414 goto EXIT;
1415 }
1416
1417 defDecOps.nSize = sizeof(defDecOps);
1418 defInbufOps.nSize = sizeof(defInbufOps);
1419 defOutbufOps.nSize = sizeof(defOutbufOps);
1420
1421 memcpy((char *)pDecOps + sizeof(pDecOps->nSize), (char *)&defDecOps + sizeof(defDecOps.nSize),
1422 pDecOps->nSize - sizeof(pDecOps->nSize));
1423
1424 memcpy((char *)pInbufOps + sizeof(pInbufOps->nSize), (char *)&defInbufOps + sizeof(defInbufOps.nSize),
1425 pInbufOps->nSize - sizeof(pInbufOps->nSize));
1426
1427 memcpy((char *)pOutbufOps + sizeof(pOutbufOps->nSize), (char *)&defOutbufOps + sizeof(defOutbufOps.nSize),
1428 pOutbufOps->nSize - sizeof(pOutbufOps->nSize));
1429
1430EXIT:
1431 return ret;
1432}