1 /*
2  *  Copyright (C) 2017-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 #include "RPProcessInfo.h"
10 
11 #include "ServiceBroker.h"
12 #include "cores/DataCacheCore.h"
13 #include "cores/RetroPlayer/buffers/RenderBufferManager.h"
14 #include "cores/RetroPlayer/rendering/RenderContext.h"
15 #include "settings/DisplaySettings.h"
16 #include "settings/MediaSettings.h"
17 #include "threads/SingleLock.h"
18 #include "utils/log.h"
19 #include "windowing/GraphicContext.h"
20 #include "windowing/WinSystem.h"
21 
22 extern "C"
23 {
24 #include <libavutil/pixdesc.h>
25 }
26 
27 #include <utility>
28 
29 using namespace KODI;
30 using namespace RETRO;
31 
32 CreateRPProcessControl CRPProcessInfo::m_processControl = nullptr;
33 std::vector<std::unique_ptr<IRendererFactory>> CRPProcessInfo::m_rendererFactories;
34 CCriticalSection CRPProcessInfo::m_createSection;
35 
CRPProcessInfo(std::string platformName)36 CRPProcessInfo::CRPProcessInfo(std::string platformName)
37   : m_platformName(std::move(platformName)),
38     m_renderBufferManager(new CRenderBufferManager),
39     m_renderContext(new CRenderContext(CServiceBroker::GetRenderSystem(),
40                                        CServiceBroker::GetWinSystem(),
41                                        CServiceBroker::GetWinSystem()->GetGfxContext(),
42                                        CDisplaySettings::GetInstance(),
43                                        CMediaSettings::GetInstance()))
44 {
45   for (auto& rendererFactory : m_rendererFactories)
46   {
47     RenderBufferPoolVector bufferPools = rendererFactory->CreateBufferPools(*m_renderContext);
48     if (!bufferPools.empty())
49       m_renderBufferManager->RegisterPools(rendererFactory.get(), std::move(bufferPools));
50   }
51 
52   // Initialize default scaling method
53   for (auto scalingMethod : GetScalingMethods())
54   {
55     if (HasScalingMethod(scalingMethod))
56     {
57       m_defaultScalingMethod = scalingMethod;
58       break;
59     }
60   }
61 }
62 
63 CRPProcessInfo::~CRPProcessInfo() = default;
64 
CreateInstance()65 CRPProcessInfo* CRPProcessInfo::CreateInstance()
66 {
67   CRPProcessInfo* processInfo = nullptr;
68 
69   CSingleLock lock(m_createSection);
70 
71   if (m_processControl != nullptr)
72   {
73     processInfo = m_processControl();
74 
75     if (processInfo != nullptr)
76       CLog::Log(LOGINFO, "RetroPlayer[PROCESS]: Created process info for %s",
77                 processInfo->GetPlatformName().c_str());
78     else
79       CLog::Log(LOGERROR, "RetroPlayer[PROCESS]: Failed to create process info");
80   }
81   else
82   {
83     CLog::Log(LOGERROR, "RetroPlayer[PROCESS]: No process control registered");
84   }
85 
86   return processInfo;
87 }
88 
RegisterProcessControl(CreateRPProcessControl createFunc)89 void CRPProcessInfo::RegisterProcessControl(CreateRPProcessControl createFunc)
90 {
91   std::unique_ptr<CRPProcessInfo> processInfo(createFunc());
92 
93   CSingleLock lock(m_createSection);
94 
95   if (processInfo)
96   {
97     CLog::Log(LOGINFO, "RetroPlayer[PROCESS]: Registering process control for %s",
98               processInfo->GetPlatformName().c_str());
99     m_processControl = createFunc;
100   }
101   else
102   {
103     CLog::Log(LOGERROR, "RetroPlayer[PROCESS]: Failed to register process control");
104     m_processControl = nullptr;
105   }
106 }
107 
RegisterRendererFactory(IRendererFactory * factory)108 void CRPProcessInfo::RegisterRendererFactory(IRendererFactory* factory)
109 {
110   CSingleLock lock(m_createSection);
111 
112   CLog::Log(LOGINFO, "RetroPlayer[RENDER]: Registering renderer factory for %s",
113             factory->RenderSystemName().c_str());
114 
115   m_rendererFactories.emplace_back(factory);
116 }
117 
GetRenderSystemName(IRenderBufferPool * renderBufferPool) const118 std::string CRPProcessInfo::GetRenderSystemName(IRenderBufferPool* renderBufferPool) const
119 {
120   return m_renderBufferManager->GetRenderSystemName(renderBufferPool);
121 }
122 
CreateRenderer(IRenderBufferPool * renderBufferPool,const CRenderSettings & renderSettings)123 CRPBaseRenderer* CRPProcessInfo::CreateRenderer(IRenderBufferPool* renderBufferPool,
124                                                 const CRenderSettings& renderSettings)
125 {
126   CSingleLock lock(m_createSection);
127 
128   for (auto& rendererFactory : m_rendererFactories)
129   {
130     RenderBufferPoolVector bufferPools = m_renderBufferManager->GetPools(rendererFactory.get());
131     for (auto& bufferPool : bufferPools)
132     {
133       if (bufferPool.get() == renderBufferPool)
134         return rendererFactory->CreateRenderer(renderSettings, *m_renderContext,
135                                                std::move(bufferPool));
136     }
137   }
138 
139   CLog::Log(LOGERROR, "RetroPlayer[RENDER]: Failed to find a suitable renderer factory");
140 
141   return nullptr;
142 }
143 
SetDataCache(CDataCacheCore * cache)144 void CRPProcessInfo::SetDataCache(CDataCacheCore* cache)
145 {
146   m_dataCache = cache;
147   ;
148 }
149 
ResetInfo()150 void CRPProcessInfo::ResetInfo()
151 {
152   if (m_dataCache != nullptr)
153   {
154     m_dataCache->SetVideoDecoderName("", false);
155     m_dataCache->SetVideoDeintMethod("");
156     m_dataCache->SetVideoPixelFormat("");
157     m_dataCache->SetVideoDimensions(0, 0);
158     m_dataCache->SetVideoFps(0.0f);
159     m_dataCache->SetVideoDAR(1.0f);
160     m_dataCache->SetAudioDecoderName("");
161     m_dataCache->SetAudioChannels("");
162     m_dataCache->SetAudioSampleRate(0);
163     m_dataCache->SetAudioBitsPerSample(0);
164     m_dataCache->SetRenderClockSync(false);
165     m_dataCache->SetStateSeeking(false);
166     m_dataCache->SetSpeed(1.0f, 1.0f);
167     m_dataCache->SetGuiRender(true); //! @todo
168     m_dataCache->SetVideoRender(false); //! @todo
169     m_dataCache->SetPlayTimes(0, 0, 0, 0);
170   }
171 }
172 
HasScalingMethod(SCALINGMETHOD scalingMethod) const173 bool CRPProcessInfo::HasScalingMethod(SCALINGMETHOD scalingMethod) const
174 {
175   return m_renderBufferManager->HasScalingMethod(scalingMethod);
176 }
177 
GetScalingMethods()178 std::vector<SCALINGMETHOD> CRPProcessInfo::GetScalingMethods()
179 {
180   return {
181       SCALINGMETHOD::NEAREST,
182       SCALINGMETHOD::LINEAR,
183   };
184 }
185 
186 //******************************************************************************
187 // video codec
188 //******************************************************************************
SetVideoPixelFormat(AVPixelFormat pixFormat)189 void CRPProcessInfo::SetVideoPixelFormat(AVPixelFormat pixFormat)
190 {
191   const char* videoPixelFormat = av_get_pix_fmt_name(pixFormat);
192 
193   if (m_dataCache != nullptr)
194     m_dataCache->SetVideoPixelFormat(videoPixelFormat != nullptr ? videoPixelFormat : "");
195 }
196 
SetVideoDimensions(int width,int height)197 void CRPProcessInfo::SetVideoDimensions(int width, int height)
198 {
199   if (m_dataCache != nullptr)
200     m_dataCache->SetVideoDimensions(width, height);
201 }
202 
SetVideoFps(float fps)203 void CRPProcessInfo::SetVideoFps(float fps)
204 {
205   if (m_dataCache != nullptr)
206     m_dataCache->SetVideoFps(fps);
207 }
208 
209 //******************************************************************************
210 // player audio info
211 //******************************************************************************
SetAudioChannels(const std::string & channels)212 void CRPProcessInfo::SetAudioChannels(const std::string& channels)
213 {
214   if (m_dataCache != nullptr)
215     m_dataCache->SetAudioChannels(channels);
216 }
217 
SetAudioSampleRate(int sampleRate)218 void CRPProcessInfo::SetAudioSampleRate(int sampleRate)
219 {
220   if (m_dataCache != nullptr)
221     m_dataCache->SetAudioSampleRate(sampleRate);
222 }
223 
SetAudioBitsPerSample(int bitsPerSample)224 void CRPProcessInfo::SetAudioBitsPerSample(int bitsPerSample)
225 {
226   if (m_dataCache != nullptr)
227     m_dataCache->SetAudioBitsPerSample(bitsPerSample);
228 }
229 
230 //******************************************************************************
231 // player states
232 //******************************************************************************
SetSpeed(float speed)233 void CRPProcessInfo::SetSpeed(float speed)
234 {
235   if (m_dataCache != nullptr)
236     m_dataCache->SetSpeed(1.0f, speed);
237 }
238 
SetPlayTimes(time_t start,int64_t current,int64_t min,int64_t max)239 void CRPProcessInfo::SetPlayTimes(time_t start, int64_t current, int64_t min, int64_t max)
240 {
241   if (m_dataCache != nullptr)
242     m_dataCache->SetPlayTimes(start, current, min, max);
243 }
244