1/*
2 * Copyright (C) 2012 Intel Corporation.  All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17#include <cutils/properties.h>
18#include <system/graphics.h>
19#include <nativebase/nativebase.h>
20
21#include "isv_worker.h"
22#ifndef TARGET_VPP_USE_GEN
23#include <hal_public.h>
24#else
25#include <ufo/graphics.h>
26#endif
27
28//#define LOG_NDEBUG 0
29#undef LOG_TAG
30#define LOG_TAG "isv-omxil"
31
32#define CHECK_VASTATUS(str) \
33    do { \
34        if (vaStatus != VA_STATUS_SUCCESS) { \
35                ALOGE("%s failed\n", str); \
36                return STATUS_ERROR;}   \
37        }while(0);
38
39enum STRENGTH {
40    STRENGTH_LOW = 0,
41    STRENGTH_MEDIUM,
42    STRENGTH_HIGH
43};
44
45#define DENOISE_DEBLOCK_STRENGTH STRENGTH_MEDIUM
46#define COLOR_STRENGTH STRENGTH_MEDIUM
47#ifdef TARGET_VPP_USE_GEN
48#define COLOR_NUM 4
49#else
50#define COLOR_NUM 2
51#endif
52
53#define MAX_FRC_OUTPUT 4 /*for frcx4*/
54
55using namespace android;
56
57ISVWorker::ISVWorker()
58    :mNumForwardReferences(0),
59    mVAContext(VA_INVALID_ID),
60    mWidth(0), mHeight(0),
61    mDisplay(NULL), mVADisplay(NULL),
62    mVAConfig(VA_INVALID_ID),
63    mForwardReferences(NULL),
64    mPrevInput(0), mPrevOutput(0),
65    mNumFilterBuffers(0),
66    mFilterFrc(VA_INVALID_ID), mFilters(0),
67    mInputIndex(0), mOutputIndex(0),
68    mOutputCount(0) {
69    memset(&mFilterBuffers, VA_INVALID_ID, VAProcFilterCount * sizeof(VABufferID));
70    memset(&mFilterParam, 0, sizeof(mFilterParam));
71}
72
73bool ISVWorker::isSupport() const {
74    bool support = false;
75
76    int num_entrypoints = vaMaxNumEntrypoints(mVADisplay);
77    VAEntrypoint * entrypoints = (VAEntrypoint *)malloc(num_entrypoints * sizeof(VAEntrypoint));
78    if (entrypoints == NULL) {
79        ALOGE("failed to malloc entrypoints array\n");
80        return false;
81    }
82
83    // check if it contains VPP entry point VAEntrypointVideoProc
84    VAStatus vaStatus = vaQueryConfigEntrypoints(mVADisplay, VAProfileNone, entrypoints, &num_entrypoints);
85    if (vaStatus != VA_STATUS_SUCCESS) {
86        ALOGE("vaQueryConfigEntrypoints failed");
87        return false;
88    }
89    for (int i = 0; !support && i < num_entrypoints; i++) {
90        support = entrypoints[i] == VAEntrypointVideoProc;
91    }
92    free(entrypoints);
93    entrypoints = NULL;
94
95    return support;
96}
97
98uint32_t ISVWorker::getProcBufCount() {
99    return getOutputBufCount(mInputIndex);
100}
101
102uint32_t ISVWorker::getFillBufCount() {
103        return getOutputBufCount(mOutputIndex);
104}
105
106uint32_t ISVWorker::getOutputBufCount(uint32_t index) {
107    uint32_t bufCount = 1;
108    if (((mFilters & FilterFrameRateConversion) != 0)
109            && index > 0)
110            bufCount = mFilterParam.frcRate - (((mFilterParam.frcRate == FRC_RATE_2_5X) ? (index & 1): 0));
111    return bufCount;
112}
113
114
115status_t ISVWorker::init(uint32_t width, uint32_t height) {
116    ALOGV("init");
117
118    if (mDisplay != NULL) {
119        ALOGE("VA is particially started");
120        return STATUS_ERROR;
121    }
122    mDisplay = new Display;
123    *mDisplay = ANDROID_DISPLAY_HANDLE;
124
125    mVADisplay = vaGetDisplay(mDisplay);
126    if (mVADisplay == NULL) {
127        ALOGE("vaGetDisplay failed");
128        return STATUS_ERROR;
129    }
130
131    int majorVersion, minorVersion;
132    VAStatus vaStatus = vaInitialize(mVADisplay, &majorVersion, &minorVersion);
133    CHECK_VASTATUS("vaInitialize");
134
135    // Check if VPP entry point is supported
136    if (!isSupport()) {
137        ALOGE("VPP is not supported on current platform");
138        return STATUS_NOT_SUPPORT;
139    }
140
141    // Find out the format for the target
142    VAConfigAttrib attrib;
143    attrib.type = VAConfigAttribRTFormat;
144    vaStatus = vaGetConfigAttributes(mVADisplay, VAProfileNone, VAEntrypointVideoProc, &attrib, 1);
145    CHECK_VASTATUS("vaGetConfigAttributes");
146
147    if ((attrib.value & VA_RT_FORMAT_YUV420) == 0) {
148        ALOGE("attribute is %x vs wanted %x", attrib.value, VA_RT_FORMAT_YUV420);
149        return STATUS_NOT_SUPPORT;
150    }
151
152    ALOGV("ready to create config");
153    // Create the configuration
154    vaStatus = vaCreateConfig(mVADisplay, VAProfileNone, VAEntrypointVideoProc, &attrib, 1, &mVAConfig);
155    CHECK_VASTATUS("vaCreateConfig");
156
157
158    // Create Context
159    ALOGV("ready to create context");
160    mWidth = width;
161    mHeight = height;
162    vaStatus = vaCreateContext(mVADisplay, mVAConfig, mWidth, mHeight, 0, NULL, 0, &mVAContext);
163    CHECK_VASTATUS("vaCreateContext");
164
165    ALOGV("VA has been successfully started");
166    return STATUS_OK;
167}
168
169status_t ISVWorker::deinit() {
170    {
171        Mutex::Autolock autoLock(mPipelineBufferLock);
172        while (!mPipelineBuffers.isEmpty()) {
173            VABufferID pipelineBuffer = mPipelineBuffers.itemAt(0);
174            if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, pipelineBuffer))
175                ALOGW("%s: failed to destroy va buffer id %d", __func__, pipelineBuffer);
176            mPipelineBuffers.removeAt(0);
177        }
178    }
179
180    if (mNumFilterBuffers != 0) {
181        for (uint32_t i = 0; i < mNumFilterBuffers; i++) {
182            if(VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, mFilterBuffers[i]))
183                ALOGW("%s: failed to destroy va buffer id %d", __func__, mFilterBuffers[i]);
184        }
185        mNumFilterBuffers = 0;
186        memset(&mFilterBuffers, VA_INVALID_ID, VAProcFilterCount * sizeof(VABufferID));
187        mFilterFrc = VA_INVALID_ID;
188    }
189
190    if (mForwardReferences != NULL) {
191        free(mForwardReferences);
192        mForwardReferences = NULL;
193        mNumForwardReferences = 0;
194    }
195
196    if (mVAContext != VA_INVALID_ID) {
197         vaDestroyContext(mVADisplay, mVAContext);
198         mVAContext = VA_INVALID_ID;
199    }
200
201    if (mVAConfig != VA_INVALID_ID) {
202        vaDestroyConfig(mVADisplay, mVAConfig);
203        mVAConfig = VA_INVALID_ID;
204    }
205
206    if (mVADisplay) {
207        vaTerminate(mVADisplay);
208        mVADisplay = NULL;
209    }
210
211    if (mDisplay) {
212        delete mDisplay;
213        mDisplay = NULL;
214    }
215
216    return STATUS_OK;
217}
218
219status_t ISVWorker::allocSurface(uint32_t* width, uint32_t* height,
220        uint32_t stride, uint32_t format, unsigned long handle, int32_t* surfaceId)
221{
222    if (mWidth == 0 || mHeight == 0) {
223        ALOGE("%s: isv worker has not been initialized.", __func__);
224        return STATUS_ERROR;
225    }
226
227#ifndef TARGET_VPP_USE_GEN
228    *width = mWidth;
229    *height = mHeight;
230#endif
231    // Create VASurfaces
232    VASurfaceAttrib attribs[3];
233    VASurfaceAttribExternalBuffers vaExtBuf;
234
235    memset(&vaExtBuf, 0, sizeof(VASurfaceAttribExternalBuffers));
236    switch(format) {
237        case HAL_PIXEL_FORMAT_YV12:
238            vaExtBuf.pixel_format = VA_FOURCC_YV12;
239            vaExtBuf.num_planes = 3;
240            vaExtBuf.pitches[0] = stride;
241            vaExtBuf.pitches[1] = stride / 2;
242            vaExtBuf.pitches[2] = stride / 2;
243            vaExtBuf.pitches[3] = 0;
244            vaExtBuf.offsets[0] = 0;
245            vaExtBuf.offsets[1] = stride * *height;
246            vaExtBuf.offsets[2] = vaExtBuf.offsets[1] + (stride / 2) * (*height / 2);
247            vaExtBuf.offsets[3] = 0;
248            break;
249        case HAL_PIXEL_FORMAT_INTEL_YV12:
250            vaExtBuf.pixel_format = VA_FOURCC_YV12;
251            vaExtBuf.num_planes = 3;
252            vaExtBuf.pitches[0] = stride;
253            vaExtBuf.pitches[1] = stride / 2;
254            vaExtBuf.pitches[2] = stride / 2;
255            vaExtBuf.pitches[3] = 0;
256            vaExtBuf.offsets[0] = 0;
257            // The height of HAL_PIXEL_FORMAT_INTEL_YV12 gralloc buffer has been aligned with 32 pixels.
258            vaExtBuf.offsets[1] = stride * ((*height + 31) & ~31);
259            vaExtBuf.offsets[2] = vaExtBuf.offsets[1] + (stride / 2) * (((*height + 31) & ~31) / 2);
260            vaExtBuf.offsets[3] = 0;
261            break;
262#ifdef TARGET_VPP_USE_GEN
263        case HAL_PIXEL_FORMAT_NV12_Y_TILED_INTEL:
264        case HAL_PIXEL_FORMAT_NV12_X_TILED_INTEL:
265        //it will be removed in future, it indicate the same format with HAL_PIXEL_FORMAT_NV12_Y_TILED_INTEL
266        case HAL_PIXEL_FORMAT_YUV420PackedSemiPlanar_Tiled_INTEL:
267#else
268        case HAL_PIXEL_FORMAT_NV12_VED:
269        case HAL_PIXEL_FORMAT_NV12_VEDT:
270#endif
271            vaExtBuf.pixel_format = VA_FOURCC_NV12;
272            vaExtBuf.num_planes = 2;
273            vaExtBuf.pitches[0] = stride;
274            vaExtBuf.pitches[1] = stride;
275            vaExtBuf.pitches[2] = 0;
276            vaExtBuf.pitches[3] = 0;
277            vaExtBuf.offsets[0] = 0;
278            vaExtBuf.offsets[1] = stride * *height;
279            vaExtBuf.offsets[2] = 0;
280            vaExtBuf.offsets[3] = 0;
281            break;
282        default:
283            ALOGE("%s: can't support this format 0x%08x", __func__, format);
284            return STATUS_ERROR;
285    }
286    vaExtBuf.width = *width;
287    vaExtBuf.height = *height;
288    vaExtBuf.data_size = stride * *height * 1.5;
289    vaExtBuf.num_buffers = 1;
290#ifndef TARGET_VPP_USE_GEN
291    if (format == HAL_PIXEL_FORMAT_NV12_VEDT) {
292        ALOGV("set TILING flag");
293        vaExtBuf.flags |= VA_SURFACE_EXTBUF_DESC_ENABLE_TILING;
294    }
295#endif
296    vaExtBuf.flags |= VA_SURFACE_ATTRIB_MEM_TYPE_ANDROID_GRALLOC;
297    vaExtBuf.buffers = (long unsigned int*)&handle;
298
299    attribs[0].type = (VASurfaceAttribType)VASurfaceAttribMemoryType;
300    attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
301    attribs[0].value.type = VAGenericValueTypeInteger;
302    attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_ANDROID_GRALLOC;
303
304    attribs[1].type = (VASurfaceAttribType)VASurfaceAttribExternalBufferDescriptor;
305    attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
306    attribs[1].value.type = VAGenericValueTypePointer;
307    attribs[1].value.value.p = &vaExtBuf;
308
309    attribs[2].type = (VASurfaceAttribType)VASurfaceAttribUsageHint;
310    attribs[2].flags = VA_SURFACE_ATTRIB_SETTABLE;
311    attribs[2].value.type = VAGenericValueTypeInteger;
312    attribs[2].value.value.i = VA_SURFACE_ATTRIB_USAGE_HINT_VPP_READ;
313
314    ALOGV("%s: Ext buffer: width %d, height %d, data_size %d, pitch %d", __func__,
315            vaExtBuf.width, vaExtBuf.height, vaExtBuf.data_size, vaExtBuf.pitches[0]);
316    VAStatus vaStatus = vaCreateSurfaces(mVADisplay, VA_RT_FORMAT_YUV420, vaExtBuf.width,
317                                 vaExtBuf.height, (VASurfaceID*)surfaceId, 1, attribs, 3);
318    CHECK_VASTATUS("vaCreateSurfaces");
319
320    return (vaStatus == VA_STATUS_SUCCESS) ? STATUS_OK : STATUS_ERROR;
321}
322
323status_t ISVWorker::freeSurface(int32_t* surfaceId)
324{
325    VAStatus vaStatus = VA_STATUS_SUCCESS;
326    vaDestroySurfaces(mVADisplay, (VASurfaceID*)surfaceId, 1);
327    CHECK_VASTATUS("vaDestroySurfaces");
328
329    return (vaStatus == VA_STATUS_SUCCESS) ? STATUS_OK : STATUS_ERROR;
330}
331
332status_t ISVWorker::configFilters(uint32_t filters,
333                                  const FilterParam* filterParam)
334{
335    status_t ret = STATUS_OK;
336
337    if (!filterParam) {
338        ALOGE("%s: invalid filterParam", __func__);
339        return STATUS_ERROR;
340    }
341
342    if (filters != 0) {
343        mFilterParam.srcWidth = filterParam->srcWidth;
344        mFilterParam.srcHeight = filterParam->srcHeight;
345        mFilterParam.dstWidth = filterParam->dstWidth;
346        mFilterParam.dstHeight = filterParam->dstHeight;
347        mFilterParam.frameRate = filterParam->frameRate;
348        mFilterParam.frcRate = filterParam->frcRate;
349    }
350
351    if (mFilters != filters) {
352        mFilters = filters;
353        ALOGI("%s: mFilters 0x%x, fps %d, frc rate %d", __func__, mFilters, mFilterParam.frameRate, mFilterParam.frcRate);
354        ret = setupFilters();
355    }
356
357    return ret;
358}
359
360bool ISVWorker::isFpsSupport(int32_t fps, int32_t *fpsSet, int32_t fpsSetCnt) {
361    bool ret = false;
362    for (int32_t i = 0; i < fpsSetCnt; i++) {
363        if (fps == fpsSet[i]) {
364            ret = true;
365            break;
366        }
367    }
368
369    return ret;
370}
371
372status_t ISVWorker::setupFilters() {
373    ALOGV("setupFilters");
374    VAProcFilterParameterBuffer deblock, denoise, sharpen, stde;
375    VAProcFilterParameterBufferDeinterlacing deint;
376    VAProcFilterParameterBufferColorBalance color[COLOR_NUM];
377    VAProcFilterParameterBufferFrameRateConversion frc;
378    VABufferID deblockId, denoiseId, deintId, sharpenId, colorId, frcId, stdeId;
379    uint32_t numCaps;
380    VAProcFilterCap deblockCaps, denoiseCaps, sharpenCaps, frcCaps, stdeCaps;
381    VAProcFilterCapDeinterlacing deinterlacingCaps[VAProcDeinterlacingCount];
382    VAProcFilterCapColorBalance colorCaps[COLOR_NUM];
383    VAStatus vaStatus;
384    uint32_t numSupportedFilters = VAProcFilterCount;
385    VAProcFilterType supportedFilters[VAProcFilterCount];
386
387    if (mNumFilterBuffers != 0) {
388        for (uint32_t i = 0; i < mNumFilterBuffers; i++) {
389            if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, mFilterBuffers[i]))
390                ALOGW("%s: failed to destroy va buffer %d", __func__, mFilterBuffers[i]);
391                //return STATUS_ERROR;
392        }
393        memset(&mFilterBuffers, VA_INVALID_ID, VAProcFilterCount * sizeof(VABufferID));
394        mFilterFrc = VA_INVALID_ID;
395        mNumFilterBuffers = 0;
396    }
397
398    // query supported filters
399    vaStatus = vaQueryVideoProcFilters(mVADisplay, mVAContext, supportedFilters, &numSupportedFilters);
400    CHECK_VASTATUS("vaQueryVideoProcFilters");
401
402    // create filter buffer for each filter
403    for (uint32_t i = 0; i < numSupportedFilters; i++) {
404        switch (supportedFilters[i]) {
405            case VAProcFilterDeblocking:
406                if ((mFilters & FilterDeblocking) != 0) {
407                    // check filter caps
408                    numCaps = 1;
409                    vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext,
410                            VAProcFilterDeblocking,
411                            &deblockCaps,
412                            &numCaps);
413                    CHECK_VASTATUS("vaQueryVideoProcFilterCaps for deblocking");
414                    // create parameter buffer
415                    deblock.type = VAProcFilterDeblocking;
416                    deblock.value = deblockCaps.range.min_value + DENOISE_DEBLOCK_STRENGTH * deblockCaps.range.step;
417                    vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
418                        VAProcFilterParameterBufferType, sizeof(deblock), 1,
419                        &deblock, &deblockId);
420                    CHECK_VASTATUS("vaCreateBuffer for deblocking");
421                    mFilterBuffers[mNumFilterBuffers] = deblockId;
422                    mNumFilterBuffers++;
423                }
424                break;
425            case VAProcFilterNoiseReduction:
426                if((mFilters & FilterNoiseReduction) != 0) {
427                    // check filter caps
428                    numCaps = 1;
429                    vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext,
430                            VAProcFilterNoiseReduction,
431                            &denoiseCaps,
432                            &numCaps);
433                    CHECK_VASTATUS("vaQueryVideoProcFilterCaps for denoising");
434                    // create parameter buffer
435                    denoise.type = VAProcFilterNoiseReduction;
436#ifdef TARGET_VPP_USE_GEN
437                    char propValueString[PROPERTY_VALUE_MAX];
438
439                    // placeholder for vpg driver: can't support denoise factor auto adjust, so leave config to user.
440                    property_get("vpp.filter.denoise.factor", propValueString, "64.0");
441                    denoise.value = atof(propValueString);
442                    denoise.value = (denoise.value < 0.0f) ? 0.0f : denoise.value;
443                    denoise.value = (denoise.value > 64.0f) ? 64.0f : denoise.value;
444#else
445                    denoise.value = denoiseCaps.range.min_value + DENOISE_DEBLOCK_STRENGTH * denoiseCaps.range.step;
446#endif
447                    vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
448                        VAProcFilterParameterBufferType, sizeof(denoise), 1,
449                        &denoise, &denoiseId);
450                    CHECK_VASTATUS("vaCreateBuffer for denoising");
451                    mFilterBuffers[mNumFilterBuffers] = denoiseId;
452                    mNumFilterBuffers++;
453                }
454                break;
455            case VAProcFilterDeinterlacing:
456                if ((mFilters & FilterDeinterlacing) != 0) {
457                    numCaps = VAProcDeinterlacingCount;
458                    vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext,
459                            VAProcFilterDeinterlacing,
460                            &deinterlacingCaps[0],
461                            &numCaps);
462                    CHECK_VASTATUS("vaQueryVideoProcFilterCaps for deinterlacing");
463                    for (uint32_t i = 0; i < numCaps; i++)
464                    {
465                        VAProcFilterCapDeinterlacing * const cap = &deinterlacingCaps[i];
466                        if (cap->type != VAProcDeinterlacingBob) // desired Deinterlacing Type
467                            continue;
468
469                        deint.type = VAProcFilterDeinterlacing;
470                        deint.algorithm = VAProcDeinterlacingBob;
471                        vaStatus = vaCreateBuffer(mVADisplay,
472                                mVAContext,
473                                VAProcFilterParameterBufferType,
474                                sizeof(deint), 1,
475                                &deint, &deintId);
476                        CHECK_VASTATUS("vaCreateBuffer for deinterlacing");
477                        mFilterBuffers[mNumFilterBuffers] = deintId;
478                        mNumFilterBuffers++;
479                    }
480                }
481                break;
482            case VAProcFilterSharpening:
483                if((mFilters & FilterSharpening) != 0) {
484                    // check filter caps
485                    numCaps = 1;
486                    vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext,
487                            VAProcFilterSharpening,
488                            &sharpenCaps,
489                            &numCaps);
490                    CHECK_VASTATUS("vaQueryVideoProcFilterCaps for sharpening");
491                    // create parameter buffer
492                    sharpen.type = VAProcFilterSharpening;
493#ifdef TARGET_VPP_USE_GEN
494                    char propValueString[PROPERTY_VALUE_MAX];
495
496                    // placeholder for vpg driver: can't support sharpness factor auto adjust, so leave config to user.
497                    property_get("vpp.filter.sharpen.factor", propValueString, "8.0");
498                    sharpen.value = atof(propValueString);
499                    sharpen.value = (sharpen.value < 0.0f) ? 0.0f : sharpen.value;
500                    sharpen.value = (sharpen.value > 64.0f) ? 64.0f : sharpen.value;
501#else
502                    sharpen.value = sharpenCaps.range.default_value;
503#endif
504                    vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
505                        VAProcFilterParameterBufferType, sizeof(sharpen), 1,
506                        &sharpen, &sharpenId);
507                    CHECK_VASTATUS("vaCreateBuffer for sharpening");
508                    mFilterBuffers[mNumFilterBuffers] = sharpenId;
509                    mNumFilterBuffers++;
510                }
511                break;
512            case VAProcFilterColorBalance:
513                if((mFilters & FilterColorBalance) != 0) {
514                    uint32_t featureCount = 0;
515                    // check filter caps
516                    // FIXME: it's not used at all!
517                    numCaps = COLOR_NUM;
518                    vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext,
519                            VAProcFilterColorBalance,
520                            colorCaps,
521                            &numCaps);
522                    CHECK_VASTATUS("vaQueryVideoProcFilterCaps for color balance");
523                    // create parameter buffer
524                    for (uint32_t i = 0; i < numCaps; i++) {
525                        if (colorCaps[i].type == VAProcColorBalanceAutoSaturation) {
526                            color[i].type = VAProcFilterColorBalance;
527                            color[i].attrib = VAProcColorBalanceAutoSaturation;
528                            color[i].value = colorCaps[i].range.min_value + COLOR_STRENGTH * colorCaps[i].range.step;
529                            featureCount++;
530                        }
531                        else if (colorCaps[i].type == VAProcColorBalanceAutoBrightness) {
532                            color[i].type = VAProcFilterColorBalance;
533                            color[i].attrib = VAProcColorBalanceAutoBrightness;
534                            color[i].value = colorCaps[i].range.min_value + COLOR_STRENGTH * colorCaps[i].range.step;
535                            featureCount++;
536                        }
537                    }
538#ifdef TARGET_VPP_USE_GEN
539                    //TODO: VPG need to support check input value by colorCaps.
540                    enum {kHue = 0, kSaturation, kBrightness, kContrast};
541                    char propValueString[PROPERTY_VALUE_MAX];
542                    color[kHue].type = VAProcFilterColorBalance;
543                    color[kHue].attrib = VAProcColorBalanceHue;
544
545                    // placeholder for vpg driver: can't support auto color balance, so leave config to user.
546                    property_get("vpp.filter.procamp.hue", propValueString, "179.0");
547                    color[kHue].value = atof(propValueString);
548                    color[kHue].value = (color[kHue].value < -180.0f) ? -180.0f : color[kHue].value;
549                    color[kHue].value = (color[kHue].value > 180.0f) ? 180.0f : color[kHue].value;
550                    featureCount++;
551
552                    color[kSaturation].type   = VAProcFilterColorBalance;
553                    color[kSaturation].attrib = VAProcColorBalanceSaturation;
554                    property_get("vpp.filter.procamp.saturation", propValueString, "1.0");
555                    color[kSaturation].value = atof(propValueString);
556                    color[kSaturation].value = (color[kSaturation].value < 0.0f) ? 0.0f : color[kSaturation].value;
557                    color[kSaturation].value = (color[kSaturation].value > 10.0f) ? 10.0f : color[kSaturation].value;
558                    featureCount++;
559
560                    color[kBrightness].type   = VAProcFilterColorBalance;
561                    color[kBrightness].attrib = VAProcColorBalanceBrightness;
562                    property_get("vpp.filter.procamp.brightness", propValueString, "0.0");
563                    color[kBrightness].value = atof(propValueString);
564                    color[kBrightness].value = (color[kBrightness].value < -100.0f) ? -100.0f : color[kBrightness].value;
565                    color[kBrightness].value = (color[kBrightness].value > 100.0f) ? 100.0f : color[kBrightness].value;
566                    featureCount++;
567
568                    color[kContrast].type   = VAProcFilterColorBalance;
569                    color[kContrast].attrib = VAProcColorBalanceContrast;
570                    property_get("vpp.filter.procamp.contrast", propValueString, "1.0");
571                    color[kContrast].value = atof(propValueString);
572                    color[kContrast].value = (color[kContrast].value < 0.0f) ? 0.0f : color[kContrast].value;
573                    color[kContrast].value = (color[kContrast].value > 10.0f) ? 10.0f : color[kContrast].value;
574                    featureCount++;
575#endif
576                    vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
577                        VAProcFilterParameterBufferType, sizeof(*color), featureCount,
578                        color, &colorId);
579                    CHECK_VASTATUS("vaCreateBuffer for color balance");
580                    mFilterBuffers[mNumFilterBuffers] = colorId;
581                    mNumFilterBuffers++;
582                }
583                break;
584            case VAProcFilterFrameRateConversion:
585                if((mFilters & FilterFrameRateConversion) != 0) {
586                    frc.type = VAProcFilterFrameRateConversion;
587                    frc.input_fps = mFilterParam.frameRate;
588                    switch (mFilterParam.frcRate){
589                        case FRC_RATE_1X:
590                            frc.output_fps = frc.input_fps;
591                            break;
592                        case FRC_RATE_2X:
593                            frc.output_fps = frc.input_fps * 2;
594                            break;
595                        case FRC_RATE_2_5X:
596                            frc.output_fps = frc.input_fps * 5/2;
597                            break;
598                        case FRC_RATE_4X:
599                            frc.output_fps = frc.input_fps * 4;
600                            break;
601                    }
602                    vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
603                        VAProcFilterParameterBufferType, sizeof(frc), 1,
604                        &frc, &frcId);
605                    CHECK_VASTATUS("vaCreateBuffer for frc");
606                    mFilterBuffers[mNumFilterBuffers] = frcId;
607                    mNumFilterBuffers++;
608                    mFilterFrc = frcId;
609                }
610                break;
611            case VAProcFilterSkinToneEnhancement:
612                if((mFilters & FilterSkinToneEnhancement) != 0) {
613                    // check filter caps
614                    numCaps = 1;
615                    vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext,
616                            VAProcFilterSkinToneEnhancement,
617                            &stdeCaps,
618                            &numCaps);
619                    CHECK_VASTATUS("vaQueryVideoProcFilterCaps for skintone");
620                    // create parameter buffer
621                    stde.type = VAProcFilterSkinToneEnhancement;
622#ifdef TARGET_VPP_USE_GEN
623                    char propValueString[PROPERTY_VALUE_MAX];
624
625                    // placeholder for vpg driver: can't support skintone factor auto adjust, so leave config to user.
626                    property_get("vpp.filter.skintone.factor", propValueString, "8.0");
627                    stde.value = atof(propValueString);
628                    stde.value = (stde.value < 0.0f) ? 0.0f : stde.value;
629                    stde.value = (stde.value > 8.0f) ? 8.0f : stde.value;
630#else
631                    stde.value = stdeCaps.range.default_value;
632#endif
633                    vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
634                        VAProcFilterParameterBufferType, sizeof(stde), 1,
635                        &stde, &stdeId);
636                    CHECK_VASTATUS("vaCreateBuffer for skintone");
637                    mFilterBuffers[mNumFilterBuffers] = stdeId;
638                    mNumFilterBuffers++;
639                }
640                break;
641            default:
642                ALOGW("%s: Not supported filter 0x%08x", __func__, supportedFilters[i]);
643                break;
644        }
645    }
646
647    return setupPipelineCaps();
648}
649
650status_t ISVWorker::setupPipelineCaps() {
651    ALOGV("setupPipelineCaps");
652    //TODO color standards
653    VAProcPipelineCaps pipelineCaps;
654    VAStatus vaStatus;
655    pipelineCaps.input_color_standards = in_color_standards;
656    pipelineCaps.num_input_color_standards = VAProcColorStandardCount;
657    pipelineCaps.output_color_standards = out_color_standards;
658    pipelineCaps.num_output_color_standards = VAProcColorStandardCount;
659
660    vaStatus = vaQueryVideoProcPipelineCaps(mVADisplay, mVAContext,
661        mFilterBuffers, mNumFilterBuffers,
662        &pipelineCaps);
663    CHECK_VASTATUS("vaQueryVideoProcPipelineCaps");
664
665    if (mForwardReferences != NULL) {
666        free(mForwardReferences);
667        mForwardReferences = NULL;
668        mNumForwardReferences = 0;
669    }
670
671    mNumForwardReferences = pipelineCaps.num_forward_references;
672    if (mNumForwardReferences > 0) {
673        mForwardReferences = (VASurfaceID*)malloc(mNumForwardReferences * sizeof(VASurfaceID));
674        if (mForwardReferences == NULL)
675            return STATUS_ALLOCATION_ERROR;
676        memset(mForwardReferences, 0, mNumForwardReferences * sizeof(VASurfaceID));
677    }
678    return STATUS_OK;
679}
680
681status_t ISVWorker::process(ISVBuffer* inputBuffer, Vector<ISVBuffer*> outputBuffer,
682                             uint32_t outputCount, bool isEOS, uint32_t flags) {
683    ALOGV("process: outputCount=%d, mInputIndex=%d", outputCount, mInputIndex);
684    VASurfaceID input;
685    VASurfaceID output[MAX_FRC_OUTPUT];
686    VABufferID pipelineId;
687    VAProcPipelineParameterBuffer *pipeline;
688    VAProcFilterParameterBufferFrameRateConversion *frc;
689    VAStatus vaStatus = STATUS_OK;
690    uint32_t i = 0;
691
692    if (isEOS) {
693        if (mInputIndex == 0) {
694            ALOGV("%s: don't need to flush VSP", __func__);
695            return STATUS_OK;
696        }
697        input = VA_INVALID_SURFACE;
698        outputCount = 1;
699        output[0] = mPrevOutput;
700    } else {
701        if (!inputBuffer || outputBuffer.size() != outputCount) {
702            ALOGE("%s: invalid input/output buffer", __func__);
703            return STATUS_ERROR;
704        }
705
706        if (outputCount < 1 || outputCount > 4) {
707            ALOGE("%s: invalid outputCount", __func__);
708            return STATUS_ERROR;
709        }
710
711        input = inputBuffer->getSurface();
712        for (i = 0; i < outputCount; i++) {
713            output[i] = outputBuffer[i]->getSurface();
714            if (output[i] == VA_INVALID_SURFACE) {
715                ALOGE("invalid output buffer");
716                return STATUS_ERROR;
717            }
718        }
719    }
720
721    // reference frames setting
722    if (mNumForwardReferences > 0) {
723        /* add previous frame into reference array*/
724        for (i = 1; i < mNumForwardReferences; i++) {
725            mForwardReferences[i - 1] = mForwardReferences[i];
726        }
727
728        //make last reference to input
729        mForwardReferences[mNumForwardReferences - 1] = mPrevInput;
730    }
731
732    mPrevInput = input;
733
734    // create pipeline parameter buffer
735    vaStatus = vaCreateBuffer(mVADisplay,
736            mVAContext,
737            VAProcPipelineParameterBufferType,
738            sizeof(VAProcPipelineParameterBuffer),
739            1,
740            NULL,
741            &pipelineId);
742    CHECK_VASTATUS("vaCreateBuffer for VAProcPipelineParameterBufferType");
743
744    ALOGV("before vaBeginPicture");
745    vaStatus = vaBeginPicture(mVADisplay, mVAContext, output[0]);
746    CHECK_VASTATUS("vaBeginPicture");
747
748    // map pipeline paramter buffer
749    vaStatus = vaMapBuffer(mVADisplay, pipelineId, (void**)&pipeline);
750    CHECK_VASTATUS("vaMapBuffer for pipeline parameter buffer");
751
752    // frc pamameter setting
753    if ((mFilters & FilterFrameRateConversion) != 0) {
754        vaStatus = vaMapBuffer(mVADisplay, mFilterFrc, (void **)&frc);
755        CHECK_VASTATUS("vaMapBuffer for frc parameter buffer");
756        if (isEOS)
757            frc->num_output_frames = 0;
758        else
759            frc->num_output_frames = outputCount - 1;
760        frc->output_frames = output + 1;
761    }
762
763    // pipeline parameter setting
764    VARectangle dst_region;
765    dst_region.x = 0;
766    dst_region.y = 0;
767    dst_region.width = mFilterParam.dstWidth;
768    dst_region.height = mFilterParam.dstHeight;
769
770    VARectangle src_region;
771    src_region.x = 0;
772    src_region.y = 0;
773    src_region.width = mFilterParam.srcWidth;
774    src_region.height = mFilterParam.srcHeight;
775
776    if (isEOS) {
777        pipeline->surface = 0;
778        pipeline->pipeline_flags = VA_PIPELINE_FLAG_END;
779    }
780    else {
781        pipeline->surface = input;
782        pipeline->pipeline_flags = 0;
783    }
784#ifdef TARGET_VPP_USE_GEN
785    pipeline->surface_region = &src_region;
786    pipeline->output_region = &dst_region;
787    pipeline->surface_color_standard = VAProcColorStandardBT601;
788    pipeline->output_color_standard = VAProcColorStandardBT601;
789#else
790    pipeline->surface_region = NULL;
791    pipeline->output_region = NULL;//&output_region;
792    pipeline->surface_color_standard = VAProcColorStandardNone;
793    pipeline->output_color_standard = VAProcColorStandardNone;
794    /* real rotate state will be decided in psb video */
795    pipeline->rotation_state = 0;
796#endif
797    /* FIXME: set more meaningful background color */
798    pipeline->output_background_color = 0;
799    pipeline->filters = mFilterBuffers;
800    pipeline->num_filters = mNumFilterBuffers;
801    pipeline->forward_references = mForwardReferences;
802    pipeline->num_forward_references = mNumForwardReferences;
803    pipeline->backward_references = NULL;
804    pipeline->num_backward_references = 0;
805
806    //currently, we only transfer TOP field to frame, no frame rate change.
807    if (flags & (OMX_BUFFERFLAG_TFF | OMX_BUFFERFLAG_BFF)) {
808        pipeline->filter_flags = VA_TOP_FIELD;
809    } else {
810        pipeline->filter_flags = VA_FRAME_PICTURE;
811    }
812
813    if ((mFilters & FilterFrameRateConversion) != 0) {
814        vaStatus = vaUnmapBuffer(mVADisplay, mFilterFrc);
815        CHECK_VASTATUS("vaUnmapBuffer for frc parameter buffer");
816    }
817
818    vaStatus = vaUnmapBuffer(mVADisplay, pipelineId);
819    CHECK_VASTATUS("vaUnmapBuffer for pipeline parameter buffer");
820
821    ALOGV("before vaRenderPicture");
822    // Send parameter to driver
823    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &pipelineId, 1);
824    CHECK_VASTATUS("vaRenderPicture");
825
826    ALOGV("before vaEndPicture");
827    vaStatus = vaEndPicture(mVADisplay, mVAContext);
828    CHECK_VASTATUS("vaEndPicture");
829
830    if (isEOS) {
831        vaStatus = vaSyncSurface(mVADisplay, mPrevOutput);
832        CHECK_VASTATUS("vaSyncSurface");
833        if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, pipelineId)) {
834            ALOGE("%s: failed to destroy va buffer %d", __func__, pipelineId);
835            return STATUS_ERROR;
836        }
837        return STATUS_OK;
838    }
839
840    mPrevOutput = output[0];
841    mInputIndex++;
842
843    Mutex::Autolock autoLock(mPipelineBufferLock);
844    mPipelineBuffers.push_back(pipelineId);
845
846    ALOGV("process, exit");
847    return STATUS_OK;
848}
849
850status_t ISVWorker::fill(Vector<ISVBuffer*> outputBuffer, uint32_t outputCount) {
851    ALOGV("fill, outputCount=%d, mOutputIndex=%d",outputCount, mOutputIndex);
852    // get output surface
853    VASurfaceID output[MAX_FRC_OUTPUT];
854    VAStatus vaStatus;
855    VASurfaceStatus surStatus;
856
857    if (outputCount < 1)
858        return STATUS_ERROR;
859    // map GraphicBuffer to VASurface
860    for (uint32_t i = 0; i < outputCount; i++) {
861
862        output[i] = outputBuffer[i]->getSurface();
863        if (output[i] == VA_INVALID_SURFACE) {
864            ALOGE("invalid output buffer");
865            return STATUS_ERROR;
866        }
867        //FIXME: only enable sync mode
868#if 0
869        vaStatus = vaQuerySurfaceStatus(mVADisplay, output[i],&surStatus);
870        CHECK_VASTATUS("vaQuerySurfaceStatus");
871        if (surStatus == VASurfaceRendering) {
872            ALOGV("Rendering %d", i);
873            /* The behavior of driver is: all output of one process task are return in one interruption.
874               The whole outputs of one FRC task are all ready or none of them is ready.
875               If the behavior changed, it hurts the performance.
876            */
877            if (0 != i) {
878                ALOGW("*****Driver behavior changed. The performance is hurt.");
879                ALOGW("Please check driver behavior: all output of one task return in one interruption.");
880            }
881            vaStatus = STATUS_DATA_RENDERING;
882            break;
883        }
884
885        if ((surStatus != VASurfaceRendering) && (surStatus != VASurfaceReady)) {
886            ALOGE("surface statu Error %d", surStatus);
887            vaStatus = STATUS_ERROR;
888        }
889#endif
890        vaStatus = vaSyncSurface(mVADisplay, output[i]);
891        CHECK_VASTATUS("vaSyncSurface");
892        vaStatus = STATUS_OK;
893        mOutputCount++;
894        //dumpYUVFrameData(output[i]);
895    }
896
897    {
898        Mutex::Autolock autoLock(mPipelineBufferLock);
899        if (vaStatus == STATUS_OK) {
900            VABufferID pipelineBuffer = mPipelineBuffers.itemAt(0);
901            if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, pipelineBuffer)) {
902                ALOGE("%s: failed to destroy va buffer %d", __func__, pipelineBuffer);
903                return STATUS_ERROR;
904            }
905            mPipelineBuffers.removeAt(0);
906            mOutputIndex++;
907        }
908    }
909
910    ALOGV("fill, exit");
911    return vaStatus;
912}
913
914// Debug only
915#define FRAME_OUTPUT_FILE_NV12 "/storage/sdcard0/vpp_output.nv12"
916status_t ISVWorker::dumpYUVFrameData(VASurfaceID surfaceID) {
917    status_t ret;
918    if (surfaceID == VA_INVALID_SURFACE)
919        return STATUS_ERROR;
920
921    VAStatus vaStatus;
922    VAImage image;
923    unsigned char *data_ptr;
924
925    vaStatus = vaDeriveImage(mVADisplay,
926            surfaceID,
927            &image);
928    CHECK_VASTATUS("vaDeriveImage");
929
930    vaStatus = vaMapBuffer(mVADisplay, image.buf, (void **)&data_ptr);
931    CHECK_VASTATUS("vaMapBuffer");
932
933    ret = writeNV12(mFilterParam.srcWidth, mFilterParam.srcHeight, data_ptr, image.pitches[0], image.pitches[1]);
934    if (ret != STATUS_OK) {
935        ALOGV("writeNV12 error");
936        return STATUS_ERROR;
937    }
938
939    vaStatus = vaUnmapBuffer(mVADisplay, image.buf);
940    CHECK_VASTATUS("vaUnMapBuffer");
941
942    vaStatus = vaDestroyImage(mVADisplay,image.image_id);
943    CHECK_VASTATUS("vaDestroyImage");
944
945    return STATUS_OK;
946}
947
948status_t ISVWorker::reset() {
949    status_t ret;
950    ALOGV("reset");
951    if (mOutputCount > 0) {
952        ALOGI("======mVPPInputCount=%d, mVPPRenderCount=%d======",
953                mInputIndex, mOutputCount);
954    }
955    mInputIndex = 0;
956    mOutputIndex = 0;
957    mOutputCount = 0;
958
959    {
960        Mutex::Autolock autoLock(mPipelineBufferLock);
961        while (!mPipelineBuffers.isEmpty()) {
962            VABufferID pipelineBuffer = mPipelineBuffers.itemAt(0);
963            if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, pipelineBuffer)) {
964                ALOGE("%s: failed to destroy va buffer %d", __func__, pipelineBuffer);
965                return STATUS_ERROR;
966            }
967            mPipelineBuffers.removeAt(0);
968        }
969    }
970
971    if (mNumFilterBuffers != 0) {
972        for (uint32_t i = 0; i < mNumFilterBuffers; i++) {
973            if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, mFilterBuffers[i]))
974                ALOGW("%s: failed to destroy va buffer %d", __func__, mFilterBuffers[i]);
975                //return STATUS_ERROR;
976        }
977        mNumFilterBuffers = 0;
978        memset(&mFilterBuffers, VA_INVALID_ID, VAProcFilterCount * sizeof(VABufferID));
979        mFilterFrc = VA_INVALID_ID;
980    }
981
982    // we need to clear the cache for reference surfaces
983    if (mForwardReferences != NULL) {
984        free(mForwardReferences);
985        mForwardReferences = NULL;
986        mNumForwardReferences = 0;
987    }
988
989    if (mVAContext != VA_INVALID_ID) {
990         vaDestroyContext(mVADisplay, mVAContext);
991         mVAContext = VA_INVALID_ID;
992    }
993    VAStatus vaStatus = vaCreateContext(mVADisplay, mVAConfig, mWidth, mHeight, 0, NULL, 0, &mVAContext);
994    CHECK_VASTATUS("vaCreateContext");
995
996    return setupFilters();
997}
998
999uint32_t ISVWorker::getVppOutputFps() {
1000    uint32_t outputFps;
1001    //mFilterParam.frcRate is 1 if FRC is disabled or input FPS is not changed by VPP.
1002    if (FRC_RATE_2_5X == mFilterParam.frcRate) {
1003        outputFps = mFilterParam.frameRate * 5 / 2;
1004    } else {
1005        outputFps = mFilterParam.frameRate * mFilterParam.frcRate;
1006    }
1007
1008    ALOGV("vpp is on in settings %d %d %d", outputFps,  mFilterParam.frameRate, mFilterParam.frcRate);
1009    return outputFps;
1010}
1011
1012
1013status_t ISVWorker::writeNV12(int width, int height, unsigned char *out_buf, int y_pitch, int uv_pitch) {
1014    size_t result;
1015    int frame_size;
1016    unsigned char *y_start, *uv_start;
1017    int h;
1018
1019    FILE *ofile = fopen(FRAME_OUTPUT_FILE_NV12, "ab");
1020    if(ofile == NULL) {
1021        ALOGE("Open %s failed!", FRAME_OUTPUT_FILE_NV12);
1022        return STATUS_ERROR;
1023    }
1024
1025    if (out_buf == NULL)
1026    {
1027        fclose(ofile);
1028        return STATUS_ERROR;
1029    }
1030    if ((width % 2) || (height % 2))
1031    {
1032        fclose(ofile);
1033        return STATUS_ERROR;
1034    }
1035    // Set frame size
1036    frame_size = height * width * 3/2;
1037
1038    /* write y */
1039    y_start = out_buf;
1040    for (h = 0; h < height; ++h) {
1041        result = fwrite(y_start, sizeof(unsigned char), width, ofile);
1042        y_start += y_pitch;
1043    }
1044
1045    /* write uv */
1046    uv_start = out_buf + uv_pitch * height;
1047    for (h = 0; h < height / 2; ++h) {
1048        result = fwrite(uv_start, sizeof(unsigned char), width, ofile);
1049        uv_start += uv_pitch;
1050    }
1051    // Close file
1052    fclose(ofile);
1053    return STATUS_OK;
1054}
1055
1056