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