1 /**
2 \brief vaapi filters
3 \author mean (C) 2016
4 * Use VA-API video processing API
5 * (c) mean 2016
6 *
7 */
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17 #include "ADM_default.h"
18 #include <list>
19 #include "ADM_coreLibVA.h"
20 #include "ADM_coreVideoFilter.h"
21 #include "ADM_videoFilterCache.h"
22 #include "ADM_vidMisc.h"
23 #include "DIA_factory.h"
24 #include "DIA_coreToolkit.h"
25 #include "vaapiFilterDeint.h"
26 #include "vaapiFilterDeint_desc.cpp"
27
28 /**
29 \class vaapiSlot
30 */
31 class vaapiSlot
32 {
33 public:
34 ADM_vaSurface *surface;
35 bool external;
36 uint64_t pts;
37
38 vaapiSlot();
39 ~vaapiSlot();
40 void reset(void);
41 };
42
vaapiSlot()43 vaapiSlot::vaapiSlot()
44 {
45 reset();
46 }
~vaapiSlot()47 vaapiSlot::~vaapiSlot() {}
48
reset(void)49 void vaapiSlot::reset(void)
50 {
51 surface=NULL;
52 external=false;
53 pts=ADM_NO_PTS;
54 }
55 #define ADM_VAAPI_DEINT_MAX_REF 8
56
57 /**
58 \class vaapiVideoFilterDeint
59 */
60 class vaapiVideoFilterDeint : public ADM_coreVideoFilterCached
61 {
62 protected:
63 enum
64 {
65 ADM_VAAPI_DEINT_TOP_FIELD_FIRST=0,
66 ADM_VAAPI_DEINT_BOTTOM_FIELD_FIRST=1
67 };
68 enum
69 {
70 ADM_VAAPI_DEINT_SEND_FRAME=0,
71 ADM_VAAPI_DEINT_SEND_FIELD=1
72 };
73
74 vaapiSlot *inputQueue;
75 uint32_t queueLength;
76 std::list <ADM_vaSurface *> freeSurfaces;
77 ADM_vaSurface *surfacePool[ADM_VAAPI_DEINT_MAX_REF];
78 ADM_vaSurface *outputSurface;
79 VAConfigID configId;
80 VAContextID contextId;
81 VABufferID filterBuffer;
82 uint32_t algoCount; // actually supported by hardware and driver
83 uint32_t unsupported; // specified deint method rejected by driver
84 VASurfaceID *forwardRefs, *backwardRefs;
85 uint32_t nbForwardRefs,nbBackwardRefs;
86
87 vaapiFilterDeint configuration;
88 uint64_t deltaPts;
89 bool passThrough;
90 bool preloadCompleted;
91 bool secondField;
92
93 bool setupVaapi(void);
94 bool cleanupVaapi(void);
95
96 bool rotateSlots(void);
97 bool clearSlots(void);
98 bool fillSlot(uint32_t slot,ADMImage *image);
99
100 bool updateInfo(bool status);
101
102 public:
103
104 vaapiVideoFilterDeint(ADM_coreVideoFilter *previous,CONFcouple *conf);
105 ~vaapiVideoFilterDeint();
106
107 virtual const char *getConfiguration(void); // Return current configuration as a human readable string
108 virtual bool getNextFrame(uint32_t *fn,ADMImage *image); // Return the next image
109 virtual bool getCoupledConf(CONFcouple **couples); // Return the current filter configuration
110 virtual void setCoupledConf(CONFcouple *couples);
111 virtual bool configure(void); // Start graphical user interface
112 virtual bool goToTime(uint64_t usSeek);
113 };
114
115 // Add the hook to make it valid plugin
116 DECLARE_VIDEO_FILTER( vaapiVideoFilterDeint, // Class
117 1,0,0, // Version
118 (ADM_UI_QT4+ADM_FEATURE_LIBVA), // We need a display for VA-API; so no cli...
119 VF_INTERLACING, // Category
120 "vaapiDeint", // internal name (must be uniq!)
121 QT_TRANSLATE_NOOP("vaapiDeint","VA-API Deinterlacer"), // Display name
122 QT_TRANSLATE_NOOP("vaapiDeint","Deinterlace and optionally resize video using VA-API.") // Description
123 )
124
deintModeToString(uint32_t mode)125 static const char *deintModeToString(uint32_t mode)
126 {
127 switch(mode)
128 {
129 #define DEINT(algo,name) case VAProcDeinterlacing##algo: return #name;
130 DEINT(Bob,Bob)
131 DEINT(Weave,Weave)
132 DEINT(MotionAdaptive,Motion-Adaptive)
133 DEINT(MotionCompensated,Motion-Compensated)
134 default:
135 return "Invalid";
136 #undef DEINT
137 }
138 }
139
140 /**
141 \fn setupVaapi
142 */
setupVaapi(void)143 bool vaapiVideoFilterDeint::setupVaapi(void)
144 {
145 unsupported = 0;
146
147 if(!admLibVA::isOperationnal())
148 {
149 ADM_warning("HW accel is not available.\n");
150 return false;
151 }
152
153 configId = admLibVA::createFilterConfig();
154 if(configId == VA_INVALID)
155 {
156 ADM_warning("Cannot create config\n");
157 return false;
158 }
159 // Allocate output surface
160 uint32_t outWidth=configuration.targetWidth;
161 uint32_t outHeight=configuration.targetHeight;
162 FilterInfo *prevInfo=previousFilter->getInfo();
163 ADM_assert(prevInfo);
164
165 if(!configuration.resize)
166 {
167 outWidth=prevInfo->width;
168 outHeight=prevInfo->height;
169 }
170
171 outputSurface = ADM_vaSurface::allocateWithSurface(outWidth, outHeight);
172 if(!outputSurface)
173 {
174 ADM_warning("Cannot allocate output surface with size %u x %u\n", outWidth, outHeight);
175 cleanupVaapi();
176 return false;
177 }
178
179 VAStatus status = vaCreateContext(admLibVA::getDisplay(), configId,
180 outWidth, outHeight, VA_PROGRESSIVE,
181 &outputSurface->surface, 1, &contextId);
182
183 if(status != VA_STATUS_SUCCESS)
184 {
185 ADM_warning("Cannot create context: error %d (%s)\n",status,vaErrorStr(status));
186 cleanupVaapi();
187 return false;
188 }
189 // Query supported deinterlacing algorithms
190 VAProcFilterCapDeinterlacing deintCaps[VAProcDeinterlacingCount];
191 algoCount = VAProcDeinterlacingCount;
192
193 status = vaQueryVideoProcFilterCaps(admLibVA::getDisplay(), contextId,
194 VAProcFilterDeinterlacing, &deintCaps, &algoCount);
195
196 if(status != VA_STATUS_SUCCESS)
197 {
198 ADM_warning("Cannot query deinterlacing capabilities: error %d (%s)\n",status,vaErrorStr(status));
199 cleanupVaapi();
200 return false;
201 }
202 if(algoCount)
203 ADM_info("Driver reports %u deinterlacing methods as supported.\n",algoCount);
204 else
205 {
206 ADM_error("Driver reports that deinterlacing is not supported.\n");
207 cleanupVaapi();
208 return false;
209 }
210 uint32_t i,best=(uint32_t)deintCaps[algoCount-1].type;
211 int algo = -1;
212 for(i=0; i < algoCount; i++)
213 {
214 if((uint32_t)deintCaps[i].type != configuration.deintMode)
215 continue;
216 algo = i;
217 break;
218 }
219 if(algo == -1)
220 {
221 ADM_warning("Requested deinterlacing mode %s is not supported.\n",deintModeToString(configuration.deintMode));
222 ADM_warning("Using %s instead.\n",deintModeToString(best));
223 unsupported = configuration.deintMode;
224 configuration.deintMode = best;
225 }
226 // Query required number of reference surfaces
227 VAProcFilterParameterBufferDeinterlacing deintParams;
228
229 deintParams.type = VAProcFilterDeinterlacing;
230 deintParams.algorithm = (VAProcDeinterlacingType)configuration.deintMode;
231 deintParams.flags = 0;
232
233 status = vaCreateBuffer(admLibVA::getDisplay(), contextId,
234 VAProcFilterParameterBufferType, sizeof(deintParams),
235 1, &deintParams, &filterBuffer);
236 if(status != VA_STATUS_SUCCESS)
237 {
238 ADM_warning("Cannot create parameter buffer: error %d (%s)\n",status,vaErrorStr(status));
239 cleanupVaapi();
240 return false;
241 }
242
243 VAProcPipelineCaps caps;
244
245 status = vaQueryVideoProcPipelineCaps(admLibVA::getDisplay(), contextId,
246 &filterBuffer, 1, &caps);
247 if(status != VA_STATUS_SUCCESS)
248 {
249 ADM_warning("Cannot query video pipeline capabilities: error %d (%s)\n",status,vaErrorStr(status));
250 cleanupVaapi();
251 return false;
252 }
253 nbForwardRefs = caps.num_forward_references;
254 nbBackwardRefs = caps.num_backward_references;
255 if(nbForwardRefs)
256 {
257 forwardRefs = (VASurfaceID *)malloc(nbForwardRefs * sizeof(VASurfaceID));
258 if(!forwardRefs)
259 {
260 cleanupVaapi();
261 return false;
262 }
263 }
264 if(nbBackwardRefs)
265 {
266 backwardRefs = (VASurfaceID *)malloc(nbBackwardRefs * sizeof(VASurfaceID));
267 if(!backwardRefs)
268 {
269 cleanupVaapi();
270 return false;
271 }
272 }
273 queueLength = nbForwardRefs + nbBackwardRefs + 1;
274 ADM_info("Video processing pipeline for mode %s operates with %u forward and %u backward references.\n",
275 deintModeToString(configuration.deintMode),
276 nbForwardRefs,nbBackwardRefs);
277 if(queueLength + 1 > ADM_VAAPI_DEINT_MAX_REF)
278 {
279 ADM_error("Pipeline requires too many references (%u forward, %u back).\n",nbForwardRefs,nbBackwardRefs);
280 cleanupVaapi();
281 return false;
282 }
283 // Allocate source surfaces
284 for(i=0; i < queueLength; i++)
285 {
286 ADM_vaSurface *s = ADM_vaSurface::allocateWithSurface(prevInfo->width,prevInfo->height);
287 if(!s)
288 {
289 ADM_warning("Cannot allocate input surface %d\n",i);
290 cleanupVaapi();
291 return false;
292 }
293 surfacePool[i] = s;
294 }
295 freeSurfaces.clear();
296 for(i=0; i < queueLength; i++)
297 freeSurfaces.push_back(surfacePool[i]);
298 inputQueue = new vaapiSlot[queueLength];
299 return true;
300 }
301 /**
302 \fn cleanupVaapi
303 */
cleanupVaapi(void)304 bool vaapiVideoFilterDeint::cleanupVaapi(void)
305 {
306 for(uint32_t i=0; i < queueLength; i++)
307 {
308 ADM_vaSurface *s = surfacePool[i];
309 if(s)
310 {
311 delete s;
312 surfacePool[i]=NULL;
313 }
314 }
315 if(filterBuffer!=VA_INVALID)
316 {
317 vaDestroyBuffer(admLibVA::getDisplay(), filterBuffer);
318 filterBuffer=VA_INVALID;
319 }
320 if(outputSurface)
321 {
322 delete outputSurface;
323 outputSurface=NULL;
324 }
325 if(configId!=VA_INVALID)
326 {
327 admLibVA::destroyFilterConfig(configId);
328 configId=VA_INVALID;
329 }
330 if(contextId!=VA_INVALID)
331 {
332 admLibVA::destroyFilterContext(contextId);
333 contextId=VA_INVALID;
334 }
335 if(forwardRefs)
336 free(forwardRefs);
337 forwardRefs=NULL;
338 if(backwardRefs)
339 free(backwardRefs);
340 backwardRefs=NULL;
341 if(inputQueue)
342 delete [] inputQueue;
343 inputQueue=NULL;
344 unsupported=0;
345 return true;
346 }
347 /**
348 * \fn updateInfo
349 * @param status
350 * @return
351 */
updateInfo(bool status)352 bool vaapiVideoFilterDeint::updateInfo(bool status)
353 {
354 passThrough=!status;
355 memcpy(&info,previousFilter->getInfo(),sizeof(info));
356 if(passThrough)
357 {
358 ADM_warning("PassThrough mode\n");
359 return true;
360 }
361 if(configuration.framePerField==ADM_VAAPI_DEINT_SEND_FIELD)
362 {
363 info.frameIncrement /= 2;
364 if(info.timeBaseNum && info.timeBaseDen)
365 {
366 if(info.timeBaseDen <= 30000 || (info.timeBaseNum & 1))
367 info.timeBaseDen *= 2;
368 else
369 info.timeBaseNum /= 2;
370 /* The frame increment passed along the filter chain may be based on
371 the average frame rate, but we need the minimum increment here.
372 Check whether the time base ~ matches the average increment and derive
373 the minimum increment from time base if possible. */
374 double f=1000.*1000.;
375 f /= info.timeBaseDen;
376 f *= info.timeBaseNum;
377 f += 0.49;
378 if((uint64_t)f > (uint64_t)info.frameIncrement*3/4)
379 info.frameIncrement = (uint32_t)f;
380 }
381 ADM_info("New frame increment: %u us, new time base: %u / %u\n", info.frameIncrement, info.timeBaseNum, info.timeBaseDen);
382 }
383 if(configuration.resize)
384 {
385 info.width=configuration.targetWidth;
386 info.height=configuration.targetHeight;
387 }
388 return true;
389 }
390 /**
391 \fn constructor
392 */
vaapiVideoFilterDeint(ADM_coreVideoFilter * in,CONFcouple * setup)393 vaapiVideoFilterDeint::vaapiVideoFilterDeint(ADM_coreVideoFilter *in, CONFcouple *setup)
394 : ADM_coreVideoFilterCached(ADM_VAAPI_DEINT_MAX_REF,in,setup)
395 {
396 preloadCompleted=false;
397 secondField=false;
398 configId=VA_INVALID;
399 contextId=VA_INVALID;
400 for(int i=0; i < ADM_VAAPI_DEINT_MAX_REF; i++)
401 surfacePool[i]=NULL;
402 outputSurface=NULL;
403 forwardRefs=NULL;
404 backwardRefs=NULL;
405 inputQueue=NULL;
406 queueLength=0;
407 nbForwardRefs=0;
408 nbBackwardRefs=0;
409 deltaPts=0;
410 if(!setup || !ADM_paramLoad(setup,vaapiFilterDeint_param,&configuration))
411 {
412 // Default value
413 configuration.deintMode=4;
414 configuration.fieldOrder=0;
415 configuration.framePerField=0;
416 configuration.targetWidth=info.width;
417 configuration.targetHeight=info.height;
418 configuration.resize=false;
419 }
420
421 myName="vaapiDeint";
422 bool status=setupVaapi();
423 updateInfo(status);
424 }
425 /**
426 \fn destructor
427 */
~vaapiVideoFilterDeint()428 vaapiVideoFilterDeint::~vaapiVideoFilterDeint()
429 {
430 cleanupVaapi();
431 }
432 /**
433 \fn configure
434 */
configure(void)435 bool vaapiVideoFilterDeint::configure( void)
436 {
437 diaMenuEntry deintMethod[]={
438 { VAProcDeinterlacingBob, QT_TRANSLATE_NOOP("vaapiDeint","Bob"),NULL },
439 { VAProcDeinterlacingWeave, QT_TRANSLATE_NOOP("vaapiDeint","Weave"),NULL },
440 { VAProcDeinterlacingMotionAdaptive, QT_TRANSLATE_NOOP("vaapiDeint","Motion-Adaptive"),NULL },
441 { VAProcDeinterlacingMotionCompensated, QT_TRANSLATE_NOOP("vaapiDeint","Motion-Compensated"),NULL }
442 };
443 diaMenuEntry fieldOrder[]={
444 { ADM_VAAPI_DEINT_TOP_FIELD_FIRST, QT_TRANSLATE_NOOP("vaapiDeint","Top Field First"),NULL },
445 { ADM_VAAPI_DEINT_BOTTOM_FIELD_FIRST, QT_TRANSLATE_NOOP("vaapiDeint","Bottom Field First"),NULL }
446 };
447 diaMenuEntry outputPolicy[]={
448 { ADM_VAAPI_DEINT_SEND_FRAME, QT_TRANSLATE_NOOP("vaapiDeint","Frame per Frame"),NULL },
449 { ADM_VAAPI_DEINT_SEND_FIELD, QT_TRANSLATE_NOOP("vaapiDeint","Double Framerate"),NULL }
450 };
451
452 diaElemMenu dMode(&configuration.deintMode, QT_TRANSLATE_NOOP("vaapiDeint","_Mode:"), 4, deintMethod);
453 diaElemMenu fOrder(&configuration.fieldOrder, QT_TRANSLATE_NOOP("vaapiDeint","_Field Order:"), 2, fieldOrder);
454 diaElemMenu outPol(&configuration.framePerField, QT_TRANSLATE_NOOP("vaapiDeint","_Output:"), 2, outputPolicy);
455
456 diaElemFrame frameDeint(QT_TRANSLATE_NOOP("vaapiDeint","Deinterlacing"));
457 frameDeint.swallow(&dMode);
458 frameDeint.swallow(&fOrder);
459 frameDeint.swallow(&outPol);
460
461 diaElemToggle tResize(&configuration.resize, QT_TRANSLATE_NOOP("vaapiDeint","_Resize"));
462 diaElemUInteger tWidth(&configuration.targetWidth, QT_TRANSLATE_NOOP("vaapiDeint","Width:"), 16, MAXIMUM_SIZE);
463 diaElemUInteger tHeight(&configuration.targetHeight, QT_TRANSLATE_NOOP("vaapiDeint","Height:"), 16, MAXIMUM_SIZE);
464
465 diaElemFrame frameResize(QT_TRANSLATE_NOOP("vaapiDeint","Transformation"));
466 frameResize.swallow(&tResize);
467 frameResize.swallow(&tWidth);
468 frameResize.swallow(&tHeight);
469
470 tResize.link(1,&tWidth);
471 tResize.link(1,&tHeight);
472
473 diaElem *elems[]={&frameDeint,&frameResize};
474 if(diaFactoryRun(QT_TRANSLATE_NOOP("vaapiDeint","VA-API Deinterlacer and Resizer"),2,elems))
475 {
476 cleanupVaapi();
477 bool status=setupVaapi();
478 if(unsupported)
479 {
480
481 GUI_Info_HIG( ADM_LOG_IMPORTANT,
482 QT_TRANSLATE_NOOP("vaapiDeint","Unsupported Mode"),
483 QT_TRANSLATE_NOOP("vaapiDeint","Specified deinterlacing mode %s is not supported, replaced with %s."),
484 deintModeToString(unsupported), deintModeToString(configuration.deintMode));
485 unsupported = 0;
486 }
487 if(!status)
488 {
489 GUI_Error_HIG(QT_TRANSLATE_NOOP("vaapiDeint","VA-API Setup Error"),
490 QT_TRANSLATE_NOOP("vaapiDeint","Could not setup VA-API, purely passthrough operation."));
491 }
492 updateInfo(status);
493 return true;
494 }
495 return false;
496 }
497 /**
498 \fn getCoupledConf
499 \brief Return our current configuration as couple name=value
500 */
getCoupledConf(CONFcouple ** couples)501 bool vaapiVideoFilterDeint::getCoupledConf(CONFcouple **couples)
502 {
503 return ADM_paramSave(couples, vaapiFilterDeint_param, &configuration);
504 }
505
setCoupledConf(CONFcouple * couples)506 void vaapiVideoFilterDeint::setCoupledConf(CONFcouple *couples)
507 {
508 ADM_paramLoad(couples, vaapiFilterDeint_param, &configuration);
509 }
510
511 /**
512 \fn getConfiguration
513 \brief Return current setting as a string
514 */
getConfiguration(void)515 const char *vaapiVideoFilterDeint::getConfiguration(void)
516 {
517 static char conf[256];
518 sprintf(conf,"VA-API deint. mode: %s, parity: %s, double fps: %s",
519 deintModeToString(configuration.deintMode),
520 (configuration.fieldOrder==ADM_VAAPI_DEINT_TOP_FIELD_FIRST)? "top field first" : "bottom field first",
521 (configuration.framePerField==ADM_VAAPI_DEINT_SEND_FIELD)? "yes" : "no");
522 if(configuration.resize)
523 {
524 char part2[80]={0};
525 sprintf(part2,", resize from %dx%d to %dx%d",
526 previousFilter->getInfo()->width, previousFilter->getInfo()->height,
527 configuration.targetWidth, configuration.targetHeight);
528 strcat(conf,part2);
529 }
530 conf[255]=0;
531 return conf;
532 }
533
534 /**
535 \fn goToTime
536 \brief called when seeking. Need to cleanup our stuff.
537 */
goToTime(uint64_t usSeek)538 bool vaapiVideoFilterDeint::goToTime(uint64_t usSeek)
539 {
540 secondField=false;
541 preloadCompleted=false;
542 clearSlots();
543 uint32_t oldFrameIncrement=info.frameIncrement;
544 if(!passThrough && configuration.framePerField==ADM_VAAPI_DEINT_SEND_FIELD)
545 info.frameIncrement*=2;
546 bool r=ADM_coreVideoFilterCached::goToTime(usSeek);
547 info.frameIncrement=oldFrameIncrement;
548 return r;
549 }
550
551 /**
552 \fn fillSlot
553 \brief upload the image to the slot.
554 */
fillSlot(uint32_t slot,ADMImage * image)555 bool vaapiVideoFilterDeint::fillSlot(uint32_t slot,ADMImage *image)
556 {
557 ADM_assert(slot<queueLength);
558 ADM_vaSurface *target;
559 bool external=false;
560 if(image->refType!=ADM_HW_LIBVA)
561 {
562 // provide a surface from our pool
563 ADM_assert(freeSurfaces.size());
564 target=freeSurfaces.front();
565 freeSurfaces.pop_front();
566 if(!target->fromAdmImage(image))
567 return false;
568 }else
569 {
570 // use the provided surface
571 target=(ADM_vaSurface *)image->refDescriptor.refHwImage;
572 //printf("Source image is already VAAPI, surface %d, slot %d, pts %s\n",(uint32_t)target->surface,slot,ADM_us2plain(image->Pts));
573 ADM_assert(target->refCount);
574 image->hwIncRefCount();
575 external=true;
576 }
577 inputQueue[slot].pts=image->Pts;
578 inputQueue[slot].surface=target;
579 inputQueue[slot].external=external;
580 return true;
581 }
582
583 /**
584 \fn rotateSlots
585 */
rotateSlots(void)586 bool vaapiVideoFilterDeint::rotateSlots(void)
587 {
588 ADM_assert(queueLength);
589 vaapiSlot *s = &inputQueue[0];
590 if(s->surface)
591 {
592 if(!s->external)
593 freeSurfaces.push_back(s->surface);
594 else if(s->surface->refCount>0)
595 s->surface->refCount--;
596 }
597 for(int i=0; i < (int)queueLength-1; i++)
598 inputQueue[i] = inputQueue[i+1];
599 s = &inputQueue[queueLength-1];
600 s->reset();
601 return true;
602 }
603
604 /**
605 \fn clearSlots
606 */
clearSlots(void)607 bool vaapiVideoFilterDeint::clearSlots(void)
608 {
609 for(int i=0; i < (int)queueLength; i++)
610 {
611 vaapiSlot *s = &inputQueue[i];
612 if(s->surface)
613 {
614 if(!s->external)
615 freeSurfaces.push_back(s->surface);
616 else if(s->surface->refCount>0)
617 s->surface->refCount--;
618 }
619 s->reset();
620 }
621 return true;
622 }
623
624 /**
625 \fn getNextFrame
626 */
getNextFrame(uint32_t * fn,ADMImage * image)627 bool vaapiVideoFilterDeint::getNextFrame(uint32_t *fn,ADMImage *image)
628 {
629 bool r=false;
630 uint32_t i;
631 if(passThrough)
632 {
633 //ADM_info("VA-API deinterlacer: passthrough\n");
634 return previousFilter->getNextFrame(fn,image);
635 }
636 if(!secondField)
637 {
638 // shift frames;... free slot[0]
639 rotateSlots();
640
641 if(!preloadCompleted)
642 {
643 for(i=0; i < queueLength; i++)
644 {
645 ADMImage *ref = vidCache->getImageAs(ADM_HW_LIBVA,i);
646 if(!ref || false==fillSlot(i,ref))
647 {
648 vidCache->unlockAll();
649 ADM_error("Cannot fill the queue, need %u pictures, got %u, aborting.\n",queueLength,i);
650 return false;
651 }
652 }
653 preloadCompleted=true;
654 nextFrame+=nbForwardRefs;
655 //ADM_info("Preloaded %u pictures, nextFrame = %u\n",queueLength,nextFrame);
656 }else
657 {
658 //printf("[vaapiVideoFilterDeint::getNextFrame] requesting frame %u from cache.\n",nextFrame);
659 ADMImage *next = vidCache->getImageAs(ADM_HW_LIBVA,nextFrame);
660 if(!next)
661 {
662 vidCache->unlockAll();
663 return false;
664 }
665 if(false==fillSlot(queueLength-1,next))
666 {
667 vidCache->unlockAll();
668 return false;
669 }
670 }
671 }
672 vaapiSlot *src = &inputQueue[nbForwardRefs];
673 ADM_assert(src);
674 vaapiSlot *prev = NULL;
675 if(nbForwardRefs)
676 prev = &inputQueue[nbForwardRefs-1];
677 if(prev && prev->pts!=ADM_NO_PTS && src->pts!=ADM_NO_PTS && src->pts > prev->pts)
678 deltaPts = src->pts - prev->pts;
679 image->Pts = src->pts;
680 if(secondField && image->Pts != ADM_NO_PTS)
681 {
682 if(deltaPts < info.frameIncrement*2)
683 image->Pts += deltaPts/2;
684 else
685 image->Pts += info.frameIncrement;
686 }
687
688 for(i=0; i < nbForwardRefs; i++)
689 {
690 forwardRefs[i] = inputQueue[nbForwardRefs-i-1].surface->surface;
691 //printf("forward ref %d is VASurfaceID %u\n",i,(uint32_t)forwardReferences[i]);
692 }
693 for(i=0; i < nbBackwardRefs; i++)
694 {
695 backwardRefs[i] = inputQueue[nbForwardRefs+i+1].surface->surface;
696 //printf("backward ref %d is VASurfaceID %u\n",i,(uint32_t)backwardReferences[i]);
697 }
698
699 //-- Perform --
700 VAProcPipelineParameterBuffer param;
701 VABufferID paramId;
702 VAStatus status;
703
704 memset(¶m,0,sizeof(param));
705
706 param.surface = src->surface->surface;
707 param.surface_region = NULL;
708 param.surface_color_standard = VAProcColorStandardBT709 ; // FIXME
709 param.output_region = NULL;
710 param.output_background_color = 0xff000000;
711 param.output_color_standard = VAProcColorStandardBT709; // FIXME
712
713 param.filter_flags = VA_FRAME_PICTURE;
714 param.filter_flags |= VA_FILTER_SCALING_HQ;
715 param.pipeline_flags = 0;
716 param.filters = &filterBuffer;
717 param.num_filters = 1;
718
719 param.forward_references = forwardRefs;
720 param.num_forward_references = nbForwardRefs;
721 param.backward_references = backwardRefs;
722 param.num_backward_references = nbBackwardRefs;
723
724 VAProcFilterParameterBufferDeinterlacing *deintParams;
725 void *deintParamsPtr;
726
727 #define CHECK(x) { status=x; if(status!=VA_STATUS_SUCCESS) { ADM_warning( #x " failed with error %d: %s\n",status,vaErrorStr(status)); goto failed; }}
728 CHECK(vaMapBuffer(admLibVA::getDisplay(), filterBuffer, &deintParamsPtr))
729
730 deintParams = (VAProcFilterParameterBufferDeinterlacing *)deintParamsPtr;
731 deintParams->flags = 0;
732 if(configuration.fieldOrder == ADM_VAAPI_DEINT_BOTTOM_FIELD_FIRST)
733 deintParams->flags |= VA_DEINTERLACING_BOTTOM_FIELD_FIRST;
734 if(secondField == (configuration.fieldOrder == ADM_VAAPI_DEINT_TOP_FIELD_FIRST))
735 deintParams->flags |= VA_DEINTERLACING_BOTTOM_FIELD;
736 deintParamsPtr=NULL;
737
738 CHECK(vaUnmapBuffer(admLibVA::getDisplay(), filterBuffer))
739
740 CHECK(vaBeginPicture(admLibVA::getDisplay(), contextId, outputSurface->surface))
741 CHECK(vaCreateBuffer(admLibVA::getDisplay(), contextId,
742 VAProcPipelineParameterBufferType,
743 sizeof(param), 1,
744 ¶m, ¶mId))
745 // Go
746 CHECK(vaRenderPicture(admLibVA::getDisplay(), contextId, ¶mId, 1))
747 CHECK(vaEndPicture(admLibVA::getDisplay(), contextId))
748
749 // Download result to regular ADMImage
750 r = outputSurface->toAdmImage(image);
751 //printf("Result is %d\n",r);
752 failed:
753 if(paramId!=VA_INVALID)
754 vaDestroyBuffer(admLibVA::getDisplay(), paramId);
755 if(configuration.framePerField==ADM_VAAPI_DEINT_SEND_FIELD)
756 {
757 *fn=(nextFrame-nbForwardRefs)*2+secondField;
758 secondField=!secondField;
759 //printf("%s, frame number: %u, pts: %s\n",secondField? "First field" : "Second field",*fn,ADM_us2plain(image->Pts));
760 }else
761 *fn=nextFrame-nbForwardRefs;
762 if(!secondField) nextFrame++;
763 vidCache->unlockAll();
764 return r;
765 }
766 // EOF
767