summaryrefslogtreecommitdiff
path: root/avmedia/source/macavf/macavf_player.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'avmedia/source/macavf/macavf_player.cxx')
-rw-r--r--avmedia/source/macavf/macavf_player.cxx463
1 files changed, 463 insertions, 0 deletions
diff --git a/avmedia/source/macavf/macavf_player.cxx b/avmedia/source/macavf/macavf_player.cxx
new file mode 100644
index 000000000000..3a1882a095b3
--- /dev/null
+++ b/avmedia/source/macavf/macavf_player.cxx
@@ -0,0 +1,463 @@
+/**************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *************************************************************/
+
+
+#include "macavf_player.hxx"
+#include "macavf_framegrabber.hxx"
+#include "macavf_window.hxx"
+
+#include <cmath> // for log10()
+
+using namespace ::com::sun::star;
+
+#include <hash_map>
+typedef std::hash_map<NSObject*,avmedia::macavf::MacAVObserverHandler*> HandlersForObject;
+
+@implementation MacAVObserverObject
+{
+ HandlersForObject maHandlersForObject;
+}
+- (void)observeValueForKeyPath:(NSString*)pKeyPath ofObject:(id)pObject change:(NSDictionary*)pChangeDict context:(void*)pContext
+{
+ NSString* pDictStr = [NSString stringWithFormat:@"%@", pChangeDict];
+ OSL_TRACE( "MacAVObserver::onKeyChange k=\"%s\" c=%s", [pKeyPath UTF8String], [pDictStr UTF8String]);
+ avmedia::macavf::MacAVObserverHandler* pHandler = (avmedia::macavf::MacAVObserverHandler*)pContext;
+ pHandler->handleObservation( pKeyPath );
+}
+
+- (void)onNotification:(NSNotification*)pNotification
+{
+ NSString* pNoteName = (NSString*)[pNotification name];
+ OSL_TRACE( "MacAVObserver::onNotification key=\"%s\"", [pNoteName UTF8String]);
+ HandlersForObject::iterator it = maHandlersForObject.find( [pNotification object]);
+ if( it != maHandlersForObject.end() )
+ (*it).second->handleObservation( pNoteName );
+}
+
+- (void)setHandlerForObject:(NSObject*)pObject handler:(avmedia::macavf::MacAVObserverHandler*)pHandler
+{
+ maHandlersForObject[ pObject] = pHandler;
+}
+
+- (void)removeHandlerForObject:(NSObject*)pObject
+{
+ maHandlersForObject.erase( pObject);
+}
+
+@end
+
+
+namespace avmedia { namespace macavf {
+
+MacAVObserverObject* MacAVObserverHandler::mpMacAVObserverObject = NULL;
+
+MacAVObserverObject* MacAVObserverHandler::getObserver() const
+{
+ if( !mpMacAVObserverObject)
+ {
+ mpMacAVObserverObject = [MacAVObserverObject alloc];
+ [mpMacAVObserverObject retain];
+ }
+ return mpMacAVObserverObject;
+}
+
+
+// ----------------
+// - Player -
+// ----------------
+
+Player::Player( const uno::Reference< lang::XMultiServiceFactory >& rxMgr )
+: mxMgr( rxMgr )
+, mpPlayer( NULL )
+, mfUnmutedVolume( 0 )
+, mfStopTime( DBL_MAX )
+, mbMuted( false )
+, mbLooping( false )
+{}
+
+// ------------------------------------------------------------------------------
+
+Player::~Player()
+{
+ if( !mpPlayer )
+ return;
+ // remove the observers
+ [mpPlayer removeObserver:getObserver() forKeyPath:@"currentItem.status"];
+ AVPlayerItem* pOldPlayerItem = [mpPlayer currentItem];
+ [[NSNotificationCenter defaultCenter] removeObserver:getObserver()
+ name:AVPlayerItemDidPlayToEndTimeNotification
+ object:pOldPlayerItem];
+ [getObserver() removeHandlerForObject:pOldPlayerItem];
+ // release the AVPlayer
+ CFRelease( mpPlayer );
+}
+
+// ------------------------------------------------------------------------------
+
+bool Player::handleObservation( NSString* pKeyPath )
+{
+ OSL_TRACE( "AVPlayer::handleObservation key=\"%s\"", [pKeyPath UTF8String]);
+ if( [pKeyPath isEqualToString:AVPlayerItemDidPlayToEndTimeNotification])
+ {
+ OSL_TRACE( "AVPlayer replay=%d", mbLooping);
+ if( mbLooping )
+ setMediaTime( 0.0);
+ }
+ return true;
+}
+
+// ------------------------------------------------------------------------------
+
+bool Player::create( const ::rtl::OUString& rURL )
+{
+ // get the media asset
+ NSString* aNSStr = [NSString stringWithCharacters:rURL.getStr() length:rURL.getLength()];
+ NSURL* aNSURL = [NSURL URLWithString: [aNSStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
+ // get the matching AVPlayerItem
+ AVPlayerItem* pPlayerItem = [AVPlayerItem playerItemWithURL:aNSURL];
+
+ // create or update the AVPlayer with the new AVPlayerItem
+ if( !mpPlayer )
+ {
+ mpPlayer = [AVPlayer playerWithPlayerItem:pPlayerItem];
+ CFRetain( mpPlayer );
+ [mpPlayer setActionAtItemEnd:AVPlayerActionAtItemEndNone];
+ }
+ else
+ {
+ // remove the obsoleted observers
+ AVPlayerItem* pOldPlayerItem = [mpPlayer currentItem];
+ [mpPlayer removeObserver:getObserver() forKeyPath:@"currentItem.status"];
+ [getObserver() removeHandlerForObject:pOldPlayerItem];
+ [[NSNotificationCenter defaultCenter] removeObserver:getObserver()
+ name:AVPlayerItemDidPlayToEndTimeNotification
+ object:pOldPlayerItem];
+ // replace the playeritem
+ [mpPlayer replaceCurrentItemWithPlayerItem:pPlayerItem];
+ }
+
+ // observe the status of the current player item
+ [mpPlayer addObserver:getObserver() forKeyPath:@"currentItem.status" options:0 context:this];
+
+ // observe playback-end needed for playback looping
+ [[NSNotificationCenter defaultCenter] addObserver:getObserver()
+ selector:@selector(onNotification:)
+ name:AVPlayerItemDidPlayToEndTimeNotification
+ object:pPlayerItem];
+ [getObserver() setHandlerForObject:pPlayerItem handler:this];
+
+ return true;
+}
+
+// ------------------------------------------------------------------------------
+
+void SAL_CALL Player::start()
+ throw (uno::RuntimeException)
+{
+ if( !mpPlayer )
+ return;
+#if 0
+ const AVPlayerStatus eStatus = [mpPlayer status];
+ OSL_TRACE ("Player::start status=%d", (int)eStatus);
+ if( eStatus == AVPlayerStatusReadyToPlay)
+#endif
+ [mpPlayer play];
+ // else // TODO: delay until it becomes ready
+}
+
+// ------------------------------------------------------------------------------
+
+void SAL_CALL Player::stop()
+ throw (uno::RuntimeException)
+{
+ if( !mpPlayer )
+ return;
+ const bool bPlaying = isPlaying();
+ OSL_TRACE ("Player::stop() playing=%d", bPlaying);
+ if( bPlaying )
+ [mpPlayer pause];
+}
+
+// ------------------------------------------------------------------------------
+
+sal_Bool SAL_CALL Player::isPlaying()
+ throw (uno::RuntimeException)
+{
+ if( !mpPlayer )
+ return false;
+ const float fRate = [mpPlayer rate];
+ return (fRate != 0.0);
+}
+
+// ------------------------------------------------------------------------------
+
+double SAL_CALL Player::getDuration()
+ throw (uno::RuntimeException)
+{
+ // slideshow checks for non-zero duration, so cheat here
+ double duration = 0.01;
+
+ if( mpPlayer )
+ {
+ AVPlayerItem* pItem = [mpPlayer currentItem];
+ if( [pItem status] == AVPlayerItemStatusReadyToPlay )
+ duration = CMTimeGetSeconds( [pItem duration] );
+ else // fall back to AVAsset's best guess
+ duration = CMTimeGetSeconds( [[pItem asset] duration] );
+ }
+
+ return duration;
+}
+
+// ------------------------------------------------------------------------------
+
+void SAL_CALL Player::setMediaTime( double fTime )
+ throw (uno::RuntimeException)
+{
+ OSL_TRACE ("Player::setMediaTime( %.3fsec)", fTime);
+ if( mpPlayer )
+ [mpPlayer seekToTime: CMTimeMakeWithSeconds(fTime,1000) ];
+}
+
+// ------------------------------------------------------------------------------
+
+double SAL_CALL Player::getMediaTime()
+ throw (uno::RuntimeException)
+{
+ if( !mpPlayer )
+ return 0.0;
+
+ const double position = CMTimeGetSeconds( [mpPlayer currentTime] );
+ OSL_TRACE( "Player::getMediaTime() = %.3fsec", position);
+ if( position >= mfStopTime )
+ if( isPlaying() )
+ stop();
+
+ return position;
+}
+
+// ------------------------------------------------------------------------------
+
+void SAL_CALL Player::setStopTime( double fTime )
+ throw (uno::RuntimeException)
+{
+ OSL_TRACE ("Player::setStopTime( %.3fsec)", fTime);
+ mfStopTime = fTime;
+}
+
+// ------------------------------------------------------------------------------
+
+double SAL_CALL Player::getStopTime()
+ throw (uno::RuntimeException)
+{
+ return mfStopTime;
+}
+
+// ------------------------------------------------------------------------------
+
+void SAL_CALL Player::setRate( double fRate )
+ throw (uno::RuntimeException)
+{
+ OSL_TRACE ("Player::setRate( %.3f)", fRate);
+ if( !mpPlayer )
+ return;
+
+ // playback rate: 0 = stop, 1 = normal speed, 2 = double speed, -1 = normal speed backwards
+ [mpPlayer setRate: fRate];
+}
+
+// ------------------------------------------------------------------------------
+
+double SAL_CALL Player::getRate()
+ throw (uno::RuntimeException)
+{
+ // macavf: 0 = stop, 1 = normal speed, 2 = double speed, -1 = normal speed backwards
+ const double fRate = mpPlayer ? (double)[mpPlayer rate] : 1.0;
+ OSL_TRACE ("Player::getRate() = %.3f", fRate);
+ return fRate;
+}
+
+// ------------------------------------------------------------------------------
+
+void SAL_CALL Player::setPlaybackLoop( sal_Bool bSet )
+ throw (uno::RuntimeException)
+{
+ OSL_TRACE ("Player::setPlaybackLoop( %d)", bSet );
+ mbLooping = bSet;
+}
+
+// ------------------------------------------------------------------------------
+
+sal_Bool SAL_CALL Player::isPlaybackLoop()
+ throw (uno::RuntimeException)
+{
+ const bool bRet = mbLooping;
+ OSL_TRACE ("Player::isPlaybackLoop() = %d", bRet );
+ return bRet;
+}
+
+// ------------------------------------------------------------------------------
+
+void SAL_CALL Player::setMute( sal_Bool bSet )
+ throw (uno::RuntimeException)
+{
+ OSL_TRACE( "Player::setMute(%d), was-muted: %d unmuted-volume: %.3f", bSet, mbMuted, mfUnmutedVolume );
+
+ if( !mpPlayer )
+ return;
+
+ mbMuted = (bSet == TRUE);
+ [mpPlayer setMuted:mbMuted];
+}
+
+// ------------------------------------------------------------------------------
+
+sal_Bool SAL_CALL Player::isMute()
+ throw (uno::RuntimeException)
+{
+ OSL_TRACE ("Player::isMuted() = %d", mbMuted);
+ return mbMuted;
+}
+
+// ------------------------------------------------------------------------------
+
+void SAL_CALL Player::setVolumeDB( sal_Int16 nVolumeDB )
+ throw (uno::RuntimeException)
+{
+ // -40dB <-> AVPlayer volume 0.0
+ // 0dB <-> AVPlayer volume 1.0
+ mfUnmutedVolume = (nVolumeDB <= -40) ? 0.0 : pow( 10.0, nVolumeDB / 20.0 );
+ OSL_TRACE( "Player::setVolume(%ddB), muted=%d, unmuted-volume: %.3f", nVolumeDB, mbMuted, mfUnmutedVolume );
+
+ // change volume
+ if( !mbMuted && mpPlayer )
+ [mpPlayer setVolume:mfUnmutedVolume];
+}
+
+// ------------------------------------------------------------------------------
+
+sal_Int16 SAL_CALL Player::getVolumeDB()
+ throw (uno::RuntimeException)
+{
+ if( !mpPlayer )
+ return 0;
+
+ // get the actual volume
+ const float fVolume = [mpPlayer volume];
+
+ // convert into Dezibel value
+ // -40dB <-> AVPlayer volume 0.0
+ // 0dB <-> AVPlayer volume 1.0
+ const int nVolumeDB = (fVolume <= 0) ? -40 : lrint( 20.0*log10(fVolume));
+
+ return (sal_Int16)nVolumeDB;
+}
+
+// ------------------------------------------------------------------------------
+
+awt::Size SAL_CALL Player::getPreferredPlayerWindowSize()
+ throw (uno::RuntimeException)
+{
+ awt::Size aSize( 0, 0 ); // default size
+
+ AVAsset* pMovie = [[mpPlayer currentItem] asset];
+ NSArray* pVideoTracks = [pMovie tracksWithMediaType:AVMediaTypeVideo];
+ AVAssetTrack* pFirstVideoTrack = (AVAssetTrack*)[pVideoTracks firstObject];
+ if( pFirstVideoTrack )
+ {
+ const CGSize aPrefSize = [pFirstVideoTrack naturalSize];
+ aSize = awt::Size( aPrefSize.width, aPrefSize.height );
+ }
+
+ return aSize;
+}
+
+// ------------------------------------------------------------------------------
+
+uno::Reference< ::media::XPlayerWindow > SAL_CALL Player::createPlayerWindow( const uno::Sequence< uno::Any >& aArguments )
+ throw (uno::RuntimeException)
+{
+ // get the preferred window size
+ const awt::Size aSize( getPreferredPlayerWindowSize() );
+ OSL_TRACE( "Player::createPlayerWindow %dx%d argsLength: %d", aSize.Width, aSize.Height, aArguments.getLength() );
+
+ // get the parent view
+ sal_IntPtr nNSViewPtr = NULL;
+ aArguments[0] >>= nNSViewPtr;
+ NSView* pParentView = reinterpret_cast<NSView*>(nNSViewPtr);
+
+ // check the window parameters
+ uno::Reference< ::media::XPlayerWindow > xRet;
+ if( (aSize.Width <= 0) || (aSize.Height <= 0) || (pParentView == NULL) )
+ return xRet;
+
+ // create the window
+ ::avmedia::macavf::Window* pWindow = new ::avmedia::macavf::Window( mxMgr, *this, pParentView );
+ xRet = pWindow;
+ return xRet;
+}
+
+// ------------------------------------------------------------------------------
+
+uno::Reference< media::XFrameGrabber > SAL_CALL Player::createFrameGrabber()
+ throw (uno::RuntimeException)
+{
+ uno::Reference< media::XFrameGrabber > xRet;
+ OSL_TRACE ("Player::createFrameGrabber");
+
+ FrameGrabber* pGrabber = new FrameGrabber( mxMgr );
+ AVAsset* pMovie = [[mpPlayer currentItem] asset];
+ if( pGrabber->create( pMovie ) )
+ xRet = pGrabber;
+
+ return xRet;
+}
+
+// ------------------------------------------------------------------------------
+
+::rtl::OUString SAL_CALL Player::getImplementationName( )
+ throw (uno::RuntimeException)
+{
+ return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( AVMEDIA_MACAVF_PLAYER_IMPLEMENTATIONNAME ) );
+}
+
+// ------------------------------------------------------------------------------
+
+sal_Bool SAL_CALL Player::supportsService( const ::rtl::OUString& ServiceName )
+ throw (uno::RuntimeException)
+{
+ return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( AVMEDIA_MACAVF_PLAYER_SERVICENAME ) );
+}
+
+// ------------------------------------------------------------------------------
+
+uno::Sequence< ::rtl::OUString > SAL_CALL Player::getSupportedServiceNames( )
+ throw (uno::RuntimeException)
+{
+ uno::Sequence< ::rtl::OUString > aRet(1);
+ aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( AVMEDIA_MACAVF_PLAYER_SERVICENAME ) );
+
+ return aRet;
+}
+
+} // namespace macavf
+} // namespace avmedia
+