fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / avmedia / source / macavf / player.mm
blob257576db2151a3d34de77aa88c40617f375b16cd
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  */
20 #include "player.hxx"
21 #include "framegrabber.hxx"
22 #include "window.hxx"
24 #include <cmath> // for log10()
26 using namespace ::com::sun::star;
28 @implementation MacAVObserverObject
30 - (void)observeValueForKeyPath:(NSString*)pKeyPath ofObject:(id)pObject change:(NSDictionary*)pChangeDict context:(void*)pContext
32     (void) pObject;
33     NSString* pDictStr = [NSString stringWithFormat:@"%@", pChangeDict];
34     OSL_TRACE( "MacAVObserver::onKeyChange k=\"%s\" c=%s", [pKeyPath UTF8String], [pDictStr UTF8String]);
35     avmedia::macavf::MacAVObserverHandler* pHandler = static_cast<avmedia::macavf::MacAVObserverHandler*>(pContext);
36     pHandler->handleObservation( pKeyPath );
39 - (void)onNotification:(NSNotification*)pNotification
41     NSString* pNoteName = (NSString*)[pNotification name];
42     OSL_TRACE( "MacAVObserver::onNotification key=\"%s\"", [pNoteName UTF8String]);
43     HandlersForObject::iterator it = maHandlersForObject.find( [pNotification object]);
44     if( it != maHandlersForObject.end() )
45         (*it).second->handleObservation( pNoteName );
48 - (void)setHandlerForObject:(NSObject*)pObject handler:(avmedia::macavf::MacAVObserverHandler*)pHandler
50     maHandlersForObject[ pObject] = pHandler;
53 - (void)removeHandlerForObject:(NSObject*)pObject
55     maHandlersForObject.erase( pObject);
58 @end
61 namespace avmedia { namespace macavf {
63 MacAVObserverObject* MacAVObserverHandler::mpMacAVObserverObject = NULL;
65 MacAVObserverObject* MacAVObserverHandler::getObserver()
67     if( !mpMacAVObserverObject)
68     {
69         mpMacAVObserverObject = [MacAVObserverObject alloc];
70         [mpMacAVObserverObject retain];
71     }
72     return mpMacAVObserverObject;
76 // ----------------
77 // - Player -
78 // ----------------
80 Player::Player( const uno::Reference< lang::XMultiServiceFactory >& rxMgr )
81 :   mxMgr( rxMgr )
82 ,   mpPlayer( NULL )
83 ,   mfUnmutedVolume( 0 )
84 ,   mfStopTime( DBL_MAX )
85 ,   mbMuted( false )
86 ,   mbLooping( false )
89 // ------------------------------------------------------------------------------
91 Player::~Player()
93     if( !mpPlayer )
94         return;
95     // remove the observers
96     [mpPlayer removeObserver:getObserver() forKeyPath:@"currentItem.status"];
97     AVPlayerItem* pOldPlayerItem = [mpPlayer currentItem];
98     [[NSNotificationCenter defaultCenter] removeObserver:getObserver()
99         name:AVPlayerItemDidPlayToEndTimeNotification
100         object:pOldPlayerItem];
101     [getObserver() removeHandlerForObject:pOldPlayerItem];
102     // release the AVPlayer
103     CFRelease( mpPlayer );
106 // ------------------------------------------------------------------------------
108 bool Player::handleObservation( NSString* pKeyPath )
110     OSL_TRACE( "AVPlayer::handleObservation key=\"%s\"", [pKeyPath UTF8String]);
111     if( [pKeyPath isEqualToString:AVPlayerItemDidPlayToEndTimeNotification])
112     {
113         OSL_TRACE( "AVPlayer replay=%d", mbLooping);
114         if( mbLooping )
115             setMediaTime( 0.0);
116     }
117     return true;
120 // ------------------------------------------------------------------------------
122 bool Player::create( const ::rtl::OUString& rURL )
124     // get the media asset
125     NSString* aNSStr = [NSString stringWithCharacters:rURL.getStr() length:rURL.getLength()];
126     NSURL* aNSURL = [NSURL URLWithString: [aNSStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
127     // get the matching AVPlayerItem
128     AVPlayerItem* pPlayerItem = [AVPlayerItem playerItemWithURL:aNSURL];
130     // create or update the AVPlayer with the new AVPlayerItem
131     if( !mpPlayer )
132     {
133         mpPlayer = [AVPlayer playerWithPlayerItem:pPlayerItem];
134         CFRetain( mpPlayer );
135         [mpPlayer setActionAtItemEnd:AVPlayerActionAtItemEndNone];
136     }
137     else
138     {
139         // remove the obsoleted observers
140         AVPlayerItem* pOldPlayerItem = [mpPlayer currentItem];
141         [mpPlayer removeObserver:getObserver() forKeyPath:@"currentItem.status"];
142         [getObserver() removeHandlerForObject:pOldPlayerItem];
143         [[NSNotificationCenter defaultCenter] removeObserver:getObserver()
144             name:AVPlayerItemDidPlayToEndTimeNotification
145             object:pOldPlayerItem];
146         // replace the playeritem
147         [mpPlayer replaceCurrentItemWithPlayerItem:pPlayerItem];
148     }
150     // observe the status of the current player item
151     [mpPlayer addObserver:getObserver() forKeyPath:@"currentItem.status" options:0 context:this];
153     // observe playback-end needed for playback looping
154     [[NSNotificationCenter defaultCenter] addObserver:getObserver()
155         selector:@selector(onNotification:)
156         name:AVPlayerItemDidPlayToEndTimeNotification
157         object:pPlayerItem];
158     [getObserver() setHandlerForObject:pPlayerItem handler:this];
160     return true;
163 // ------------------------------------------------------------------------------
165 void SAL_CALL Player::start()
166     throw (uno::RuntimeException)
168     if( !mpPlayer )
169         return;
170 #if 0
171     const AVPlayerStatus eStatus = [mpPlayer status];
172     OSL_TRACE ("Player::start status=%d", (int)eStatus);
173     if( eStatus == AVPlayerStatusReadyToPlay)
174 #endif
175     {
176         [mpPlayer play];
177     }
178     // else // TODO: delay until it becomes ready
181 // ------------------------------------------------------------------------------
183 void SAL_CALL Player::stop()
184     throw (uno::RuntimeException)
186     if( !mpPlayer )
187         return;
188     const bool bPlaying = isPlaying();
189     OSL_TRACE ("Player::stop() playing=%d", bPlaying);
190     if( bPlaying )
191         [mpPlayer pause];
194 // ------------------------------------------------------------------------------
196 sal_Bool SAL_CALL Player::isPlaying()
197     throw (uno::RuntimeException)
199     if( !mpPlayer )
200         return false;
201     const float fRate = [mpPlayer rate];
202     return (fRate != 0.0);
205 // ------------------------------------------------------------------------------
207 double SAL_CALL Player::getDuration()
208     throw (uno::RuntimeException)
210     // slideshow checks for non-zero duration, so cheat here
211     double duration = 0.01;
213     if( mpPlayer )
214     {
215         AVPlayerItem* pItem = [mpPlayer currentItem];
216         if( [pItem status] == AVPlayerItemStatusReadyToPlay )
217             duration = CMTimeGetSeconds( [pItem duration] );
218         else // fall back to AVAsset's best guess
219             duration = CMTimeGetSeconds( [[pItem asset] duration] );
220     }
222     return duration;
225 // ------------------------------------------------------------------------------
227 void SAL_CALL Player::setMediaTime( double fTime )
228     throw (uno::RuntimeException)
230     OSL_TRACE ("Player::setMediaTime( %.3fsec)", fTime);
231     if( mpPlayer )
232         [mpPlayer seekToTime: CMTimeMakeWithSeconds(fTime,1000) ];
235 // ------------------------------------------------------------------------------
237 double SAL_CALL Player::getMediaTime()
238     throw (uno::RuntimeException)
240     if( !mpPlayer )
241         return 0.0;
243     const double position = CMTimeGetSeconds( [mpPlayer currentTime] );
244     OSL_TRACE( "Player::getMediaTime() = %.3fsec", position);
245     if( position >= mfStopTime )
246         if( isPlaying() )
247             stop();
249     return position;
252 // ------------------------------------------------------------------------------
254 void SAL_CALL Player::setStopTime( double fTime )
255     throw (uno::RuntimeException)
257     OSL_TRACE ("Player::setStopTime( %.3fsec)", fTime);
258     mfStopTime = fTime;
261 // ------------------------------------------------------------------------------
263 double SAL_CALL Player::getStopTime()
264     throw (uno::RuntimeException)
266     return mfStopTime;
269 // ------------------------------------------------------------------------------
271 void SAL_CALL Player::setPlaybackLoop( sal_Bool bSet )
272     throw (uno::RuntimeException)
274     OSL_TRACE ("Player::setPlaybackLoop( %d)", bSet );
275     mbLooping = bSet;
278 // ------------------------------------------------------------------------------
280 sal_Bool SAL_CALL Player::isPlaybackLoop()
281     throw (uno::RuntimeException)
283     const bool bRet = mbLooping;
284     OSL_TRACE ("Player::isPlaybackLoop() = %d", bRet );
285     return bRet;
288 // ------------------------------------------------------------------------------
290 void SAL_CALL Player::setMute( sal_Bool bSet )
291     throw (uno::RuntimeException)
293     OSL_TRACE( "Player::setMute(%d), was-muted: %d unmuted-volume: %.3f", bSet, mbMuted, mfUnmutedVolume );
295     if( !mpPlayer )
296         return;
298     mbMuted = bSet;
299     [mpPlayer setMuted:mbMuted];
302 // ------------------------------------------------------------------------------
304 sal_Bool SAL_CALL Player::isMute()
305     throw (uno::RuntimeException)
307     OSL_TRACE ("Player::isMuted() = %d", mbMuted);
308     return mbMuted;
311 // ------------------------------------------------------------------------------
313 void SAL_CALL Player::setVolumeDB( sal_Int16 nVolumeDB )
314     throw (uno::RuntimeException)
316     // -40dB <-> AVPlayer volume 0.0
317     //   0dB <-> AVPlayer volume 1.0
318     mfUnmutedVolume = (nVolumeDB <= -40) ? 0.0 : pow( 10.0, nVolumeDB / 20.0 );
319     OSL_TRACE( "Player::setVolume(%ddB), muted=%d, unmuted-volume: %.3f", nVolumeDB, mbMuted, mfUnmutedVolume );
321     // change volume
322     if( !mbMuted && mpPlayer )
323         [mpPlayer setVolume:mfUnmutedVolume];
326 // ------------------------------------------------------------------------------
328 sal_Int16 SAL_CALL Player::getVolumeDB()
329     throw (uno::RuntimeException)
331     if( !mpPlayer )
332         return 0;
334     // get the actual volume
335     const float fVolume = [mpPlayer volume];
337     // convert into Dezibel value
338     // -40dB <-> AVPlayer volume 0.0
339     //   0dB <-> AVPlayer volume 1.0
340     const int nVolumeDB = (fVolume <= 0) ? -40 : lrint( 20.0*log10(fVolume));
342     return (sal_Int16)nVolumeDB;
345 // ------------------------------------------------------------------------------
347 awt::Size SAL_CALL Player::getPreferredPlayerWindowSize()
348     throw (uno::RuntimeException)
350     awt::Size aSize( 0, 0 ); // default size
352     AVAsset* pMovie = [[mpPlayer currentItem] asset];
353     NSArray* pVideoTracks = [pMovie tracksWithMediaType:AVMediaTypeVideo];
354     if ([pVideoTracks count] > 0)
355     {
356         AVAssetTrack* pFirstVideoTrack = (AVAssetTrack*) [pVideoTracks objectAtIndex:0];
357         const CGSize aPrefSize = [pFirstVideoTrack naturalSize];
358         aSize = awt::Size( aPrefSize.width, aPrefSize.height );
359     }
361     return aSize;
364 // ------------------------------------------------------------------------------
366 uno::Reference< ::media::XPlayerWindow > SAL_CALL Player::createPlayerWindow( const uno::Sequence< uno::Any >& aArguments )
367     throw (uno::RuntimeException)
369     // get the preferred window size
370     const awt::Size aSize( getPreferredPlayerWindowSize() );
371     OSL_TRACE( "Player::createPlayerWindow %dx%d argsLength: %d", aSize.Width, aSize.Height, aArguments.getLength() );
373     // get the parent view
374     sal_IntPtr nNSViewPtr = 0;
375     aArguments[0] >>= nNSViewPtr;
376     NSView* pParentView = reinterpret_cast<NSView*>(nNSViewPtr);
378     // check the window parameters
379     uno::Reference< ::media::XPlayerWindow > xRet;
380     if( (aSize.Width <= 0) || (aSize.Height <= 0) || (pParentView == NULL) )
381          return xRet;
383     // create the window
384     ::avmedia::macavf::Window* pWindow = new ::avmedia::macavf::Window( mxMgr, *this, pParentView );
385     xRet = pWindow;
386     return xRet;
389 // ------------------------------------------------------------------------------
391 uno::Reference< media::XFrameGrabber > SAL_CALL Player::createFrameGrabber()
392     throw (uno::RuntimeException)
394     uno::Reference< media::XFrameGrabber > xRet;
395     OSL_TRACE ("Player::createFrameGrabber");
397     FrameGrabber* pGrabber = new FrameGrabber( mxMgr );
398     AVAsset* pMovie = [[mpPlayer currentItem] asset];
399     if( pGrabber->create( pMovie ) )
400         xRet = pGrabber;
402     return xRet;
405 // ------------------------------------------------------------------------------
407 ::rtl::OUString SAL_CALL Player::getImplementationName(  )
408     throw (uno::RuntimeException)
410     return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( AVMEDIA_MACAVF_PLAYER_IMPLEMENTATIONNAME ) );
413 // ------------------------------------------------------------------------------
415 sal_Bool SAL_CALL Player::supportsService( const ::rtl::OUString& ServiceName )
416     throw (uno::RuntimeException)
418     return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( AVMEDIA_MACAVF_PLAYER_SERVICENAME ) );
421 // ------------------------------------------------------------------------------
423 uno::Sequence< ::rtl::OUString > SAL_CALL Player::getSupportedServiceNames(  )
424     throw (uno::RuntimeException)
426     uno::Sequence< ::rtl::OUString > aRet(1);
427     aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( AVMEDIA_MACAVF_PLAYER_SERVICENAME ) );
429     return aRet;
432 } // namespace macavf
433 } // namespace avmedia
435 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */