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