• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  #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  
freeSurface(int32_t * surfaceId)308  status_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  
configFilters(uint32_t filters,const FilterParam * filterParam)317  status_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  
isFpsSupport(int32_t fps,int32_t * fpsSet,int32_t fpsSetCnt)345  bool 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  
setupFilters()357  status_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  
setupPipelineCaps()635  status_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  
process(ISVBuffer * inputBuffer,Vector<ISVBuffer * > outputBuffer,uint32_t outputCount,bool isEOS,uint32_t flags)666  status_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  
fill(Vector<ISVBuffer * > outputBuffer,uint32_t outputCount)835  status_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"
dumpYUVFrameData(VASurfaceID surfaceID)901  status_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  
reset()933  status_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  
getVppOutputFps()984  uint32_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  
writeNV12(int width,int height,unsigned char * out_buf,int y_pitch,int uv_pitch)998  status_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