1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include "framegrabber.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
34 avmedia::macavf::MacAVObserverHandler* pHandler = static_cast<avmedia::macavf::MacAVObserverHandler*>(pContext);
35 pHandler->handleObservation( pKeyPath );
38 - (void)onNotification:(NSNotification*)pNotification
40 NSString* pNoteName = (NSString*)[pNotification name];
41 HandlersForObject::iterator it = maHandlersForObject.find( [pNotification object]);
42 if( it != maHandlersForObject.end() )
43 (*it).second->handleObservation( pNoteName );
46 - (void)setHandlerForObject:(NSObject*)pObject handler:(avmedia::macavf::MacAVObserverHandler*)pHandler
48 maHandlersForObject[ pObject] = pHandler;
51 - (void)removeHandlerForObject:(NSObject*)pObject
53 maHandlersForObject.erase( pObject);
59 namespace avmedia { namespace macavf {
61 MacAVObserverObject* MacAVObserverHandler::mpMacAVObserverObject = nullptr;
63 MacAVObserverObject* MacAVObserverHandler::getObserver()
65 if( !mpMacAVObserverObject)
67 mpMacAVObserverObject = [MacAVObserverObject alloc];
68 [mpMacAVObserverObject retain];
70 return mpMacAVObserverObject;
74 Player::Player( const uno::Reference< lang::XMultiServiceFactory >& rxMgr )
77 , mfUnmutedVolume( 0 )
78 , mfStopTime( DBL_MAX )
88 // remove the observers
89 [mpPlayer removeObserver:getObserver() forKeyPath:@"currentItem.status"];
90 AVPlayerItem* pOldPlayerItem = [mpPlayer currentItem];
91 [[NSNotificationCenter defaultCenter] removeObserver:getObserver()
92 name:AVPlayerItemDidPlayToEndTimeNotification
93 object:pOldPlayerItem];
94 [getObserver() removeHandlerForObject:pOldPlayerItem];
95 // release the AVPlayer
96 CFRelease( mpPlayer );
100 bool Player::handleObservation( NSString* pKeyPath )
102 if( [pKeyPath isEqualToString:AVPlayerItemDidPlayToEndTimeNotification])
111 bool Player::create( const ::rtl::OUString& rURL )
113 // get the media asset
114 NSString* aNSStr = [NSString stringWithCharacters:reinterpret_cast<unichar const *>(rURL.getStr()) length:rURL.getLength()];
115 SAL_WNODEPRECATED_DECLARATIONS_PUSH
116 //TODO: 10.11 stringByAddingPercentEscapesUsingEncoding
117 NSURL* aNSURL = [NSURL URLWithString: [aNSStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
118 SAL_WNODEPRECATED_DECLARATIONS_POP
119 // get the matching AVPlayerItem
120 AVPlayerItem* pPlayerItem = [AVPlayerItem playerItemWithURL:aNSURL];
122 // create or update the AVPlayer with the new AVPlayerItem
125 mpPlayer = [AVPlayer playerWithPlayerItem:pPlayerItem];
126 CFRetain( mpPlayer );
127 [mpPlayer setActionAtItemEnd:AVPlayerActionAtItemEndNone];
131 // remove the obsoleted observers
132 AVPlayerItem* pOldPlayerItem = [mpPlayer currentItem];
133 [mpPlayer removeObserver:getObserver() forKeyPath:@"currentItem.status"];
134 [getObserver() removeHandlerForObject:pOldPlayerItem];
135 [[NSNotificationCenter defaultCenter] removeObserver:getObserver()
136 name:AVPlayerItemDidPlayToEndTimeNotification
137 object:pOldPlayerItem];
138 // replace the playeritem
139 [mpPlayer replaceCurrentItemWithPlayerItem:pPlayerItem];
142 // observe the status of the current player item
143 [mpPlayer addObserver:getObserver() forKeyPath:@"currentItem.status" options:0 context:this];
145 // observe playback-end needed for playback looping
146 [[NSNotificationCenter defaultCenter] addObserver:getObserver()
147 selector:@selector(onNotification:)
148 name:AVPlayerItemDidPlayToEndTimeNotification
150 [getObserver() setHandlerForObject:pPlayerItem handler:this];
156 void SAL_CALL Player::start()
162 // else // TODO: delay until it becomes ready
166 void SAL_CALL Player::stop()
170 const bool bPlaying = isPlaying();
176 sal_Bool SAL_CALL Player::isPlaying()
180 const float fRate = [mpPlayer rate];
181 return (fRate != 0.0);
185 double SAL_CALL Player::getDuration()
187 // slideshow checks for non-zero duration, so cheat here
188 double duration = 0.01;
192 AVPlayerItem* pItem = [mpPlayer currentItem];
193 if( [pItem status] == AVPlayerItemStatusReadyToPlay )
194 duration = CMTimeGetSeconds( [pItem duration] );
195 else // fall back to AVAsset's best guess
196 duration = CMTimeGetSeconds( [[pItem asset] duration] );
203 void SAL_CALL Player::setMediaTime( double fTime )
206 [mpPlayer seekToTime: CMTimeMakeWithSeconds(fTime,1000) ];
210 double SAL_CALL Player::getMediaTime()
215 const double position = CMTimeGetSeconds( [mpPlayer currentTime] );
216 if( position >= mfStopTime )
224 void SAL_CALL Player::setStopTime( double fTime )
230 double SAL_CALL Player::getStopTime()
236 void SAL_CALL Player::setPlaybackLoop( sal_Bool bSet )
242 sal_Bool SAL_CALL Player::isPlaybackLoop()
248 void SAL_CALL Player::setMute( sal_Bool bSet )
254 [mpPlayer setMuted:mbMuted];
258 sal_Bool SAL_CALL Player::isMute()
264 void SAL_CALL Player::setVolumeDB( sal_Int16 nVolumeDB )
266 // -40dB <-> AVPlayer volume 0.0
267 // 0dB <-> AVPlayer volume 1.0
268 mfUnmutedVolume = (nVolumeDB <= -40) ? 0.0 : pow( 10.0, nVolumeDB / 20.0 );
271 if( !mbMuted && mpPlayer )
272 [mpPlayer setVolume:mfUnmutedVolume];
276 sal_Int16 SAL_CALL Player::getVolumeDB()
281 // get the actual volume
282 const float fVolume = [mpPlayer volume];
284 // convert into Dezibel value
285 // -40dB <-> AVPlayer volume 0.0
286 // 0dB <-> AVPlayer volume 1.0
287 const int nVolumeDB = (fVolume <= 0) ? -40 : lrint( 20.0*log10(fVolume));
289 return (sal_Int16)nVolumeDB;
293 awt::Size SAL_CALL Player::getPreferredPlayerWindowSize()
295 awt::Size aSize( 0, 0 ); // default size
297 AVAsset* pMovie = [[mpPlayer currentItem] asset];
298 NSArray* pVideoTracks = [pMovie tracksWithMediaType:AVMediaTypeVideo];
299 if ([pVideoTracks count] > 0)
301 AVAssetTrack* pFirstVideoTrack = (AVAssetTrack*) [pVideoTracks objectAtIndex:0];
302 const CGSize aPrefSize = [pFirstVideoTrack naturalSize];
303 aSize = awt::Size( aPrefSize.width, aPrefSize.height );
310 uno::Reference< ::media::XPlayerWindow > SAL_CALL Player::createPlayerWindow( const uno::Sequence< uno::Any >& aArguments )
312 // get the preferred window size
313 const awt::Size aSize( getPreferredPlayerWindowSize() );
315 // get the parent view
316 sal_IntPtr nNSViewPtr = 0;
317 aArguments[0] >>= nNSViewPtr;
318 NSView* pParentView = reinterpret_cast<NSView*>(nNSViewPtr);
320 // check the window parameters
321 uno::Reference< ::media::XPlayerWindow > xRet;
322 if( (aSize.Width <= 0) || (aSize.Height <= 0) || (pParentView == nullptr) )
326 ::avmedia::macavf::Window* pWindow = new ::avmedia::macavf::Window( mxMgr, *this, pParentView );
332 uno::Reference< media::XFrameGrabber > SAL_CALL Player::createFrameGrabber()
334 uno::Reference< media::XFrameGrabber > xRet;
336 FrameGrabber* pGrabber = new FrameGrabber( mxMgr );
337 AVAsset* pMovie = [[mpPlayer currentItem] asset];
338 if( pGrabber->create( pMovie ) )
345 ::rtl::OUString SAL_CALL Player::getImplementationName( )
347 return ::rtl::OUString( AVMEDIA_MACAVF_PLAYER_IMPLEMENTATIONNAME );
351 sal_Bool SAL_CALL Player::supportsService( const ::rtl::OUString& ServiceName )
353 return ServiceName == AVMEDIA_MACAVF_PLAYER_SERVICENAME;
357 uno::Sequence< ::rtl::OUString > SAL_CALL Player::getSupportedServiceNames( )
359 return { AVMEDIA_MACAVF_PLAYER_SERVICENAME };
362 } // namespace macavf
363 } // namespace avmedia
365 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */