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 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : // must be first
22 : #include <canvas/debug.hxx>
23 : #include <tools/diagnose_ex.h>
24 : #include <canvas/verbosetrace.hxx>
25 :
26 : #include <math.h>
27 :
28 : #include <comphelper/anytostring.hxx>
29 : #include <cppuhelper/exc_hlp.hxx>
30 :
31 : #include <vcl/canvastools.hxx>
32 : #include <vcl/syschild.hxx>
33 : #include <vcl/window.hxx>
34 :
35 : #include <basegfx/tools/canvastools.hxx>
36 : #include <basegfx/matrix/b2dhommatrixtools.hxx>
37 : #include <basegfx/numeric/ftools.hxx>
38 : #include <basegfx/polygon/b2dpolygon.hxx>
39 : #include <basegfx/point/b2dpoint.hxx>
40 : #include <basegfx/matrix/b2dhommatrix.hxx>
41 : #include <basegfx/polygon/b2dpolygontools.hxx>
42 : #include <basegfx/range/b2irange.hxx>
43 : #include <canvas/canvastools.hxx>
44 : #include <cppcanvas/vclfactory.hxx>
45 : #include <cppcanvas/basegfxfactory.hxx>
46 : #include <avmedia/mediawindow.hxx>
47 :
48 : #include <com/sun/star/media/XManager.hpp>
49 : #include <com/sun/star/media/XPlayer.hpp>
50 : #include <com/sun/star/media/XPlayerWindow.hpp>
51 : #include <com/sun/star/beans/XPropertySet.hpp>
52 : #include <com/sun/star/lang/XMultiComponentFactory.hpp>
53 : #include <com/sun/star/lang/NoSupportException.hpp>
54 : #include <com/sun/star/awt/XWindow.hpp>
55 : #include <com/sun/star/rendering/XCanvas.hpp>
56 : #include <com/sun/star/lang/XComponent.hpp>
57 :
58 : #include "viewmediashape.hxx"
59 : #include "mediashape.hxx"
60 : #include "tools.hxx"
61 : #include "unoview.hxx"
62 :
63 : using namespace ::com::sun::star;
64 :
65 : namespace slideshow
66 : {
67 : namespace internal
68 : {
69 0 : ViewMediaShape::ViewMediaShape( const ViewLayerSharedPtr& rViewLayer,
70 : const uno::Reference< drawing::XShape >& rxShape,
71 : const uno::Reference< uno::XComponentContext >& rxContext ) :
72 : mpViewLayer( rViewLayer ),
73 : mpMediaWindow(),
74 : maWindowOffset( 0, 0 ),
75 : maBounds(),
76 : mxShape( rxShape ),
77 : mxPlayer(),
78 : mxPlayerWindow(),
79 : mxComponentContext( rxContext ),
80 0 : mbIsSoundEnabled(true)
81 : {
82 0 : ENSURE_OR_THROW( mxShape.is(), "ViewMediaShape::ViewMediaShape(): Invalid Shape" );
83 0 : ENSURE_OR_THROW( mpViewLayer, "ViewMediaShape::ViewMediaShape(): Invalid View" );
84 0 : ENSURE_OR_THROW( mpViewLayer->getCanvas(), "ViewMediaShape::ViewMediaShape(): Invalid ViewLayer canvas" );
85 0 : ENSURE_OR_THROW( mxComponentContext.is(), "ViewMediaShape::ViewMediaShape(): Invalid component context" );
86 :
87 0 : UnoViewSharedPtr pUnoView (::boost::dynamic_pointer_cast<UnoView>(rViewLayer));
88 0 : if (pUnoView)
89 : {
90 0 : mbIsSoundEnabled = pUnoView->isSoundEnabled();
91 0 : }
92 0 : }
93 :
94 :
95 :
96 0 : ViewMediaShape::~ViewMediaShape()
97 : {
98 : try
99 : {
100 0 : endMedia();
101 : }
102 0 : catch (uno::Exception &)
103 : {
104 : OSL_FAIL( OUStringToOString(
105 : comphelper::anyToString(
106 : cppu::getCaughtException() ),
107 : RTL_TEXTENCODING_UTF8 ).getStr() );
108 : }
109 0 : }
110 :
111 :
112 :
113 0 : ViewLayerSharedPtr ViewMediaShape::getViewLayer() const
114 : {
115 0 : return mpViewLayer;
116 : }
117 :
118 :
119 :
120 0 : bool ViewMediaShape::startMedia()
121 : {
122 0 : if( !mxPlayer.is() )
123 0 : implInitialize( maBounds );
124 :
125 0 : if( mxPlayer.is() && ( mxPlayer->getDuration() > 0.0 ) )
126 0 : mxPlayer->start();
127 :
128 0 : return true;
129 : }
130 :
131 :
132 :
133 0 : void ViewMediaShape::endMedia()
134 : {
135 : // shutdown player window
136 0 : if( mxPlayerWindow.is() )
137 : {
138 0 : uno::Reference< lang::XComponent > xComponent( mxPlayerWindow, uno::UNO_QUERY );
139 :
140 0 : if( xComponent.is() )
141 0 : xComponent->dispose();
142 :
143 0 : mxPlayerWindow.clear();
144 : }
145 :
146 0 : mpMediaWindow.reset();
147 :
148 : // shutdown player
149 0 : if( mxPlayer.is() )
150 : {
151 0 : mxPlayer->stop();
152 :
153 0 : uno::Reference< lang::XComponent > xComponent( mxPlayer, uno::UNO_QUERY );
154 :
155 0 : if( xComponent.is() )
156 0 : xComponent->dispose();
157 :
158 0 : mxPlayer.clear();
159 : }
160 0 : }
161 :
162 :
163 :
164 0 : void ViewMediaShape::pauseMedia()
165 : {
166 0 : if( mxPlayer.is() && ( mxPlayer->getDuration() > 0.0 ) )
167 0 : mxPlayer->stop();
168 0 : }
169 :
170 :
171 :
172 0 : void ViewMediaShape::setMediaTime(double fTime)
173 : {
174 0 : if( mxPlayer.is() && ( mxPlayer->getDuration() > 0.0 ) )
175 0 : mxPlayer->setMediaTime(fTime);
176 0 : }
177 :
178 :
179 :
180 0 : bool ViewMediaShape::render( const ::basegfx::B2DRectangle& rBounds ) const
181 : {
182 0 : ::cppcanvas::CanvasSharedPtr pCanvas = mpViewLayer->getCanvas();
183 :
184 0 : if( !pCanvas )
185 0 : return false;
186 :
187 0 : if( !mpMediaWindow.get() && !mxPlayerWindow.is() )
188 : {
189 : // draw placeholder for no-video (no window) case
190 : // no window and player == audio icon
191 : // no window and no player == broken icon
192 0 : BitmapEx aAudioLogo(mxPlayer.is() ?
193 0 : avmedia::MediaWindow::getAudioLogo() : avmedia::MediaWindow::getEmptyLogo() );
194 :
195 : uno::Reference< rendering::XBitmap > xBitmap(vcl::unotools::xBitmapFromBitmapEx(
196 0 : pCanvas->getUNOCanvas()->getDevice(), aAudioLogo));
197 :
198 0 : rendering::ViewState aViewState;
199 0 : aViewState.AffineTransform = pCanvas->getViewState().AffineTransform;
200 :
201 0 : rendering::RenderState aRenderState;
202 0 : ::canvas::tools::initRenderState( aRenderState );
203 :
204 0 : const ::Size aBmpSize( aAudioLogo.GetSizePixel() );
205 :
206 0 : const ::basegfx::B2DVector aScale( rBounds.getWidth() / aBmpSize.Width(),
207 0 : rBounds.getHeight() / aBmpSize.Height() );
208 : const basegfx::B2DHomMatrix aTranslation(basegfx::tools::createScaleTranslateB2DHomMatrix(
209 0 : aScale, rBounds.getMinimum()));
210 0 : ::canvas::tools::setRenderStateTransform( aRenderState, aTranslation );
211 :
212 0 : pCanvas->getUNOCanvas()->drawBitmap( xBitmap,
213 : aViewState,
214 0 : aRenderState );
215 : }
216 :
217 0 : return true;
218 : }
219 :
220 0 : bool ViewMediaShape::resize( const ::basegfx::B2DRectangle& rNewBounds ) const
221 : {
222 0 : maBounds = rNewBounds;
223 :
224 0 : ::cppcanvas::CanvasSharedPtr pCanvas = mpViewLayer->getCanvas();
225 :
226 0 : if( !pCanvas )
227 0 : return false;
228 :
229 0 : if( !mxPlayerWindow.is() )
230 0 : return true;
231 :
232 0 : uno::Reference< beans::XPropertySet > xPropSet( pCanvas->getUNOCanvas()->getDevice(),
233 0 : uno::UNO_QUERY );
234 :
235 0 : uno::Reference< awt::XWindow > xParentWindow;
236 0 : if( xPropSet.is() &&
237 : getPropertyValue( xParentWindow,
238 : xPropSet,
239 0 : OUString("Window" )) )
240 : {
241 0 : const awt::Rectangle aRect( xParentWindow->getPosSize() );
242 :
243 0 : maWindowOffset.X = aRect.X;
244 0 : maWindowOffset.Y = aRect.Y;
245 : }
246 :
247 0 : ::basegfx::B2DRange aTmpRange;
248 : ::canvas::tools::calcTransformedRectBounds( aTmpRange,
249 : rNewBounds,
250 0 : mpViewLayer->getTransformation() );
251 : const ::basegfx::B2IRange& rRangePix(
252 0 : ::basegfx::unotools::b2ISurroundingRangeFromB2DRange( aTmpRange ));
253 :
254 0 : mxPlayerWindow->setEnable( !rRangePix.isEmpty() );
255 :
256 0 : if( rRangePix.isEmpty() )
257 0 : return true;
258 :
259 0 : const Point aPosPixel( rRangePix.getMinX() + maWindowOffset.X,
260 0 : rRangePix.getMinY() + maWindowOffset.Y );
261 0 : const Size aSizePixel( rRangePix.getMaxX() - rRangePix.getMinX(),
262 0 : rRangePix.getMaxY() - rRangePix.getMinY() );
263 :
264 0 : if( mpMediaWindow.get() )
265 : {
266 0 : mpMediaWindow->SetPosSizePixel( aPosPixel, aSizePixel );
267 0 : mxPlayerWindow->setPosSize( 0, 0,
268 : aSizePixel.Width(), aSizePixel.Height(),
269 0 : 0 );
270 : }
271 : else
272 : {
273 0 : mxPlayerWindow->setPosSize( aPosPixel.X(), aPosPixel.Y(),
274 : aSizePixel.Width(), aSizePixel.Height(),
275 0 : 0 );
276 : }
277 :
278 0 : return true;
279 : }
280 :
281 :
282 :
283 0 : bool ViewMediaShape::implInitialize( const ::basegfx::B2DRectangle& rBounds )
284 : {
285 0 : if( !mxPlayer.is() && mxShape.is() )
286 : {
287 0 : ENSURE_OR_RETURN_FALSE( mpViewLayer->getCanvas(),
288 : "ViewMediaShape::update(): Invalid layer canvas" );
289 :
290 0 : uno::Reference< rendering::XCanvas > xCanvas( mpViewLayer->getCanvas()->getUNOCanvas() );
291 :
292 0 : if( xCanvas.is() )
293 : {
294 0 : uno::Reference< beans::XPropertySet > xPropSet;
295 0 : OUString aURL;
296 :
297 : try
298 : {
299 0 : xPropSet.set( mxShape, uno::UNO_QUERY );
300 :
301 : // create Player
302 0 : if (xPropSet.is())
303 : {
304 0 : if ((xPropSet->getPropertyValue(
305 0 : OUString( "PrivateTempFileURL")) >>= aURL)
306 0 : && !aURL.isEmpty())
307 : {
308 0 : implInitializeMediaPlayer( aURL );
309 : }
310 0 : else if (xPropSet->getPropertyValue(
311 0 : OUString( "MediaURL")) >>= aURL)
312 : {
313 0 : implInitializeMediaPlayer( aURL );
314 : }
315 : }
316 :
317 : // create visible object
318 0 : uno::Sequence< uno::Any > aDeviceParams;
319 :
320 0 : if( ::canvas::tools::getDeviceInfo( xCanvas, aDeviceParams ).getLength() > 1 )
321 : {
322 0 : OUString aImplName;
323 :
324 0 : aDeviceParams[ 0 ] >>= aImplName;
325 :
326 0 : if( aImplName.endsWithIgnoreAsciiCase( "VCL" ) ||
327 0 : aImplName.endsWithIgnoreAsciiCase( "Cairo" ) )
328 : {
329 0 : implInitializeVCLBasedPlayerWindow( rBounds, aDeviceParams );
330 : }
331 0 : else if( aImplName.endsWithIgnoreAsciiCase("DX") ||
332 0 : aImplName.endsWithIgnoreAsciiCase("DX9") )
333 : {
334 0 : implInitializeDXBasedPlayerWindow( rBounds, aDeviceParams );
335 0 : }
336 : }
337 :
338 : // set player properties
339 0 : implSetMediaProperties( xPropSet );
340 : }
341 0 : catch( uno::RuntimeException& )
342 : {
343 0 : throw;
344 : }
345 0 : catch( uno::Exception& )
346 : {
347 : OSL_FAIL( OUStringToOString(
348 : comphelper::anyToString( cppu::getCaughtException() ),
349 : RTL_TEXTENCODING_UTF8 ).getStr() );
350 0 : }
351 0 : }
352 : }
353 :
354 0 : return mxPlayer.is() || mxPlayerWindow.is();
355 : }
356 :
357 :
358 :
359 0 : void ViewMediaShape::implSetMediaProperties( const uno::Reference< beans::XPropertySet >& rxProps )
360 : {
361 0 : if( mxPlayer.is() )
362 : {
363 0 : mxPlayer->setMediaTime( 0.0 );
364 :
365 0 : if( rxProps.is() )
366 : {
367 0 : sal_Bool bLoop( false );
368 : getPropertyValue( bLoop,
369 : rxProps,
370 0 : OUString( "Loop" ));
371 0 : mxPlayer->setPlaybackLoop( bLoop );
372 :
373 0 : sal_Bool bMute( false );
374 : getPropertyValue( bMute,
375 : rxProps,
376 0 : OUString( "Mute" ));
377 0 : mxPlayer->setMute( bMute || !mbIsSoundEnabled);
378 :
379 0 : sal_Int16 nVolumeDB(0);
380 : getPropertyValue( nVolumeDB,
381 : rxProps,
382 0 : OUString( "VolumeDB" ));
383 0 : mxPlayer->setVolumeDB( nVolumeDB );
384 :
385 0 : if( mxPlayerWindow.is() )
386 : {
387 0 : media::ZoomLevel eZoom(media::ZoomLevel_FIT_TO_WINDOW);
388 : getPropertyValue( eZoom,
389 : rxProps,
390 0 : OUString( "Zoom" ));
391 0 : mxPlayerWindow->setZoomLevel( eZoom );
392 : }
393 : }
394 : }
395 0 : }
396 :
397 :
398 :
399 0 : void ViewMediaShape::implInitializeMediaPlayer( const OUString& rMediaURL )
400 : {
401 0 : if( !mxPlayer.is() )
402 : {
403 : try
404 : {
405 0 : if( !rMediaURL.isEmpty() )
406 : {
407 : mxPlayer.set( avmedia::MediaWindow::createPlayer( rMediaURL, ""/*TODO!*/ ),
408 0 : uno::UNO_QUERY );
409 : }
410 : }
411 0 : catch( uno::RuntimeException& )
412 : {
413 0 : throw;
414 : }
415 0 : catch( const uno::Exception& )
416 : {
417 : throw lang::NoSupportException(
418 0 : OUString( "No video support for " ) + rMediaURL,
419 0 : uno::Reference<uno::XInterface>() );
420 : }
421 : }
422 0 : }
423 :
424 :
425 :
426 0 : bool ViewMediaShape::implInitializeVCLBasedPlayerWindow( const ::basegfx::B2DRectangle& rBounds,
427 : const uno::Sequence< uno::Any >& rVCLDeviceParams)
428 : {
429 : OSL_TRACE( "ViewMediaShape::implInitializeVCLBasedPlayerWindow" );
430 0 : if( !mpMediaWindow.get() && !rBounds.isEmpty() )
431 : {
432 : try
433 : {
434 0 : sal_Int64 aVal=0;
435 :
436 0 : rVCLDeviceParams[ 1 ] >>= aVal;
437 :
438 0 : Window* pWindow = reinterpret_cast< Window* >( aVal );
439 :
440 0 : if( pWindow )
441 : {
442 0 : ::basegfx::B2DRange aTmpRange;
443 : ::canvas::tools::calcTransformedRectBounds( aTmpRange,
444 : rBounds,
445 0 : mpViewLayer->getTransformation() );
446 : const ::basegfx::B2IRange& rRangePix(
447 0 : ::basegfx::unotools::b2ISurroundingRangeFromB2DRange( aTmpRange ));
448 :
449 0 : if( !rRangePix.isEmpty() )
450 : {
451 0 : uno::Sequence< uno::Any > aArgs( 3 );
452 0 : awt::Rectangle aAWTRect( rRangePix.getMinX(),
453 0 : rRangePix.getMinY(),
454 0 : rRangePix.getMaxX() - rRangePix.getMinX(),
455 0 : rRangePix.getMaxY() - rRangePix.getMinY() );
456 :
457 : mpMediaWindow.reset( new
458 0 : SystemChildWindow( pWindow, WB_CLIPCHILDREN ) );
459 0 : mpMediaWindow->SetBackground( Color( COL_BLACK ) );
460 0 : mpMediaWindow->SetPosSizePixel( Point( aAWTRect.X, aAWTRect.Y ),
461 0 : Size( aAWTRect.Width, aAWTRect.Height ) );
462 0 : mpMediaWindow->SetParentClipMode( PARENTCLIPMODE_NOCLIP );
463 0 : mpMediaWindow->EnableEraseBackground( false );
464 0 : mpMediaWindow->EnablePaint( false );
465 0 : mpMediaWindow->SetForwardKey( true );
466 0 : mpMediaWindow->SetMouseTransparent( true );
467 0 : mpMediaWindow->Show();
468 :
469 0 : if( mxPlayer.is() )
470 : {
471 0 : aArgs[ 0 ] = uno::makeAny(
472 0 : sal::static_int_cast< sal_IntPtr >( mpMediaWindow->GetParentWindowHandle() ) );
473 :
474 0 : aAWTRect.X = aAWTRect.Y = 0;
475 0 : aArgs[ 1 ] = uno::makeAny( aAWTRect );
476 :
477 0 : aArgs[ 2 ] = uno::makeAny( reinterpret_cast< sal_IntPtr >( mpMediaWindow.get() ) );
478 :
479 0 : mxPlayerWindow.set( mxPlayer->createPlayerWindow( aArgs ) );
480 :
481 0 : if( mxPlayerWindow.is() )
482 : {
483 0 : mxPlayerWindow->setVisible( true );
484 0 : mxPlayerWindow->setEnable( true );
485 : }
486 : }
487 :
488 0 : if( !mxPlayerWindow.is() )
489 : {
490 : //if there was no playerwindow, then clear the mpMediaWindow too
491 : //so that we can draw a placeholder instead in that space
492 0 : mpMediaWindow.reset();
493 0 : }
494 : }
495 : }
496 : }
497 0 : catch( uno::RuntimeException& )
498 : {
499 0 : throw;
500 : }
501 0 : catch( uno::Exception& )
502 : {
503 : OSL_FAIL( OUStringToOString(
504 : comphelper::anyToString( cppu::getCaughtException() ),
505 : RTL_TEXTENCODING_UTF8 ).getStr() );
506 : }
507 : }
508 :
509 0 : return mxPlayerWindow.is();
510 : }
511 :
512 :
513 :
514 0 : bool ViewMediaShape::implInitializeDXBasedPlayerWindow( const ::basegfx::B2DRectangle& rBounds,
515 : const uno::Sequence< uno::Any >& rDXDeviceParams )
516 : {
517 0 : if( !mxPlayerWindow.is() )
518 : {
519 : try
520 : {
521 0 : if( rDXDeviceParams.getLength() == 2 )
522 : {
523 0 : sal_Int64 aWNDVal=0;
524 :
525 0 : rDXDeviceParams[ 1 ] >>= aWNDVal;
526 :
527 0 : if( aWNDVal )
528 : {
529 0 : ::basegfx::B2DRange aTmpRange;
530 : ::canvas::tools::calcTransformedRectBounds( aTmpRange,
531 : rBounds,
532 0 : mpViewLayer->getTransformation() );
533 : const ::basegfx::B2IRange& rRangePix(
534 0 : ::basegfx::unotools::b2ISurroundingRangeFromB2DRange( aTmpRange ));
535 :
536 0 : if( !rRangePix.isEmpty() )
537 : {
538 0 : uno::Sequence< uno::Any > aArgs( 2 );
539 0 : awt::Rectangle aAWTRect( rRangePix.getMinX() + maWindowOffset.X,
540 0 : rRangePix.getMinY() + maWindowOffset.Y,
541 0 : rRangePix.getMaxX() - rRangePix.getMinX(),
542 0 : rRangePix.getMaxY() - rRangePix.getMinY() );
543 :
544 0 : if( mxPlayer.is() )
545 : {
546 0 : aArgs[ 0 ] = uno::makeAny( sal::static_int_cast< sal_Int32 >( aWNDVal) );
547 0 : aArgs[ 1 ] = uno::makeAny( aAWTRect );
548 :
549 0 : mxPlayerWindow.set( mxPlayer->createPlayerWindow( aArgs ) );
550 0 : }
551 : }
552 : }
553 : }
554 : }
555 0 : catch( uno::RuntimeException& )
556 : {
557 0 : throw;
558 : }
559 0 : catch( uno::Exception& )
560 : {
561 : OSL_FAIL( OUStringToOString(
562 : comphelper::anyToString( cppu::getCaughtException() ),
563 : RTL_TEXTENCODING_UTF8 ).getStr() );
564 : }
565 : }
566 :
567 0 : return mxPlayerWindow.is();
568 : }
569 : }
570 : }
571 :
572 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|