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