xbmc
VDPAU.h
1 /*
2  * Copyright (C) 2005-2018 Team Kodi
3  * This file is part of Kodi - https://kodi.tv
4  *
5  * SPDX-License-Identifier: GPL-2.0-or-later
6  * See LICENSES/README.md for more information.
7  */
8 
9 #pragma once
10 
29 #include "cores/VideoPlayer/Buffers/VideoBuffer.h"
30 #include "cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h"
31 #include "cores/VideoSettings.h"
32 #include "guilib/DispResource.h"
33 #include "threads/CriticalSection.h"
34 #include "threads/Event.h"
35 #include "threads/SharedSection.h"
36 #include "threads/Thread.h"
37 #include "utils/ActorProtocol.h"
38 #include "utils/Geometry.h"
39 
40 #include <deque>
41 #include <list>
42 #include <map>
43 #include <mutex>
44 #include <utility>
45 #include <vector>
46 
47 #include <X11/Xlib.h>
48 #include <X11/Xutil.h>
49 
50 extern "C" {
51 #include <libavutil/avutil.h>
52 #include <libavcodec/vdpau.h>
53 }
54 
55 class CProcessInfo;
56 
57 namespace VDPAU
58 {
59 
65 {
66  VdpGetProcAddress*vdp_get_proc_address;
67  VdpDeviceDestroy* vdp_device_destroy;
68 
69  VdpVideoSurfaceCreate* vdp_video_surface_create;
70  VdpVideoSurfaceDestroy* vdp_video_surface_destroy;
71  VdpVideoSurfacePutBitsYCbCr* vdp_video_surface_put_bits_y_cb_cr;
72  VdpVideoSurfaceGetBitsYCbCr* vdp_video_surface_get_bits_y_cb_cr;
73 
74  VdpOutputSurfacePutBitsYCbCr* vdp_output_surface_put_bits_y_cb_cr;
75  VdpOutputSurfacePutBitsNative* vdp_output_surface_put_bits_native;
76  VdpOutputSurfaceCreate* vdp_output_surface_create;
77  VdpOutputSurfaceDestroy* vdp_output_surface_destroy;
78  VdpOutputSurfaceGetBitsNative* vdp_output_surface_get_bits_native;
79  VdpOutputSurfaceRenderOutputSurface* vdp_output_surface_render_output_surface;
80  VdpOutputSurfacePutBitsIndexed* vdp_output_surface_put_bits_indexed;
81 
82  VdpVideoMixerCreate* vdp_video_mixer_create;
83  VdpVideoMixerSetFeatureEnables* vdp_video_mixer_set_feature_enables;
84  VdpVideoMixerQueryParameterSupport* vdp_video_mixer_query_parameter_support;
85  VdpVideoMixerQueryFeatureSupport* vdp_video_mixer_query_feature_support;
86  VdpVideoMixerDestroy* vdp_video_mixer_destroy;
87  VdpVideoMixerRender* vdp_video_mixer_render;
88  VdpVideoMixerSetAttributeValues* vdp_video_mixer_set_attribute_values;
89 
90  VdpGenerateCSCMatrix* vdp_generate_csc_matrix;
91 
92  VdpGetErrorString* vdp_get_error_string;
93 
94  VdpDecoderCreate* vdp_decoder_create;
95  VdpDecoderDestroy* vdp_decoder_destroy;
96  VdpDecoderRender* vdp_decoder_render;
97  VdpDecoderQueryCapabilities* vdp_decoder_query_caps;
98 
99  VdpPreemptionCallbackRegister* vdp_preemption_callback_register;
100 };
101 
102 //-----------------------------------------------------------------------------
103 // VDPAU data structs
104 //-----------------------------------------------------------------------------
105 
106 class CDecoder;
107 
113 {
114 public:
115  uint16_t decodedPics;
116  uint16_t processedPics;
117  uint16_t renderPics;
118  uint64_t latency; // time decoder has waited for a frame, ideally there is no latency
119  int codecFlags;
120  bool canSkipDeint;
121  bool draining;
122 
123  void IncDecoded()
124  {
125  std::unique_lock<CCriticalSection> l(m_sec);
126  decodedPics++;
127  }
128  void DecDecoded()
129  {
130  std::unique_lock<CCriticalSection> l(m_sec);
131  decodedPics--;
132  }
133  void IncProcessed()
134  {
135  std::unique_lock<CCriticalSection> l(m_sec);
136  processedPics++;
137  }
138  void DecProcessed()
139  {
140  std::unique_lock<CCriticalSection> l(m_sec);
141  processedPics--;
142  }
143  void IncRender()
144  {
145  std::unique_lock<CCriticalSection> l(m_sec);
146  renderPics++;
147  }
148  void DecRender()
149  {
150  std::unique_lock<CCriticalSection> l(m_sec);
151  renderPics--;
152  }
153  void Reset()
154  {
155  std::unique_lock<CCriticalSection> l(m_sec);
156  decodedPics = 0;
157  processedPics = 0;
158  renderPics = 0;
159  latency = 0;
160  }
161  void Get(uint16_t& decoded, uint16_t& processed, uint16_t& render)
162  {
163  std::unique_lock<CCriticalSection> l(m_sec);
164  decoded = decodedPics, processed = processedPics, render = renderPics;
165  }
166  void SetParams(uint64_t time, int flags)
167  {
168  std::unique_lock<CCriticalSection> l(m_sec);
169  latency = time;
170  codecFlags = flags;
171  }
172  void GetParams(uint64_t& lat, int& flags)
173  {
174  std::unique_lock<CCriticalSection> l(m_sec);
175  lat = latency;
176  flags = codecFlags;
177  }
178  void SetCanSkipDeint(bool canSkip)
179  {
180  std::unique_lock<CCriticalSection> l(m_sec);
181  canSkipDeint = canSkip;
182  }
183  bool CanSkipDeint()
184  {
185  std::unique_lock<CCriticalSection> l(m_sec);
186  if (canSkipDeint)
187  return true;
188  else
189  return false;
190  }
191  void SetDraining(bool drain)
192  {
193  std::unique_lock<CCriticalSection> l(m_sec);
194  draining = drain;
195  }
196  bool IsDraining()
197  {
198  std::unique_lock<CCriticalSection> l(m_sec);
199  if (draining)
200  return true;
201  else
202  return false;
203  }
204 
205 private:
206  CCriticalSection m_sec;
207 };
208 
215 class CVideoSurfaces;
216 class CVDPAUContext;
217 
219 {
220  int surfaceWidth;
221  int surfaceHeight;
222  int vidWidth;
223  int vidHeight;
224  int outWidth;
225  int outHeight;
226  VdpDecoder vdpDecoder;
227  VdpChromaType vdpChromaType;
228  CVdpauBufferStats *stats;
229  CDecoder *vdpau;
230  int upscale;
231  CVideoSurfaces *videoSurfaces;
232  int numRenderBuffers;
233  uint32_t maxReferences;
234  bool useInteropYuv;
235  CVDPAUContext *context;
236  CProcessInfo *processInfo;
237  int resetCounter;
238  uint64_t timeOpened;
239 };
240 
246 {
247  CVdpauDecodedPicture() = default;
249  {
250  *this = rhs;
251  }
252  CVdpauDecodedPicture& operator=(const CVdpauDecodedPicture& rhs)
253  {
254  DVDPic.SetParams(rhs.DVDPic);
255  videoSurface = rhs.videoSurface;
256  isYuv = rhs.isYuv;
257  return *this;
258  };
259  VideoPicture DVDPic;
260  VdpVideoSurface videoSurface;
261  bool isYuv;
262 };
263 
268 {
269  CVdpauProcessedPicture() = default;
271  {
272  *this = rhs;
273  }
274  CVdpauProcessedPicture& operator=(const CVdpauProcessedPicture& rhs)
275  {
276  DVDPic.SetParams(rhs.DVDPic);
277  videoSurface = rhs.videoSurface;
278  outputSurface = rhs.outputSurface;
279  crop = rhs.crop;
280  isYuv = rhs.isYuv;
281  id = rhs.id;
282  return *this;
283  };
284 
285  VideoPicture DVDPic;
286  VdpVideoSurface videoSurface = VDP_INVALID_HANDLE;
287  VdpOutputSurface outputSurface = VDP_INVALID_HANDLE;
288  bool crop;
289  bool isYuv;
290  int id = 0;
291 };
292 
294 {
295 public:
296  explicit CVdpauRenderPicture(int id) : CVideoBuffer(id) { }
297  VideoPicture DVDPic;
298  CVdpauProcessedPicture procPic;
299  int width;
300  int height;
301  CRect crop;
302  void *device;
303  void *procFunc;
304  int64_t ident;
305 };
306 
307 //-----------------------------------------------------------------------------
308 // Mixer
309 //-----------------------------------------------------------------------------
310 
312 {
313 public:
314  CMixerControlProtocol(std::string name, CEvent* inEvent, CEvent* outEvent)
315  : Protocol(std::move(name), inEvent, outEvent)
316  {
317  }
318  enum OutSignal
319  {
320  INIT = 0,
321  FLUSH,
322  TIMEOUT,
323  };
324  enum InSignal
325  {
326  ACC,
327  ERROR,
328  };
329 };
330 
332 {
333 public:
334  CMixerDataProtocol(std::string name, CEvent* inEvent, CEvent* outEvent)
335  : Protocol(std::move(name), inEvent, outEvent)
336  {
337  }
338  enum OutSignal
339  {
340  FRAME,
341  BUFFER,
342  };
343  enum InSignal
344  {
345  PICTURE,
346  };
347 };
348 
354 class CMixer : private CThread
355 {
356 public:
357  explicit CMixer(CEvent *inMsgEvent);
358  ~CMixer() override;
359  void Start();
360  void Dispose();
361  bool IsActive();
362  CMixerControlProtocol m_controlPort;
363  CMixerDataProtocol m_dataPort;
364 protected:
365  void OnStartup() override;
366  void OnExit() override;
367  void Process() override;
368  void StateMachine(int signal, Actor::Protocol *port, Actor::Message *msg);
369  void Init();
370  void Uninit();
371  void Flush();
372  void CreateVdpauMixer();
373  void ProcessPicture();
374  void InitCycle();
375  void FiniCycle();
376  void CheckFeatures();
377  void SetPostProcFeatures(bool postProcEnabled);
378  void PostProcOff();
379  void InitCSCMatrix(int Width);
380  bool GenerateStudioCSCMatrix(VdpColorStandard colorStandard, VdpCSCMatrix &studioCSCMatrix);
381  void SetColor();
382  void SetNoiseReduction();
383  void SetSharpness();
384  void SetDeintSkipChroma();
385  void SetDeinterlacing();
386  void SetHWUpscaling();
387  void DisableHQScaling();
388  std::string GetDeintStrFromInterlaceMethod(EINTERLACEMETHOD method);
389  bool CheckStatus(VdpStatus vdp_st, int line);
390  CEvent m_outMsgEvent;
391  CEvent *m_inMsgEvent;
392  int m_state;
393  bool m_bStateMachineSelfTrigger;
394 
395  // extended state variables for state machine
396  int m_extTimeout;
397  bool m_vdpError;
398  CVdpauConfig m_config;
399  VdpVideoMixer m_videoMixer;
400  VdpProcamp m_Procamp;
401  VdpCSCMatrix m_CSCMatrix;
402  bool m_PostProc;
403  float m_Brightness;
404  float m_Contrast;
405  float m_NoiseReduction;
406  float m_Sharpness;
407  int m_Deint;
408  int m_Upscale;
409  bool m_SeenInterlaceFlag;
410  unsigned int m_ColorMatrix : 4;
411  VdpVideoMixerPictureStructure m_mixerfield;
412  int m_mixerstep;
413  int m_mixersteps;
414  CVdpauProcessedPicture m_processPicture;
415  std::queue<VdpOutputSurface> m_outputSurfaces;
416  std::queue<CVdpauDecodedPicture> m_decodedPics;
417  std::deque<CVdpauDecodedPicture> m_mixerInput;
418 };
419 
420 //-----------------------------------------------------------------------------
421 // Output
422 //-----------------------------------------------------------------------------
423 
425 {
426 public:
427  COutputControlProtocol(std::string name, CEvent* inEvent, CEvent* outEvent)
428  : Actor::Protocol(std::move(name), inEvent, outEvent)
429  {
430  }
431  enum OutSignal
432  {
433  INIT,
434  FLUSH,
435  PRECLEANUP,
436  TIMEOUT,
437  };
438  enum InSignal
439  {
440  ACC,
441  ERROR,
442  STATS,
443  };
444 };
445 
447 {
448 public:
449  COutputDataProtocol(std::string name, CEvent* inEvent, CEvent* outEvent)
450  : Actor::Protocol(std::move(name), inEvent, outEvent)
451  {
452  }
453  enum OutSignal
454  {
455  NEWFRAME = 0,
456  RETURNPIC,
457  };
458  enum InSignal
459  {
460  PICTURE,
461  };
462 };
463 
470 class CVdpauBufferPool;
471 
472 class COutput : private CThread
473 {
474 public:
475  COutput(CDecoder &decoder, CEvent *inMsgEvent);
476  ~COutput() override;
477  void Start();
478  void Dispose();
479  COutputControlProtocol m_controlPort;
480  COutputDataProtocol m_dataPort;
481 protected:
482  void OnStartup() override;
483  void OnExit() override;
484  void Process() override;
485  void StateMachine(int signal, Actor::Protocol *port, Actor::Message *msg);
486  bool HasWork();
487  CVdpauRenderPicture *ProcessMixerPicture();
488  void QueueReturnPicture(CVdpauRenderPicture *pic);
489  void ProcessReturnPicture(CVdpauRenderPicture *pic);
490  void ProcessSyncPicture();
491  bool Init();
492  bool Uninit();
493  void Flush();
494  bool EnsureBufferPool();
495  void ReleaseBufferPool();
496  void PreCleanup();
497  void InitMixer();
498  bool CheckStatus(VdpStatus vdp_st, int line);
499  CEvent m_outMsgEvent;
500  CEvent *m_inMsgEvent;
501  int m_state;
502  bool m_bStateMachineSelfTrigger;
503  CDecoder &m_vdpau;
504 
505  // extended state variables for state machine
506  int m_extTimeout;
507  bool m_vdpError;
508  CVdpauConfig m_config;
509  std::shared_ptr<CVdpauBufferPool> m_bufferPool;
510  CMixer m_mixer;
511 };
512 
513 //-----------------------------------------------------------------------------
514 // VDPAU Video Surface states
515 //-----------------------------------------------------------------------------
516 
518 {
519 public:
520  void AddSurface(VdpVideoSurface surf);
521  void ClearReference(VdpVideoSurface surf);
522  bool MarkRender(VdpVideoSurface surf);
523  void ClearRender(VdpVideoSurface surf);
524  bool IsValid(VdpVideoSurface surf);
525  VdpVideoSurface GetFree(VdpVideoSurface surf);
526  VdpVideoSurface RemoveNext(bool skiprender = false);
527  void Reset();
528  int Size();
529  bool HasRefs();
530 protected:
531  std::map<VdpVideoSurface, int> m_state;
532  std::list<VdpVideoSurface> m_freeSurfaces;
533  CCriticalSection m_section;
534 };
535 
536 //-----------------------------------------------------------------------------
537 // VDPAU decoder
538 //-----------------------------------------------------------------------------
539 
541 {
542 public:
543  static bool EnsureContext(CVDPAUContext **ctx);
544  void Release();
545  VDPAU_procs& GetProcs();
546  VdpDevice GetDevice();
547  bool Supports(VdpVideoMixerFeature feature);
548  VdpVideoMixerFeature* GetFeatures();
549  int GetFeatureCount();
550 private:
551  CVDPAUContext();
552  void Close();
553  bool LoadSymbols();
554  bool CreateContext();
555  void DestroyContext();
556  void QueryProcs();
557  void SpewHardwareAvailable();
558  static CVDPAUContext *m_context;
559  static CCriticalSection m_section;
560  static Display *m_display;
561  int m_refCount;
562  VdpVideoMixerFeature m_vdpFeatures[14];
563  int m_featureCount;
564  static void *m_dlHandle;
565  VdpDevice m_vdpDevice;
566  VDPAU_procs m_vdpProcs;
567  VdpStatus (*dl_vdp_device_create_x11)(Display* display, int screen, VdpDevice* device, VdpGetProcAddress **get_proc_address);
568 };
569 
573 class CDecoder
574  : public IHardwareDecoder
575  , public IDispResource
576 {
577  friend class CVdpauBufferPool;
578 
579 public:
580 
581  struct Desc
582  {
583  const char *name;
584  uint32_t id;
585  uint32_t aux; /* optional extra parameter... */
586  };
587 
588  explicit CDecoder(CProcessInfo& processInfo);
589  ~CDecoder() override;
590 
591  bool Open (AVCodecContext* avctx, AVCodecContext* mainctx, const enum AVPixelFormat) override;
592  CDVDVideoCodec::VCReturn Decode (AVCodecContext* avctx, AVFrame* frame) override;
593  bool GetPicture(AVCodecContext* avctx, VideoPicture* picture) override;
594  void Reset() override;
595  virtual void Close();
596  long Release() override;
597  bool CanSkipDeint() override;
598  unsigned GetAllowedReferences() override { return 5; }
599 
600  CDVDVideoCodec::VCReturn Check(AVCodecContext* avctx) override;
601  const std::string Name() override { return "vdpau"; }
602  void SetCodecControl(int flags) override;
603 
604  bool Supports(VdpVideoMixerFeature feature);
605  static bool IsVDPAUFormat(AVPixelFormat fmt);
606 
607  static void FFReleaseBuffer(void *opaque, uint8_t *data);
608  static int FFGetBuffer(AVCodecContext *avctx, AVFrame *pic, int flags);
609  static int Render(struct AVCodecContext *s, struct AVFrame *src,
610  const VdpPictureInfo *info, uint32_t buffers_used,
611  const VdpBitstreamBuffer *buffers);
612 
613  void OnLostDisplay() override;
614  void OnResetDisplay() override;
615 
616  static IHardwareDecoder* Create(CDVDStreamInfo &hint, CProcessInfo &processInfo, AVPixelFormat fmt);
617  static void Register();
618 
619 protected:
620  void SetWidthHeight(int width, int height);
621  bool ConfigVDPAU(AVCodecContext *avctx, int ref_frames);
622  bool CheckStatus(VdpStatus vdp_st, int line);
623  void FiniVDPAUOutput();
624  void ReturnRenderPicture(CVdpauRenderPicture *renderPic);
625  long ReleasePicReference();
626 
627  static void ReadFormatOf( AVCodecID codec
628  , VdpDecoderProfile &decoder_profile
629  , VdpChromaType &chroma_type);
630 
631  // OnLostDevice triggers transition from all states to LOST
632  // internal errors trigger transition from OPEN to RESET
633  // OnResetDevice triggers transition from LOST to RESET
634  enum EDisplayState
635  { VDPAU_OPEN
636  , VDPAU_RESET
637  , VDPAU_LOST
638  , VDPAU_ERROR
639  } m_DisplayState;
640  CCriticalSection m_DecoderSection;
641  CEvent m_DisplayEvent;
642  int m_ErrorCount;
643 
644  bool m_vdpauConfigured;
645  CVdpauConfig m_vdpauConfig;
646  CVideoSurfaces m_videoSurfaces;
647  AVVDPAUContext m_hwContext;
648  AVCodecContext* m_avctx = nullptr;
649 
650  COutput m_vdpauOutput;
651  CVdpauBufferStats m_bufferStats;
652  CEvent m_inMsgEvent;
653  CVdpauRenderPicture *m_presentPicture = nullptr;
654 
655  int m_codecControl;
656  CProcessInfo& m_processInfo;
657 
658  static bool m_capGeneral;
659 };
660 
661 }
This is an Event class built from a ConditionVariable.
Definition: Event.h:35
Definition: DVDStreamInfo.h:25
Definition: VideoBuffer.h:85
Definition: Thread.h:44
Buffer statistics used to control number of frames in queue.
Definition: VDPAU.h:112
Definition: ActorProtocol.h:73
Definition: VDPAU.h:424
Embeds the vdpau video mixer Embedded by COutput class, gets decoded frames from COutput, processes them in mixer ands sends processed frames back to COutput.
Definition: VDPAU.h:354
Definition: VDPAU.h:446
Definition: VDPAU.h:517
Definition: DVDVideoCodec.h:245
Definition: VDPAU.h:472
Definition: ActorProtocol.h:45
VDPAU main class.
Definition: VDPAU.h:573
Definition: VDPAU.h:581
Definition: DispResource.h:14
Definition: VDPAU.h:311
Holds a decoded frame Input to COutput for further processing.
Definition: VDPAU.h:245
Definition: ProcessInfo.h:26
Definition: VDPAU.cpp:1396
Definition: VDPAU.h:540
Definition: VDPAU.h:57
Definition: DVDVideoCodec.h:36
Frame after having been processed by vdpau mixer.
Definition: VDPAU.h:267
VDPAU interface to driver.
Definition: VDPAU.h:64
Definition: VDPAU.h:218
Definition: VDPAU.h:331
Definition: VDPAU.h:293