Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : */
9 :
10 : #include "oglplayer.hxx"
11 : #include "oglframegrabber.hxx"
12 : #include "oglwindow.hxx"
13 :
14 : #include <cppuhelper/supportsservice.hxx>
15 : #include <tools/stream.hxx>
16 : #include <vcl/graph.hxx>
17 : #include <vcl/graphicfilter.hxx>
18 : #include <tools/urlobj.hxx>
19 : #include <vcl/opengl/OpenGLHelper.hxx>
20 :
21 : #include <cassert>
22 :
23 : using namespace com::sun::star;
24 : using namespace libgltf;
25 :
26 : namespace avmedia { namespace ogl {
27 :
28 0 : OGLPlayer::OGLPlayer()
29 : : Player_BASE(m_aMutex)
30 : , m_pHandle(NULL)
31 : , m_pOGLWindow(NULL)
32 0 : , m_bIsRendering(false)
33 : {
34 0 : }
35 :
36 0 : OGLPlayer::~OGLPlayer()
37 : {
38 0 : osl::MutexGuard aGuard(m_aMutex);
39 0 : if( m_pHandle )
40 : {
41 0 : m_aContext.makeCurrent();
42 0 : gltf_renderer_release(m_pHandle);
43 : }
44 0 : releaseInputFiles();
45 0 : }
46 :
47 0 : static bool lcl_LoadFile( glTFFile* io_pFile, const OUString& rURL)
48 : {
49 0 : SvFileStream aStream( rURL, STREAM_READ );
50 0 : if( !aStream.IsOpen() )
51 0 : return false;
52 :
53 0 : const sal_Int64 nBytes = aStream.remainingSize();
54 0 : char* pBuffer = new char[nBytes];
55 0 : aStream.Read( pBuffer, nBytes );
56 0 : aStream.Close();
57 :
58 0 : io_pFile->buffer = pBuffer;
59 0 : io_pFile->size = nBytes;
60 :
61 0 : return true;
62 : }
63 :
64 0 : bool OGLPlayer::create( const OUString& rURL )
65 : {
66 0 : osl::MutexGuard aGuard(m_aMutex);
67 :
68 0 : m_sURL = rURL;
69 :
70 : // Convert URL to a system path
71 0 : const INetURLObject aURLObj(m_sURL);
72 0 : const std::string sFilePath = OUStringToOString( aURLObj.getFSysPath(INetURLObject::FSYS_DETECT), RTL_TEXTENCODING_UTF8 ).getStr();
73 :
74 : // Load *.json file and init renderer
75 0 : m_pHandle = gltf_renderer_init(sFilePath, m_vInputFiles);
76 :
77 0 : if( !m_pHandle )
78 : {
79 : SAL_WARN("avmedia.opengl", "gltf_renderer_init returned an invalid glTFHandle");
80 0 : return false;
81 : }
82 :
83 : // Load external resources
84 0 : for( size_t i = 0; i < m_vInputFiles.size(); ++i )
85 : {
86 0 : glTFFile& rFile = m_vInputFiles[i];
87 0 : if( !rFile.filename.empty() )
88 : {
89 : const OUString sFilesURL =
90 0 : INetURLObject::GetAbsURL(m_sURL,OStringToOUString(OString(rFile.filename.c_str()),RTL_TEXTENCODING_UTF8));
91 0 : if( rFile.type == GLTF_IMAGE )
92 : {
93 : // Load images as bitmaps
94 0 : GraphicFilter aFilter;
95 0 : Graphic aGraphic;
96 0 : if( aFilter.ImportGraphic(aGraphic, INetURLObject(sFilesURL)) != GRFILTER_OK )
97 : {
98 0 : rFile.buffer = 0;
99 0 : rFile.imagewidth = 0;
100 0 : rFile.imageheight = 0;
101 : SAL_WARN("avmedia.opengl", "Can't load texture file: " + sFilesURL);
102 0 : return false;
103 : }
104 0 : BitmapEx aBitmapEx = aGraphic.GetBitmapEx();
105 0 : rFile.buffer = new char[4 * aBitmapEx.GetSizePixel().Width() * aBitmapEx.GetSizePixel().Height()];
106 0 : OpenGLHelper::ConvertBitmapExToRGBATextureBuffer(aBitmapEx, reinterpret_cast<sal_uInt8*>(rFile.buffer), true);
107 0 : rFile.imagewidth = aBitmapEx.GetSizePixel().Width();
108 0 : rFile.imageheight = aBitmapEx.GetSizePixel().Height();
109 : }
110 0 : else if( rFile.type == GLTF_BINARY || rFile.type == GLTF_GLSL )
111 : {
112 0 : if( !lcl_LoadFile(&rFile, sFilesURL) )
113 : {
114 0 : rFile.buffer = 0;
115 0 : rFile.size = 0;
116 : SAL_WARN("avmedia.opengl", "Can't load glTF file: " + sFilesURL);
117 0 : return false;
118 : }
119 0 : }
120 : }
121 : }
122 :
123 : // Set timer
124 0 : m_aTimer.SetTimeout(1);
125 0 : m_aTimer.SetTimeoutHdl(LINK(this,OGLPlayer,TimerHandler));
126 0 : return true;
127 : }
128 :
129 0 : void OGLPlayer::releaseInputFiles()
130 : {
131 0 : for (size_t i = 0; i < m_vInputFiles.size() && m_vInputFiles[i].buffer; ++i)
132 : {
133 0 : delete [] m_vInputFiles[i].buffer;
134 0 : m_vInputFiles[i].buffer = 0;
135 : }
136 0 : m_vInputFiles.clear();
137 0 : }
138 :
139 0 : void SAL_CALL OGLPlayer::start() throw ( uno::RuntimeException, std::exception )
140 : {
141 0 : osl::MutexGuard aGuard(m_aMutex);
142 : assert(m_pHandle);
143 :
144 0 : if(!m_pOGLWindow)
145 0 : return;
146 :
147 0 : gltf_animation_resume(m_pHandle);
148 0 : m_aTimer.Start();
149 0 : m_bIsRendering = true;
150 : }
151 :
152 0 : void SAL_CALL OGLPlayer::stop() throw ( uno::RuntimeException, std::exception )
153 : {
154 0 : osl::MutexGuard aGuard(m_aMutex);
155 : assert(m_pHandle);
156 0 : m_aTimer.Stop();
157 0 : gltf_animation_stop(m_pHandle);
158 0 : m_bIsRendering = false;
159 0 : }
160 :
161 0 : sal_Bool SAL_CALL OGLPlayer::isPlaying() throw ( uno::RuntimeException, std::exception )
162 : {
163 0 : osl::MutexGuard aGuard(m_aMutex);
164 : assert(m_pHandle);
165 : // Here isPlaying means model is rendered in the window and
166 : // able to interact with the user (e.g. moving camera)
167 0 : if( getDuration() > 0.0 )
168 0 : return gltf_animation_is_playing(m_pHandle);
169 : else
170 0 : return m_bIsRendering;
171 : }
172 :
173 0 : double SAL_CALL OGLPlayer::getDuration() throw ( uno::RuntimeException, std::exception )
174 : {
175 0 : osl::MutexGuard aGuard(m_aMutex);
176 : assert(m_pHandle);
177 0 : return gltf_animation_get_duration(m_pHandle);
178 : }
179 :
180 0 : void SAL_CALL OGLPlayer::setMediaTime( double fTime ) throw ( uno::RuntimeException, std::exception )
181 : {
182 0 : osl::MutexGuard aGuard(m_aMutex);
183 : assert(m_pHandle);
184 0 : gltf_animation_set_time(m_pHandle, fTime);
185 0 : }
186 :
187 0 : double SAL_CALL OGLPlayer::getMediaTime() throw ( ::com::sun::star::uno::RuntimeException, std::exception )
188 : {
189 0 : osl::MutexGuard aGuard(m_aMutex);
190 : assert(m_pHandle);
191 0 : return gltf_animation_get_time(m_pHandle);
192 : }
193 :
194 0 : void SAL_CALL OGLPlayer::setPlaybackLoop( sal_Bool bSet ) throw ( uno::RuntimeException, std::exception )
195 : {
196 0 : osl::MutexGuard aGuard(m_aMutex);
197 : assert(m_pHandle);
198 0 : gltf_animation_set_looping(m_pHandle, bSet);
199 0 : }
200 :
201 0 : sal_Bool SAL_CALL OGLPlayer::isPlaybackLoop() throw ( uno::RuntimeException, std::exception )
202 : {
203 0 : osl::MutexGuard aGuard(m_aMutex);
204 : assert(m_pHandle);
205 0 : return gltf_animation_get_looping(m_pHandle);
206 : }
207 :
208 0 : void SAL_CALL OGLPlayer::setVolumeDB( sal_Int16 /*nVolumDB*/ ) throw ( uno::RuntimeException, std::exception )
209 : {
210 : // OpenGL models have no sound.
211 0 : }
212 :
213 0 : sal_Int16 SAL_CALL OGLPlayer::getVolumeDB() throw ( uno::RuntimeException, std::exception )
214 : {
215 : // OpenGL models have no sound.
216 0 : return 0;
217 : }
218 :
219 0 : void SAL_CALL OGLPlayer::setMute( sal_Bool /*bSet*/ ) throw ( uno::RuntimeException, std::exception )
220 : {
221 : // OpenGL models have no sound.
222 0 : }
223 :
224 0 : sal_Bool SAL_CALL OGLPlayer::isMute() throw ( uno::RuntimeException, std::exception )
225 : {
226 : // OpenGL models have no sound.
227 0 : return false;
228 : }
229 :
230 0 : awt::Size SAL_CALL OGLPlayer::getPreferredPlayerWindowSize() throw ( uno::RuntimeException, std::exception )
231 : {
232 0 : return awt::Size( 480, 360 );
233 : }
234 :
235 0 : static bool lcl_CheckOpenGLRequirements()
236 : {
237 0 : return OpenGLHelper::getGLVersion() >= 3.0;
238 : }
239 :
240 0 : uno::Reference< media::XPlayerWindow > SAL_CALL OGLPlayer::createPlayerWindow( const uno::Sequence< uno::Any >& rArguments )
241 : throw ( uno::RuntimeException, std::exception )
242 : {
243 0 : osl::MutexGuard aGuard( m_aMutex );
244 :
245 : assert( rArguments.getLength() >= 3 );
246 : assert(m_pHandle);
247 :
248 0 : sal_IntPtr pIntPtr = 0;
249 0 : rArguments[ 2 ] >>= pIntPtr;
250 0 : SystemChildWindow *pChildWindow = reinterpret_cast< SystemChildWindow* >( pIntPtr );
251 :
252 0 : if( !pChildWindow )
253 : {
254 : SAL_WARN("avmedia.opengl", "Failed to get the SystemChildWindow for rendering!");
255 0 : return uno::Reference< media::XPlayerWindow >();
256 : }
257 : assert(pChildWindow->GetParent());
258 :
259 0 : if( !m_aContext.init(pChildWindow) )
260 : {
261 : SAL_WARN("avmedia.opengl", "Context initialization failed");
262 0 : return uno::Reference< media::XPlayerWindow >();
263 : }
264 :
265 0 : if( !m_aContext.supportMultiSampling() )
266 : {
267 : SAL_WARN("avmedia.opengl", "Context does not support multisampling!");
268 0 : return uno::Reference< media::XPlayerWindow >();
269 : }
270 :
271 0 : if( !lcl_CheckOpenGLRequirements() )
272 : {
273 : SAL_WARN("avmedia.opengl", "Your platform does not have the minimal OpenGL requiremenets!");
274 0 : return uno::Reference< media::XPlayerWindow >();
275 : }
276 :
277 0 : Size aSize = pChildWindow->GetSizePixel();
278 0 : m_aContext.setWinSize(aSize);
279 0 : m_pHandle->viewport.x = 0;
280 0 : m_pHandle->viewport.y = 0;
281 0 : m_pHandle->viewport.width = aSize.Width();
282 0 : m_pHandle->viewport.height = aSize.Height();
283 :
284 : // TODO: Use the error codes to print a readable error message
285 0 : int nRet = gltf_renderer_set_content(m_pHandle, m_vInputFiles);
286 0 : releaseInputFiles();
287 0 : if( nRet != 0 )
288 : {
289 : SAL_WARN("avmedia.opengl", "Error occured while setting up the scene! Error code: " << nRet);
290 0 : return uno::Reference< media::XPlayerWindow >();
291 : }
292 : // The background color is white by default, but we need to separate the
293 : // OpenGL window from the main window so set background color to grey
294 0 : glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
295 0 : m_pOGLWindow = new OGLWindow(*m_pHandle, m_aContext, *pChildWindow->GetParent());
296 0 : return uno::Reference< media::XPlayerWindow >( m_pOGLWindow );
297 : }
298 :
299 0 : uno::Reference< media::XFrameGrabber > SAL_CALL OGLPlayer::createFrameGrabber()
300 : throw ( uno::RuntimeException, std::exception )
301 : {
302 0 : osl::MutexGuard aGuard(m_aMutex);
303 : assert(m_pHandle);
304 :
305 0 : if( !m_aContext.init() )
306 : {
307 : SAL_WARN("avmedia.opengl", "Offscreen context initialization failed");
308 0 : return uno::Reference< media::XFrameGrabber >();
309 : }
310 :
311 0 : if( !m_aContext.supportMultiSampling() )
312 : {
313 : SAL_WARN("avmedia.opengl", "Context does not support multisampling!");
314 0 : return uno::Reference< media::XFrameGrabber >();
315 : }
316 :
317 0 : if( !lcl_CheckOpenGLRequirements() )
318 : {
319 : SAL_WARN("avmedia.opengl", "Your platform does not have the minimal OpenGL requiremenets!");
320 0 : return uno::Reference< media::XFrameGrabber >();
321 : }
322 :
323 0 : m_pHandle->viewport.x = 0;
324 0 : m_pHandle->viewport.y = 0;
325 0 : m_pHandle->viewport.width = getPreferredPlayerWindowSize().Width;
326 0 : m_pHandle->viewport.height = getPreferredPlayerWindowSize().Height;
327 :
328 0 : int nRet = gltf_renderer_set_content(m_pHandle, m_vInputFiles);
329 0 : releaseInputFiles();
330 0 : if( nRet != 0 )
331 : {
332 : SAL_WARN("avmedia.opengl", "Error occured while setting up the scene! Error code: " << nRet);
333 0 : return uno::Reference< media::XFrameGrabber >();
334 : }
335 0 : glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
336 0 : OGLFrameGrabber *pFrameGrabber = new OGLFrameGrabber( *m_pHandle );
337 0 : return uno::Reference< media::XFrameGrabber >( pFrameGrabber );
338 : }
339 :
340 0 : OUString SAL_CALL OGLPlayer::getImplementationName()
341 : throw ( ::com::sun::star::uno::RuntimeException, std::exception )
342 : {
343 0 : return OUString("com.sun.star.comp.avmedia.Player_OpenGL");
344 : }
345 :
346 0 : sal_Bool SAL_CALL OGLPlayer::supportsService( const OUString& rServiceName )
347 : throw ( uno::RuntimeException, std::exception )
348 : {
349 0 : return cppu::supportsService(this, rServiceName);
350 : }
351 :
352 0 : uno::Sequence< OUString > SAL_CALL OGLPlayer::getSupportedServiceNames()
353 : throw ( uno::RuntimeException, std::exception )
354 : {
355 0 : uno::Sequence< OUString > aRet(1);
356 0 : aRet[0] = OUString("com.sun.star.media.Player_OpenGL");
357 0 : return aRet;
358 : }
359 :
360 0 : IMPL_LINK(OGLPlayer,TimerHandler,Timer*,pTimer)
361 : {
362 0 : if (pTimer == &m_aTimer)
363 : {
364 0 : osl::MutexGuard aGuard(m_aMutex);
365 : assert(m_pOGLWindow);
366 0 : m_pOGLWindow->update();
367 : }
368 :
369 0 : return 0;
370 : }
371 :
372 : } // namespace ogl
373 0 : } // namespace avmedia
374 :
375 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|