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