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