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