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 
11 #include "DVDClock.h"
12 #include "DebugRenderer.h"
13 #include "cores/VideoPlayer/VideoRenderers/BaseRenderer.h"
14 #include "cores/VideoPlayer/VideoRenderers/OverlayRenderer.h"
15 #include "cores/VideoSettings.h"
16 #include "threads/CriticalSection.h"
17 #include "threads/Event.h"
18 #include "utils/Geometry.h"
19 #include "windowing/Resolution.h"
20 
21 #include <atomic>
22 #include <deque>
23 #include <list>
24 #include <map>
25 
26 #include "PlatformDefs.h"
27 
28 class CRenderCapture;
29 struct VideoPicture;
30 
31 class CWinRenderer;
32 class CLinuxRenderer;
33 class CLinuxRendererGL;
34 class CLinuxRendererGLES;
35 class CRenderManager;
36 
37 class IRenderMsg
38 {
39   friend CRenderManager;
40 public:
41   virtual ~IRenderMsg() = default;
42 protected:
43   virtual void VideoParamsChange() = 0;
44   virtual void GetDebugInfo(std::string &audio, std::string &video, std::string &general) = 0;
45   virtual void UpdateClockSync(bool enabled) = 0;
46   virtual void UpdateRenderInfo(CRenderInfo &info) = 0;
47   virtual void UpdateRenderBuffers(int queued, int discard, int free) = 0;
48   virtual void UpdateGuiRender(bool gui) = 0;
49   virtual void UpdateVideoRender(bool video) = 0;
50   virtual CVideoSettings GetVideoSettings() = 0;
51 };
52 
53 class CRenderManager
54 {
55 public:
56   CRenderManager(CDVDClock &clock, IRenderMsg *player);
57   virtual ~CRenderManager();
58 
59   // Functions called from render thread
60   void GetVideoRect(CRect &source, CRect &dest, CRect &view);
61   float GetAspectRatio();
62   void FrameMove();
63   void FrameWait(int ms);
64   void Render(bool clear, DWORD flags = 0, DWORD alpha = 255, bool gui = true);
65   bool IsVideoLayer();
66   RESOLUTION GetResolution();
67   void UpdateResolution();
68   void TriggerUpdateResolution(float fps, int width, int height, std::string &stereomode);
69   void SetViewMode(int iViewMode);
70   void PreInit();
71   void UnInit();
72   bool Flush(bool wait, bool saveBuffers);
73   bool IsConfigured() const;
74   void ToggleDebug();
75   void ToggleDebugVideo();
76 
77   unsigned int AllocRenderCapture();
78   void ReleaseRenderCapture(unsigned int captureId);
79   void StartRenderCapture(unsigned int captureId, unsigned int width, unsigned int height, int flags);
80   bool RenderCaptureGetPixels(unsigned int captureId, unsigned int millis, uint8_t *buffer, unsigned int size);
81 
82   // Functions called from GUI
83   bool Supports(ERENDERFEATURE feature);
84   bool Supports(ESCALINGMETHOD method);
85 
GetSkippedFrames()86   int GetSkippedFrames()  { return m_QueueSkip; }
87 
88   bool Configure(const VideoPicture& picture, float fps, unsigned int orientation, int buffers = 0);
89   bool AddVideoPicture(const VideoPicture& picture, volatile std::atomic_bool& bStop, EINTERLACEMETHOD deintMethod, bool wait);
90   void AddOverlay(CDVDOverlay* o, double pts);
91   void ShowVideo(bool enable);
92 
93   /**
94    * If player uses buffering it has to wait for a buffer before it calls
95    * AddVideoPicture and AddOverlay. It waits for max 50 ms before it returns -1
96    * in case no buffer is available. Player may call this in a loop and decides
97    * by itself when it wants to drop a frame.
98    */
99   int WaitForBuffer(volatile std::atomic_bool& bStop, int timeout = 100);
100 
101   /**
102    * Can be called by player for lateness detection. This is done best by
103    * looking at the end of the queue.
104    */
105   bool GetStats(int &lateframes, double &pts, int &queued, int &discard);
106 
107   /**
108    * Video player call this on flush in oder to discard any queued frames
109    */
110   void DiscardBuffer();
111 
SetDelay(int delay)112   void SetDelay(int delay) { m_videoDelay = delay; };
GetDelay()113   int GetDelay() { return m_videoDelay; };
114 
115   void SetVideoSettings(CVideoSettings settings);
116 
117 protected:
118 
119   void PresentSingle(bool clear, DWORD flags, DWORD alpha);
120   void PresentFields(bool clear, DWORD flags, DWORD alpha);
121   void PresentBlend(bool clear, DWORD flags, DWORD alpha);
122 
123   void PrepareNextRender();
124   bool IsPresenting();
125   bool IsGuiLayer();
126 
127   bool Configure();
128   void CreateRenderer();
129   void DeleteRenderer();
130   void ManageCaptures();
131 
132   void UpdateLatencyTweak();
133   void CheckEnableClockSync();
134 
135   CBaseRenderer *m_pRenderer = nullptr;
136   OVERLAY::CRenderer m_overlays;
137   CDebugRenderer m_debugRenderer;
138   mutable CCriticalSection m_statelock;
139   CCriticalSection m_presentlock;
140   CCriticalSection m_datalock;
141   bool m_bTriggerUpdateResolution = false;
142   bool m_bRenderGUI = true;
143   bool m_renderedOverlay = false;
144   bool m_renderDebug = false;
145   bool m_renderDebugVideo = false;
146   XbmcThreads::EndTime m_debugTimer;
147   std::atomic_bool m_showVideo = {false};
148 
149   enum EPRESENTSTEP
150   {
151     PRESENT_IDLE     = 0
152   , PRESENT_FLIP
153   , PRESENT_FRAME
154   , PRESENT_FRAME2
155   , PRESENT_READY
156   };
157 
158   enum EPRESENTMETHOD
159   {
160     PRESENT_METHOD_SINGLE = 0,
161     PRESENT_METHOD_BLEND,
162     PRESENT_METHOD_BOB,
163   };
164 
165   enum ERENDERSTATE
166   {
167     STATE_UNCONFIGURED = 0,
168     STATE_CONFIGURING,
169     STATE_CONFIGURED,
170   };
171   ERENDERSTATE m_renderState = STATE_UNCONFIGURED;
172   CEvent m_stateEvent;
173 
174   /// Display latency tweak value from AdvancedSettings for the current refresh rate
175   /// in milliseconds
176   double m_latencyTweak = 0.0;
177   /// Display latency updated in PrepareNextRender in DVD clock units, includes m_latencyTweak
178   double m_displayLatency = 0.0;
179   std::atomic_int m_videoDelay = {0};
180 
181   int m_QueueSize = 2;
182   int m_QueueSkip = 0;
183 
184   struct SPresent
185   {
186     double         pts;
187     EFIELDSYNC     presentfield;
188     EPRESENTMETHOD presentmethod;
189   } m_Queue[NUM_BUFFERS];
190 
191   std::deque<int> m_free;
192   std::deque<int> m_queued;
193   std::deque<int> m_discard;
194 
195   std::unique_ptr<VideoPicture> m_pConfigPicture;
196   unsigned int m_width = 0;
197   unsigned int m_height = 0;
198   unsigned int m_dwidth = 0;
199   unsigned int m_dheight = 0;
200   float m_fps = 0.0;
201   unsigned int m_orientation = 0;
202   int m_NumberBuffers = 0;
203   std::string m_stereomode;
204 
205   int m_lateframes = -1;
206   double m_presentpts = 0.0;
207   EPRESENTSTEP m_presentstep = PRESENT_IDLE;
208   XbmcThreads::EndTime m_presentTimer;
209   bool m_forceNext = false;
210   int m_presentsource = 0;
211   int m_presentsourcePast = -1;
212   XbmcThreads::ConditionVariable m_presentevent;
213   CEvent m_flushEvent;
214   CEvent m_initEvent;
215   CDVDClock &m_dvdClock;
216   IRenderMsg *m_playerPort;
217 
218   struct CClockSync
219   {
220     void Reset();
221     double m_error;
222     int m_errCount;
223     double m_syncOffset;
224     bool m_enabled;
225   };
226   CClockSync m_clockSync;
227 
228   void RenderCapture(CRenderCapture* capture);
229   void RemoveCaptures();
230   CCriticalSection m_captCritSect;
231   std::map<unsigned int, CRenderCapture*> m_captures;
232   static unsigned int m_nextCaptureId;
233   unsigned int m_captureWaitCounter = 0;
234   //set to true when adding something to m_captures, set to false when m_captures is made empty
235   //std::list::empty() isn't thread safe, using an extra bool will save a lock per render when no captures are requested
236   bool m_hasCaptures = false;
237 };
238