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