xbmc
VAAPI.h
1 /*
2  * Copyright (C) 2005-2018 Team Kodi
3  * This file is part of Kodi - https://kodi.tv
4  *
5  * SPDX-License-Identifier: LGPL-2.1-or-later
6  * See LICENSES/README.md for more information.
7  */
8 
9 #pragma once
10 
11 #include "DVDVideoCodec.h"
12 #include "cores/VideoPlayer/Buffers/VideoBuffer.h"
13 #include "cores/VideoSettings.h"
14 #include "threads/CriticalSection.h"
15 #include "threads/Event.h"
16 #include "threads/SharedSection.h"
17 #include "threads/Thread.h"
18 #include "utils/ActorProtocol.h"
19 #include "utils/Geometry.h"
20 
21 #include "platform/linux/sse4/DllLibSSE4.h"
22 
23 #include <list>
24 #include <map>
25 #include <memory>
26 #include <mutex>
27 #include <utility>
28 #include <vector>
29 
30 #include <va/va.h>
31 
32 extern "C" {
33 #include <libavutil/avutil.h>
34 #include <libavfilter/avfilter.h>
35 }
36 
37 using namespace Actor;
38 
39 class CProcessInfo;
40 
41 #define FULLHD_WIDTH 1920
42 
43 namespace VAAPI
44 {
45 
46 void VaErrorCallback(void *user_context, const char *message);
47 void VaInfoCallback(void *user_context, const char *message);
48 
49 //-----------------------------------------------------------------------------
50 // VAAPI data structs
51 //-----------------------------------------------------------------------------
52 
53 class CDecoder;
54 
60 {
61 public:
62  uint16_t decodedPics;
63  uint16_t processedPics;
64  uint16_t renderPics;
65  uint64_t latency; // time decoder has waited for a frame, ideally there is no latency
66  int codecFlags;
67  bool canSkipDeint;
68  int processCmd;
69  bool isVpp;
70 
71  void IncDecoded()
72  {
73  std::unique_lock<CCriticalSection> l(m_sec);
74  decodedPics++;
75  }
76  void DecDecoded()
77  {
78  std::unique_lock<CCriticalSection> l(m_sec);
79  decodedPics--;
80  }
81  void IncProcessed()
82  {
83  std::unique_lock<CCriticalSection> l(m_sec);
84  processedPics++;
85  }
86  void DecProcessed()
87  {
88  std::unique_lock<CCriticalSection> l(m_sec);
89  processedPics--;
90  }
91  void IncRender()
92  {
93  std::unique_lock<CCriticalSection> l(m_sec);
94  renderPics++;
95  }
96  void DecRender()
97  {
98  std::unique_lock<CCriticalSection> l(m_sec);
99  renderPics--;
100  }
101  void Reset()
102  {
103  std::unique_lock<CCriticalSection> l(m_sec);
104  decodedPics = 0;
105  processedPics = 0;
106  renderPics = 0;
107  latency = 0;
108  isVpp = false;
109  }
110  void Get(uint16_t& decoded, uint16_t& processed, uint16_t& render, bool& vpp)
111  {
112  std::unique_lock<CCriticalSection> l(m_sec);
113  decoded = decodedPics, processed = processedPics, render = renderPics;
114  vpp = isVpp;
115  }
116  void SetParams(uint64_t time, int flags)
117  {
118  std::unique_lock<CCriticalSection> l(m_sec);
119  latency = time;
120  codecFlags = flags;
121  }
122  void GetParams(uint64_t& lat, int& flags)
123  {
124  std::unique_lock<CCriticalSection> l(m_sec);
125  lat = latency;
126  flags = codecFlags;
127  }
128  void SetCmd(int cmd)
129  {
130  std::unique_lock<CCriticalSection> l(m_sec);
131  processCmd = cmd;
132  }
133  void GetCmd(int& cmd)
134  {
135  std::unique_lock<CCriticalSection> l(m_sec);
136  cmd = processCmd;
137  processCmd = 0;
138  }
139  void SetCanSkipDeint(bool canSkip)
140  {
141  std::unique_lock<CCriticalSection> l(m_sec);
142  canSkipDeint = canSkip;
143  }
144  bool CanSkipDeint()
145  {
146  std::unique_lock<CCriticalSection> l(m_sec);
147  if (canSkipDeint)
148  return true;
149  else
150  return false;
151  }
152  void SetVpp(bool vpp)
153  {
154  std::unique_lock<CCriticalSection> l(m_sec);
155  isVpp = vpp;
156  }
157 
158 private:
159  CCriticalSection m_sec;
160 };
161 
168 class CVideoSurfaces;
169 class CVAAPIContext;
170 
172 {
173  int surfaceWidth;
174  int surfaceHeight;
175  int vidWidth;
176  int vidHeight;
177  int outWidth;
178  int outHeight;
179  AVRational aspect;
180  VAConfigID configId;
181  CVaapiBufferStats *stats;
182  int upscale;
183  CVideoSurfaces *videoSurfaces;
184  uint32_t maxReferences;
185  CVAAPIContext *context;
186  VADisplay dpy;
187  VAProfile profile;
188  VAConfigAttrib attrib;
189  CProcessInfo *processInfo;
190  bool driverIsMesa;
191  int bitDepth;
192 };
193 
199 {
200  CVaapiDecodedPicture() = default;
202  {
203  *this = rhs;
204  }
205  CVaapiDecodedPicture& operator=(const CVaapiDecodedPicture& rhs)
206  {
207  DVDPic.SetParams(rhs.DVDPic);
208  videoSurface = rhs.videoSurface;
209  index = rhs.index;
210  return *this;
211  };
212  VideoPicture DVDPic;
213  VASurfaceID videoSurface;
214  int index;
215 };
216 
220 class CPostproc;
222 {
223  CVaapiProcessedPicture() = default;
225  {
226  *this = rhs;
227  }
228  CVaapiProcessedPicture& operator=(const CVaapiProcessedPicture& rhs)
229  {
230  DVDPic.SetParams(rhs.DVDPic);
231  videoSurface = rhs.videoSurface;
232  frame = rhs.frame;
233  id = rhs.id;
234  source = rhs.source;
235  crop = rhs.crop;
236  return *this;
237  };
238 
239  VideoPicture DVDPic;
240  VASurfaceID videoSurface;
241  AVFrame *frame;
242  int id;
243  CPostproc *source = nullptr;
244  bool crop = false;
245 };
246 
248 {
249 public:
250  explicit CVaapiRenderPicture(int id) : CVideoBuffer(id) { }
251  void GetPlanes(uint8_t*(&planes)[YuvImage::MAX_PLANES]) override;
252  void GetStrides(int(&strides)[YuvImage::MAX_PLANES]) override;
253  VideoPicture DVDPic;
254  CVaapiProcessedPicture procPic;
255  AVFrame *avFrame = nullptr;
256 
257  bool valid = false;
258  VADisplay vadsp;
259 };
260 
261 //-----------------------------------------------------------------------------
262 // Output
263 //-----------------------------------------------------------------------------
264 
266 {
267 public:
268  COutputControlProtocol(std::string name, CEvent* inEvent, CEvent* outEvent)
269  : Protocol(std::move(name), inEvent, outEvent)
270  {
271  }
272  enum OutSignal
273  {
274  INIT,
275  FLUSH,
276  PRECLEANUP,
277  TIMEOUT,
278  };
279  enum InSignal
280  {
281  ACC,
282  ERROR,
283  STATS,
284  };
285 };
286 
288 {
289 public:
290  COutputDataProtocol(std::string name, CEvent* inEvent, CEvent* outEvent)
291  : Protocol(std::move(name), inEvent, outEvent)
292  {
293  }
294  enum OutSignal
295  {
296  NEWFRAME = 0,
297  RETURNPIC,
298  RETURNPROCPIC,
299  };
300  enum InSignal
301  {
302  PICTURE,
303  };
304 };
305 
307 {
308  EINTERLACEMETHOD diMethods[8];
309  int numDiMethods;
310 };
311 
319 class CDecoder;
320 class CPostproc;
321 class CVaapiBufferPool;
322 
323 class COutput : private CThread
324 {
325 public:
326  COutput(CDecoder &decoder, CEvent *inMsgEvent);
327  ~COutput() override;
328  void Start();
329  void Dispose();
330  COutputControlProtocol m_controlPort;
331  COutputDataProtocol m_dataPort;
332 protected:
333  void OnStartup() override;
334  void OnExit() override;
335  void Process() override;
336  void StateMachine(int signal, Protocol *port, Message *msg);
337  bool HasWork();
338  bool PreferPP();
339  void InitCycle();
340  CVaapiRenderPicture* ProcessPicture(CVaapiProcessedPicture &pic);
341  void QueueReturnPicture(CVaapiRenderPicture *pic);
342  void ProcessReturnPicture(CVaapiRenderPicture *pic);
343  void ProcessReturnProcPicture(int id);
344  void ProcessSyncPicture();
345  void ReleaseProcessedPicture(CVaapiProcessedPicture &pic);
346  bool Init();
347  bool Uninit();
348  void Flush();
349  void EnsureBufferPool();
350  void ReleaseBufferPool(bool precleanup = false);
351  void ReadyForDisposal(CPostproc *pp);
352  CEvent m_outMsgEvent;
353  CEvent *m_inMsgEvent;
354  int m_state;
355  bool m_bStateMachineSelfTrigger;
356  CDecoder &m_vaapi;
357 
358  // extended state variables for state machine
359  std::chrono::milliseconds m_extTimeout = std::chrono::milliseconds::zero();
362  CVaapiConfig m_config;
363  std::shared_ptr<CVaapiBufferPool> m_bufferPool;
364  CVaapiDecodedPicture m_currentPicture;
365  CPostproc *m_pp;
366  std::list<std::shared_ptr<CPostproc>> m_discardedPostprocs;
367  SDiMethods m_diMethods;
368 };
369 
370 //-----------------------------------------------------------------------------
371 // VAAPI Video Surface states
372 //-----------------------------------------------------------------------------
373 
375 {
376 public:
377  void AddSurface(VASurfaceID surf);
378  void ClearReference(VASurfaceID surf);
379  bool MarkRender(VASurfaceID surf);
380  void ClearRender(VASurfaceID surf);
381  bool IsValid(VASurfaceID surf);
382  VASurfaceID GetFree(VASurfaceID surf);
383  VASurfaceID GetAtIndex(int idx);
384  VASurfaceID RemoveNext(bool skiprender = false);
385  void Reset();
386  int Size();
387  bool HasFree();
388  bool HasRefs();
389  int NumFree();
390 protected:
391  std::map<VASurfaceID, int> m_state;
392  std::list<VASurfaceID> m_freeSurfaces;
393  CCriticalSection m_section;
394 };
395 
396 //-----------------------------------------------------------------------------
397 // VAAPI decoder
398 //-----------------------------------------------------------------------------
399 
401 {
402 public:
403  static bool EnsureContext(CVAAPIContext **ctx, CDecoder *decoder);
404  void Release(CDecoder *decoder);
405  VADisplay GetDisplay();
406  bool SupportsProfile(VAProfile profile);
407  VAConfigAttrib GetAttrib(VAProfile profile);
408  VAConfigID CreateConfig(VAProfile profile, VAConfigAttrib attrib);
409  static void FFReleaseBuffer(void *opaque, uint8_t *data);
410 private:
411  CVAAPIContext();
412  void Close();
413  void SetVaDisplayForSystem();
414  bool CreateContext();
415  void DestroyContext();
416  void QueryCaps();
417  bool CheckSuccess(VAStatus status, const std::string& function);
418  bool IsValidDecoder(CDecoder *decoder);
419  void SetValidDRMVaDisplayFromRenderNode();
420  static CVAAPIContext *m_context;
421  static CCriticalSection m_section;
422  VADisplay m_display = NULL;
423  int m_refCount;
424  int m_profileCount;
425  VAProfile *m_profiles;
426  std::vector<CDecoder*> m_decoders;
427  int m_renderNodeFD{-1};
428 };
429 
430 //-----------------------------------------------------------------------------
431 // Interface into windowing
432 //-----------------------------------------------------------------------------
433 
435 {
436 public:
437  virtual ~IVaapiWinSystem() = default;
438 
439  virtual VADisplay GetVADisplay() = 0;
440  virtual void* GetEGLDisplay() { return nullptr; }
441 };
442 
443 //-----------------------------------------------------------------------------
444 // VAAPI main class
445 //-----------------------------------------------------------------------------
446 
447 class CDecoder
448  : public IHardwareDecoder
449 {
450  friend class CVaapiBufferPool;
451 
452 public:
453 
454  explicit CDecoder(CProcessInfo& processInfo);
455  ~CDecoder() override;
456 
457  bool Open (AVCodecContext* avctx, AVCodecContext* mainctx, const enum AVPixelFormat) override;
458  CDVDVideoCodec::VCReturn Decode (AVCodecContext* avctx, AVFrame* frame) override;
459  bool GetPicture(AVCodecContext* avctx, VideoPicture* picture) override;
460  void Reset() override;
461  virtual void Close();
462  long Release() override;
463  bool CanSkipDeint() override;
464  unsigned GetAllowedReferences() override { return 4; }
465 
466  CDVDVideoCodec::VCReturn Check(AVCodecContext* avctx) override;
467  const std::string Name() override { return "vaapi"; }
468  void SetCodecControl(int flags) override;
469 
470  void FFReleaseBuffer(uint8_t *data);
471  static int FFGetBuffer(AVCodecContext *avctx, AVFrame *pic, int flags);
472 
473  static IHardwareDecoder* Create(CDVDStreamInfo &hint, CProcessInfo &processInfo, AVPixelFormat fmt);
474  static void Register(IVaapiWinSystem *winSystem, bool deepColor);
475 
476  static IVaapiWinSystem* m_pWinSystem;
477 
478 protected:
479  void SetWidthHeight(int width, int height);
480  bool ConfigVAAPI();
481  bool CheckStatus(VAStatus vdp_st, int line);
482  void FiniVAAPIOutput();
483  void ReturnRenderPicture(CVaapiRenderPicture *renderPic);
484  long ReleasePicReference();
485  bool CheckSuccess(VAStatus status, const std::string& function);
486 
487  enum EDisplayState
488  { VAAPI_OPEN
489  , VAAPI_RESET
490  , VAAPI_LOST
491  , VAAPI_ERROR
492  } m_DisplayState;
493  CCriticalSection m_DecoderSection;
494  CEvent m_DisplayEvent;
495  int m_ErrorCount;
496 
497  bool m_vaapiConfigured;
498  CVaapiConfig m_vaapiConfig;
499  CVideoSurfaces m_videoSurfaces;
500  AVCodecContext* m_avctx;
501  int m_getBufferError;
502 
503  COutput m_vaapiOutput;
504  CVaapiBufferStats m_bufferStats;
505  CEvent m_inMsgEvent;
506  CVaapiRenderPicture *m_presentPicture = nullptr;
507 
508  int m_codecControl;
509  CProcessInfo& m_processInfo;
510 
511  static bool m_capGeneral;
512  static bool m_capDeepColor;
513 
514 private:
515  struct AVBufferRefDeleter
516  {
517  void operator()(AVBufferRef* p) const;
518  };
519 
520  std::unique_ptr<AVBufferRef, AVBufferRefDeleter> m_deviceRef;
521 };
522 
523 //-----------------------------------------------------------------------------
524 // Postprocessing
525 //-----------------------------------------------------------------------------
526 
530 typedef void (COutput::*ReadyToDispose)(CPostproc *pool);
532 {
533 public:
534  virtual ~CPostproc() = default;
535  virtual bool PreInit(CVaapiConfig &config, SDiMethods *methods = NULL) = 0;
536  virtual bool Init(EINTERLACEMETHOD method) = 0;
537  virtual bool AddPicture(CVaapiDecodedPicture &inPic) = 0;
538  virtual bool Filter(CVaapiProcessedPicture &outPic) = 0;
539  virtual void ClearRef(CVaapiProcessedPicture &pic) = 0;
540  virtual void Flush() = 0;
541  virtual bool UpdateDeintMethod(EINTERLACEMETHOD method) = 0;
542  virtual bool DoesSync() = 0;
543  virtual bool WantsPic() {return true;}
544  virtual bool UseVideoSurface() = 0;
545  virtual void Discard(COutput* output, ReadyToDispose cb) { (output->*cb)(this); }
546 
547 protected:
548  CVaapiConfig m_config;
549  int m_step;
550 };
551 
555 class CSkipPostproc : public CPostproc
556 {
557 public:
558  bool PreInit(CVaapiConfig &config, SDiMethods *methods = NULL) override;
559  bool Init(EINTERLACEMETHOD method) override;
560  bool AddPicture(CVaapiDecodedPicture &inPic) override;
561  bool Filter(CVaapiProcessedPicture &outPic) override;
562  void ClearRef(CVaapiProcessedPicture &pic) override;
563  void Flush() override;
564  bool UpdateDeintMethod(EINTERLACEMETHOD method) override;
565  bool DoesSync() override;
566  bool UseVideoSurface() override;
567  void Discard(COutput *output, ReadyToDispose cb) override;
568 protected:
569  CVaapiDecodedPicture m_pic;
570  ReadyToDispose m_cbDispose = nullptr;
571  COutput *m_pOut;
572  int m_refsToSurfaces = 0;
573 };
574 
578 class CVppPostproc : public CPostproc
579 {
580 public:
581  CVppPostproc();
582  ~CVppPostproc() override;
583  bool PreInit(CVaapiConfig &config, SDiMethods *methods = NULL) override;
584  bool Init(EINTERLACEMETHOD method) override;
585  bool AddPicture(CVaapiDecodedPicture &inPic) override;
586  bool Filter(CVaapiProcessedPicture &outPic) override;
587  void ClearRef(CVaapiProcessedPicture &pic) override;
588  void Flush() override;
589  bool UpdateDeintMethod(EINTERLACEMETHOD method) override;
590  bool DoesSync() override;
591  bool WantsPic() override;
592  bool UseVideoSurface() override;
593  void Discard(COutput *output, ReadyToDispose cb) override;
594 protected:
595  bool CheckSuccess(VAStatus status, const std::string& function);
596  void Dispose();
597  void Advance();
598  VAConfigID m_configId = VA_INVALID_ID;
599  VAContextID m_contextId = VA_INVALID_ID;
600  CVideoSurfaces m_videoSurfaces;
601  std::deque<CVaapiDecodedPicture> m_decodedPics;
602  VABufferID m_filter = VA_INVALID_ID;
603  int m_forwardRefs, m_backwardRefs;
604  int m_currentIdx;
605  int m_frameCount;
606  EINTERLACEMETHOD m_vppMethod;
607  ReadyToDispose m_cbDispose = nullptr;
608  COutput *m_pOut = nullptr;
609 };
610 
615 {
616 public:
617  CFFmpegPostproc();
618  ~CFFmpegPostproc() override;
619  bool PreInit(CVaapiConfig &config, SDiMethods *methods = NULL) override;
620  bool Init(EINTERLACEMETHOD method) override;
621  bool AddPicture(CVaapiDecodedPicture &inPic) override;
622  bool Filter(CVaapiProcessedPicture &outPic) override;
623  void ClearRef(CVaapiProcessedPicture &pic) override;
624  void Flush() override;
625  bool UpdateDeintMethod(EINTERLACEMETHOD method) override;
626  bool DoesSync() override;
627  bool UseVideoSurface() override;
628  void Discard(COutput *output, ReadyToDispose cb) override;
629 protected:
630  bool CheckSuccess(VAStatus status, const std::string& function);
631  void Close();
632  DllLibSSE4 m_dllSSE4;
633  uint8_t *m_cache;
634  AVFilterGraph* m_pFilterGraph;
635  AVFilterContext* m_pFilterIn;
636  AVFilterContext* m_pFilterOut;
637  AVFrame *m_pFilterFrameIn;
638  AVFrame *m_pFilterFrameOut;
639  EINTERLACEMETHOD m_diMethod;
640  VideoPicture m_DVDPic;
641  double m_frametime;
642  double m_lastOutPts;
643  ReadyToDispose m_cbDispose = nullptr;
644  COutput *m_pOut;
645  int m_refsToPics = 0;
646 };
647 
648 }
This is an Event class built from a ConditionVariable.
Definition: Event.h:35
Definition: VAAPI.h:400
Definition: DVDStreamInfo.h:23
Definition: VideoBuffer.h:85
Definition: deflate.c:123
Definition: VAAPI.h:447
Definition: VAAPI.h:323
Definition: Thread.h:44
Definition: VAAPI.h:306
Definition: VAAPI.h:221
Definition: ActorProtocol.h:73
Definition: DVDVideoCodec.h:245
skip post processing
Definition: VAAPI.h:555
ffmpeg filter
Definition: VAAPI.h:614
Definition: ActorProtocol.h:21
Definition: ActorProtocol.h:45
Buffer pool holds allocated vaapi and gl resources Embedded in COutput.
Definition: VAAPI.cpp:1318
VAAPI post processing.
Definition: VAAPI.h:578
Holds a decoded frame Input to COutput for further processing.
Definition: VAAPI.h:198
Definition: ProcessInfo.h:26
Definition: VAAPI.h:374
Definition: VAAPI.h:434
Definition: VAAPI.h:171
Definition: VAAPI.h:265
Definition: VAAPI.h:531
Definition: DllLibSSE4.h:24
Definition: DVDVideoCodec.h:36
Buffer statistics used to control number of frames in queue.
Definition: VAAPI.h:59
Definition: VAAPI.h:43
Definition: VAAPI.h:247
Definition: VAAPI.h:287
bool m_seenInterlaced
Whether at least one interlaced frame was encountered in the video stream (indicating that more inter...
Definition: VAAPI.h:361