diff options
Diffstat (limited to 'avmedia/source/macavf')
-rw-r--r-- | avmedia/source/macavf/avmediaMacAVF.component | 26 | ||||
-rw-r--r-- | avmedia/source/macavf/framegrabber.hxx | 54 | ||||
-rw-r--r-- | avmedia/source/macavf/framegrabber.mm | 108 | ||||
-rw-r--r-- | avmedia/source/macavf/macavfcommon.hxx | 86 | ||||
-rw-r--r-- | avmedia/source/macavf/manager.hxx | 49 | ||||
-rw-r--r-- | avmedia/source/macavf/manager.mm | 77 | ||||
-rw-r--r-- | avmedia/source/macavf/player.hxx | 83 | ||||
-rw-r--r-- | avmedia/source/macavf/player.mm | 359 | ||||
-rw-r--r-- | avmedia/source/macavf/window.hxx | 108 | ||||
-rw-r--r-- | avmedia/source/macavf/window.mm | 260 |
10 files changed, 1210 insertions, 0 deletions
diff --git a/avmedia/source/macavf/avmediaMacAVF.component b/avmedia/source/macavf/avmediaMacAVF.component new file mode 100644 index 000000000..3cb9966c1 --- /dev/null +++ b/avmedia/source/macavf/avmediaMacAVF.component @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.avmedia.Manager_MacAVF" + constructor="com_sun_star_comp_avmedia_Manager_MacAVF_get_implementation"> + <service name="com.sun.star.media.Manager_MacAVF"/> + </implementation> +</component> diff --git a/avmedia/source/macavf/framegrabber.hxx b/avmedia/source/macavf/framegrabber.hxx new file mode 100644 index 000000000..5e0c749d9 --- /dev/null +++ b/avmedia/source/macavf/framegrabber.hxx @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#pragma once + +#include "macavfcommon.hxx" +#include <cppuhelper/implbase.hxx> + +#include <com/sun/star/media/XFrameGrabber.hpp> + +namespace avmedia::macavf { + +class FrameGrabber : public ::cppu::WeakImplHelper< css::media::XFrameGrabber, + css::lang::XServiceInfo > +{ +public: + + explicit FrameGrabber(); + virtual ~FrameGrabber() override; + + bool create( AVAsset* pMovie ); + + // XFrameGrabber + virtual css::uno::Reference< css::graphic::XGraphic > SAL_CALL grabFrame( double fMediaTime ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + +private: + + AVAssetImageGenerator* mpImageGen; +}; + +} // namespace avmedia::macavf + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/avmedia/source/macavf/framegrabber.mm b/avmedia/source/macavf/framegrabber.mm new file mode 100644 index 000000000..e0b8bad61 --- /dev/null +++ b/avmedia/source/macavf/framegrabber.mm @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include "framegrabber.hxx" +#include "player.hxx" + +#include <sal/log.hxx> +#include <tools/stream.hxx> +#include <vcl/graph.hxx> +#include <vcl/cvtgrf.hxx> +#include <unotools/localfilehelper.hxx> + +using namespace ::com::sun::star; + +namespace avmedia::macavf { + +FrameGrabber::FrameGrabber() +: mpImageGen( nullptr ) +{} + + +FrameGrabber::~FrameGrabber() +{ + if( mpImageGen ) + CFRelease( mpImageGen ); +} + + +bool FrameGrabber::create( AVAsset* pMovie ) +{ + if( [[pMovie tracksWithMediaType:AVMediaTypeVideo] count] == 0) + { + SAL_WARN("avmedia", "AVGrabber::create() found no video content!" ); + return false; + } + + mpImageGen = [AVAssetImageGenerator assetImageGeneratorWithAsset:pMovie]; + CFRetain( mpImageGen ); + return true; +} + + +uno::Reference< graphic::XGraphic > SAL_CALL FrameGrabber::grabFrame( double fMediaTime ) +{ + uno::Reference< graphic::XGraphic > xRet; + if( !mpImageGen ) + return xRet; + + // get the requested image from the movie + CGImage* pCGImage = [mpImageGen copyCGImageAtTime:CMTimeMakeWithSeconds(fMediaTime,1000) actualTime:nullptr error:nullptr]; + + // convert the image to a TIFF-formatted byte-array + CFMutableDataRef pCFData = CFDataCreateMutable( kCFAllocatorDefault, 0 ); + SAL_WNODEPRECATED_DECLARATIONS_PUSH // kUTTypeTIFF (12.0) + CGImageDestination* pCGImgDest = CGImageDestinationCreateWithData( pCFData, kUTTypeTIFF, 1, nullptr ); + SAL_WNODEPRECATED_DECLARATIONS_POP + CGImageDestinationAddImage( pCGImgDest, pCGImage, nullptr ); + CGImageDestinationFinalize( pCGImgDest ); + CFRelease( pCGImgDest ); + const CFIndex nBitmapLen = CFDataGetLength( pCFData ); + UInt8 * pBitmapBytes = const_cast<UInt8 *>(CFDataGetBytePtr( pCFData )); + + // convert the image into the return-value type which is a graphic::XGraphic + SvMemoryStream aMemStm( pBitmapBytes, nBitmapLen, StreamMode::READ | StreamMode::WRITE ); + Graphic aGraphic; + if( GraphicConverter::Import( aMemStm, aGraphic, ConvertDataFormat::TIF ) == ERRCODE_NONE ) + xRet = aGraphic.GetXGraphic(); + + // clean up resources + CFRelease( pCFData ); + return xRet; +} + + +OUString SAL_CALL FrameGrabber::getImplementationName( ) +{ + return AVMEDIA_MACAVF_FRAMEGRABBER_IMPLEMENTATIONNAME; +} + +sal_Bool SAL_CALL FrameGrabber::supportsService( const OUString& ServiceName ) +{ + return ServiceName == AVMEDIA_MACAVF_FRAMEGRABBER_SERVICENAME; +} + +uno::Sequence< OUString > SAL_CALL FrameGrabber::getSupportedServiceNames( ) +{ + return { AVMEDIA_MACAVF_FRAMEGRABBER_SERVICENAME }; +} + +} // namespace avmedia::macavf + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/avmedia/source/macavf/macavfcommon.hxx b/avmedia/source/macavf/macavfcommon.hxx new file mode 100644 index 000000000..b031f1ecc --- /dev/null +++ b/avmedia/source/macavf/macavfcommon.hxx @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#pragma once + +#include <premac.h> +#import <Cocoa/Cocoa.h> +#import <AVFoundation/AVFoundation.h> +#include <postmac.h> + +#include <unordered_map> + +#include <osl/mutex.hxx> +#include <rtl/ustring.hxx> +#include <tools/stream.hxx> +#include <tools/urlobj.hxx> +#include <cppuhelper/weak.hxx> +#include <cppuhelper/factory.hxx> + +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/registry/XRegistryKey.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/awt/KeyModifier.hpp> +#include <com/sun/star/awt/MouseButton.hpp> +#include <com/sun/star/media/XManager.hpp> + + +#define AVMEDIA_MACAVF_PLAYER_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.Player_MacAVF" +#define AVMEDIA_MACAVF_PLAYER_SERVICENAME "com.sun.star.media.Player_MacAVF" + +#define AVMEDIA_MACAVF_WINDOW_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.Window_MacAVF" +#define AVMEDIA_MACAVF_WINDOW_SERVICENAME "com.sun.star.media.Window_MacAVF" + +#define AVMEDIA_MACAVF_FRAMEGRABBER_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.FrameGrabber_MacAVF" +#define AVMEDIA_MACAVF_FRAMEGRABBER_SERVICENAME "com.sun.star.media.FrameGrabber_MacAVF" + + +// MacAVObserver handles the notifications used in the AVFoundation framework + +namespace avmedia::macavf { class MacAVObserverHandler; } + +typedef std::unordered_map<NSObject*,avmedia::macavf::MacAVObserverHandler*> HandlersForObject; + +@interface MacAVObserverObject : NSObject +{ + HandlersForObject maHandlersForObject; +} +- (void)observeValueForKeyPath:(NSString*)pKeyPath ofObject:(id)pObject change:(NSDictionary*)pChangeDict context:(void*)pContext; +- (void)onNotification:(NSNotification*)pNotification; +@end + +namespace avmedia::macavf { + +class MacAVObserverHandler +{ +private: + static MacAVObserverObject* mpMacAVObserverObject; +public: + virtual ~MacAVObserverHandler() {} + static MacAVObserverObject* getObserver(); + virtual bool handleObservation( NSString* pKeyPath ) = 0; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/avmedia/source/macavf/manager.hxx b/avmedia/source/macavf/manager.hxx new file mode 100644 index 000000000..9072b3800 --- /dev/null +++ b/avmedia/source/macavf/manager.hxx @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#pragma once + +#include "macavfcommon.hxx" +#include <cppuhelper/implbase.hxx> + +#include <com/sun/star/media/XManager.hpp> + + +namespace avmedia::macavf { + +class Manager : public ::cppu::WeakImplHelper< css::media::XManager, + css::lang::XServiceInfo > +{ +public: + + Manager(); + virtual ~Manager() override; + + // XManager + virtual css::uno::Reference< css::media::XPlayer > SAL_CALL createPlayer( const OUString& aURL ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; +}; + +} // namespace avmedia::macavf + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/avmedia/source/macavf/manager.mm b/avmedia/source/macavf/manager.mm new file mode 100644 index 000000000..d240bb27a --- /dev/null +++ b/avmedia/source/macavf/manager.mm @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include "manager.hxx" +#include "player.hxx" +#include <tools/urlobj.hxx> +#include <osl/diagnose.h> +#include <rtl/ref.hxx> + +using namespace ::com::sun::star; + +namespace avmedia::macavf { + +Manager::Manager() +{ +} + + +Manager::~Manager() +{} + + +uno::Reference< media::XPlayer > SAL_CALL Manager::createPlayer( const OUString& rURL ) +{ + rtl::Reference<Player> xPlayer( new Player() ); + INetURLObject aURL( rURL ); + + if( !xPlayer->create( aURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ) ) ) + return {}; + + return uno::Reference<media::XPlayer>(xPlayer); +} + + +OUString SAL_CALL Manager::getImplementationName( ) +{ + return "com.sun.star.comp.avmedia.Manager_MacAVF"; +} + + +sal_Bool SAL_CALL Manager::supportsService( const OUString& ServiceName ) +{ + return ServiceName == "com.sun.star.media.Manager_MacAVF"; +} + + +uno::Sequence< OUString > SAL_CALL Manager::getSupportedServiceNames( ) +{ + return { "com.sun.star.media.Manager_MacAVF" }; +} + +} // namespace avmedia::macavf + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_avmedia_Manager_MacAVF_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new ::avmedia::macavf::Manager()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/avmedia/source/macavf/player.hxx b/avmedia/source/macavf/player.hxx new file mode 100644 index 000000000..3dc41b347 --- /dev/null +++ b/avmedia/source/macavf/player.hxx @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#pragma once + +#include <osl/conditn.h> +#include "macavfcommon.hxx" +#include <cppuhelper/implbase.hxx> + +#include <com/sun/star/media/XPlayer.hpp> + +namespace avmedia::macavf { + +class Player +: public MacAVObserverHandler +, public ::cppu::WeakImplHelper< css::media::XPlayer, + css::lang::XServiceInfo > +{ +public: + explicit Player(); + virtual ~Player() override; + + bool create( const OUString& rURL ); + bool create( AVAsset* ); + + // XPlayer + virtual void SAL_CALL start() override; + virtual void SAL_CALL stop() override; + virtual sal_Bool SAL_CALL isPlaying() override; + virtual double SAL_CALL getDuration() override; + virtual void SAL_CALL setMediaTime( double fTime ) override; + virtual double SAL_CALL getMediaTime() override; + /// @throws css::uno::RuntimeException + virtual void setStopTime( double fTime ); + /// @throws css::uno::RuntimeException + virtual double getStopTime(); + virtual void SAL_CALL setPlaybackLoop( sal_Bool bSet ) override; + virtual sal_Bool SAL_CALL isPlaybackLoop() override; + virtual void SAL_CALL setMute( sal_Bool bSet ) override; + virtual sal_Bool SAL_CALL isMute() override; + virtual void SAL_CALL setVolumeDB( sal_Int16 nVolumeDB ) override; + virtual sal_Int16 SAL_CALL getVolumeDB() override; + virtual css::awt::Size SAL_CALL getPreferredPlayerWindowSize( ) override; + virtual css::uno::Reference< css::media::XPlayerWindow > SAL_CALL createPlayerWindow( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + virtual css::uno::Reference< css::media::XFrameGrabber > SAL_CALL createFrameGrabber( ) override; + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + AVPlayer* getAVPlayer() const { return mpPlayer; } + virtual bool handleObservation( NSString* pKeyPath ) override; + +private: + + AVPlayer* mpPlayer; + + float mfUnmutedVolume; + double mfStopTime; + + bool mbMuted; + bool mbLooping; +}; + +} // namespace avmedia::macavf + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/avmedia/source/macavf/player.mm b/avmedia/source/macavf/player.mm new file mode 100644 index 000000000..401cba74c --- /dev/null +++ b/avmedia/source/macavf/player.mm @@ -0,0 +1,359 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include "player.hxx" +#include "framegrabber.hxx" +#include "window.hxx" +#include <rtl/ref.hxx> + +#include <cmath> // for log10() + +using namespace ::com::sun::star; + +@implementation MacAVObserverObject + +- (void)observeValueForKeyPath:(NSString*)pKeyPath ofObject:(id)pObject change:(NSDictionary*)pChangeDict context:(void*)pContext +{ + (void) pObject; + (void) pChangeDict; + avmedia::macavf::MacAVObserverHandler* pHandler = static_cast<avmedia::macavf::MacAVObserverHandler*>(pContext); + pHandler->handleObservation( pKeyPath ); +} + +- (void)onNotification:(NSNotification*)pNotification +{ + NSString* pNoteName = [pNotification name]; + 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::macavf { + +MacAVObserverObject* MacAVObserverHandler::mpMacAVObserverObject = nullptr; + +MacAVObserverObject* MacAVObserverHandler::getObserver() +{ + if( !mpMacAVObserverObject) + { + mpMacAVObserverObject = [MacAVObserverObject alloc]; + [mpMacAVObserverObject retain]; + } + return mpMacAVObserverObject; +} + + +Player::Player() +: mpPlayer( nullptr ) +, 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 ) +{ + if( [pKeyPath isEqualToString:AVPlayerItemDidPlayToEndTimeNotification]) + { + if( mbLooping ) + setMediaTime( 0.0); + } + return true; +} + + +bool Player::create( const OUString& rURL ) +{ + // get the media asset + NSString* aNSStr = [NSString stringWithCharacters:reinterpret_cast<unichar const *>(rURL.getStr()) length:rURL.getLength()]; + SAL_WNODEPRECATED_DECLARATIONS_PUSH + //TODO: 10.11 stringByAddingPercentEscapesUsingEncoding + NSURL* aNSURL = [NSURL URLWithString: [aNSStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; + SAL_WNODEPRECATED_DECLARATIONS_POP + // 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() +{ + if( !mpPlayer ) + return; + + [mpPlayer play]; + // else // TODO: delay until it becomes ready +} + + +void SAL_CALL Player::stop() +{ + if( !mpPlayer ) + return; + const bool bPlaying = isPlaying(); + if( bPlaying ) + [mpPlayer pause]; +} + + +sal_Bool SAL_CALL Player::isPlaying() +{ + if( !mpPlayer ) + return false; + const float fRate = [mpPlayer rate]; + return (fRate != 0.0); +} + + +double SAL_CALL Player::getDuration() +{ + // 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 ) +{ + if( mpPlayer ) + [mpPlayer seekToTime: CMTimeMakeWithSeconds(fTime,1000) ]; +} + + +double SAL_CALL Player::getMediaTime() +{ + if( !mpPlayer ) + return 0.0; + + const double position = CMTimeGetSeconds( [mpPlayer currentTime] ); + if( position >= mfStopTime ) + if( isPlaying() ) + stop(); + + return position; +} + + +void Player::setStopTime( double fTime ) +{ + mfStopTime = fTime; +} + + +double Player::getStopTime() +{ + return mfStopTime; +} + + +void SAL_CALL Player::setPlaybackLoop( sal_Bool bSet ) +{ + mbLooping = bSet; +} + + +sal_Bool SAL_CALL Player::isPlaybackLoop() +{ + return mbLooping; +} + + +void SAL_CALL Player::setMute( sal_Bool bSet ) +{ + if( !mpPlayer ) + return; + + mbMuted = bSet; + [mpPlayer setMuted:mbMuted]; +} + + +sal_Bool SAL_CALL Player::isMute() +{ + return mbMuted; +} + + +void SAL_CALL Player::setVolumeDB( sal_Int16 nVolumeDB ) +{ + // -40dB <-> AVPlayer volume 0.0 + // 0dB <-> AVPlayer volume 1.0 + mfUnmutedVolume = (nVolumeDB <= -40) ? 0.0 : pow( 10.0, nVolumeDB / 20.0 ); + + // change volume + if( !mbMuted && mpPlayer ) + [mpPlayer setVolume:mfUnmutedVolume]; +} + + +sal_Int16 SAL_CALL Player::getVolumeDB() +{ + if( !mpPlayer ) + return 0; + + // get the actual volume + const float fVolume = [mpPlayer volume]; + + // convert into Decibel value + // -40dB <-> AVPlayer volume 0.0 + // 0dB <-> AVPlayer volume 1.0 + const int nVolumeDB = (fVolume <= 0) ? -40 : lrint( 20.0*log10(fVolume)); + + return static_cast<sal_Int16>(nVolumeDB); +} + + +awt::Size SAL_CALL Player::getPreferredPlayerWindowSize() +{ + awt::Size aSize( 0, 0 ); // default size + + AVAsset* pMovie = [[mpPlayer currentItem] asset]; + NSArray* pVideoTracks = [pMovie tracksWithMediaType:AVMediaTypeVideo]; + if ([pVideoTracks count] > 0) + { + AVAssetTrack* pFirstVideoTrack = static_cast<AVAssetTrack*>([pVideoTracks objectAtIndex:0]); + 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 ) +{ + // get the preferred window size + const awt::Size aSize( getPreferredPlayerWindowSize() ); + + // get the parent view + sal_IntPtr nNSViewPtr = 0; + aArguments[0] >>= nNSViewPtr; + NSView* pParentView = reinterpret_cast<NSView*>(nNSViewPtr); + + // check the window parameters + if( (aSize.Width <= 0) || (aSize.Height <= 0) || (pParentView == nullptr) ) + return {}; + + // create the window + return new ::avmedia::macavf::Window( *this, pParentView ); +} + + +uno::Reference< media::XFrameGrabber > SAL_CALL Player::createFrameGrabber() +{ + rtl::Reference<FrameGrabber> pGrabber = new FrameGrabber(); + AVAsset* pMovie = [[mpPlayer currentItem] asset]; + if( !pGrabber->create( pMovie ) ) + return {}; + + return pGrabber; +} + + +OUString SAL_CALL Player::getImplementationName( ) +{ + return AVMEDIA_MACAVF_PLAYER_IMPLEMENTATIONNAME; +} + + +sal_Bool SAL_CALL Player::supportsService( const OUString& ServiceName ) +{ + return ServiceName == AVMEDIA_MACAVF_PLAYER_SERVICENAME; +} + + +uno::Sequence< OUString > SAL_CALL Player::getSupportedServiceNames( ) +{ + return { AVMEDIA_MACAVF_PLAYER_SERVICENAME }; +} + +} // namespace avmedia::macavf + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/avmedia/source/macavf/window.hxx b/avmedia/source/macavf/window.hxx new file mode 100644 index 000000000..14fdaf389 --- /dev/null +++ b/avmedia/source/macavf/window.hxx @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#pragma once + +#include "macavfcommon.hxx" +#include <cppuhelper/implbase.hxx> +#include <comphelper/multicontainer2.hxx> + +#include <com/sun/star/media/XPlayerWindow.hpp> + + +@interface MyMediaView : NSView +@property (nonatomic, readonly, strong) AVPlayer* player; +@property (nonatomic, readonly, strong) AVPlayerLayer* playerLayer; +@property (nonatomic, retain) NSURL* videoURL; +- (void) play; +@end + +namespace avmedia::macavf { + +class Player; + +class Window +: public MacAVObserverHandler +, public ::cppu::WeakImplHelper< css::media::XPlayerWindow, + css::lang::XServiceInfo > +{ +public: + + Window( Player& i_rPlayer, + NSView* i_pParentView + ); + virtual ~Window() override; + + void processGraphEvent(); + void updatePointer(); + + // XPlayerWindow + virtual void SAL_CALL update( ) override; + virtual sal_Bool SAL_CALL setZoomLevel( css::media::ZoomLevel ZoomLevel ) override; + virtual css::media::ZoomLevel SAL_CALL getZoomLevel( ) override; + virtual void SAL_CALL setPointerType( sal_Int32 nPointerType ) override; + + // XWindow + virtual void SAL_CALL setPosSize( sal_Int32 X, sal_Int32 Y, sal_Int32 Width, sal_Int32 Height, sal_Int16 Flags ) override; + virtual css::awt::Rectangle SAL_CALL getPosSize( ) override; + virtual void SAL_CALL setVisible( sal_Bool Visible ) override; + virtual void SAL_CALL setEnable( sal_Bool Enable ) override; + virtual void SAL_CALL setFocus( ) override; + virtual void SAL_CALL addWindowListener( const css::uno::Reference< css::awt::XWindowListener >& xListener ) override; + virtual void SAL_CALL removeWindowListener( const css::uno::Reference< css::awt::XWindowListener >& xListener ) override; + virtual void SAL_CALL addFocusListener( const css::uno::Reference< css::awt::XFocusListener >& xListener ) override; + virtual void SAL_CALL removeFocusListener( const css::uno::Reference< css::awt::XFocusListener >& xListener ) override; + virtual void SAL_CALL addKeyListener( const css::uno::Reference< css::awt::XKeyListener >& xListener ) override; + virtual void SAL_CALL removeKeyListener( const css::uno::Reference< css::awt::XKeyListener >& xListener ) override; + virtual void SAL_CALL addMouseListener( const css::uno::Reference< css::awt::XMouseListener >& xListener ) override; + virtual void SAL_CALL removeMouseListener( const css::uno::Reference< css::awt::XMouseListener >& xListener ) override; + virtual void SAL_CALL addMouseMotionListener( const css::uno::Reference< css::awt::XMouseMotionListener >& xListener ) override; + virtual void SAL_CALL removeMouseMotionListener( const css::uno::Reference< css::awt::XMouseMotionListener >& xListener ) override; + virtual void SAL_CALL addPaintListener( const css::uno::Reference< css::awt::XPaintListener >& xListener ) override; + virtual void SAL_CALL removePaintListener( const css::uno::Reference< css::awt::XPaintListener >& xListener ) override; + + // XComponent + virtual void SAL_CALL dispose( ) override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + virtual bool handleObservation( NSString* pKeyPath ) override; + +private: + + ::osl::Mutex maMutex; + comphelper::OMultiTypeInterfaceContainerHelper2 maListeners; + css::media::ZoomLevel meZoomLevel; + Player& mrPlayer; + int mnPointerType; + + NSView* mpView; // parent-view == movie-view + AVPlayerLayer* mpPlayerLayer; + + void ImplLayoutVideoWindow(); +}; + +} // namespace avmedia::macavf + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/avmedia/source/macavf/window.mm b/avmedia/source/macavf/window.mm new file mode 100644 index 000000000..fdb2e5065 --- /dev/null +++ b/avmedia/source/macavf/window.mm @@ -0,0 +1,260 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <com/sun/star/awt/SystemPointer.hpp> +#include <com/sun/star/awt/PosSize.hpp> + +#include "window.hxx" +#include "player.hxx" + +using namespace ::com::sun::star; + + +namespace avmedia::macavf { + +Window::Window( Player& i_rPlayer, NSView* i_pParentView ) +: maListeners( maMutex ) +, meZoomLevel( media::ZoomLevel_NOT_AVAILABLE ) +, mrPlayer( i_rPlayer ) +, mnPointerType( awt::SystemPointer::ARROW ) +, mpView( i_pParentView ) +, mpPlayerLayer( nullptr ) +{ + if( !mpView ) // sanity check + return; + + // check the media asset for video content + AVPlayer* pAVPlayer = mrPlayer.getAVPlayer(); + AVAsset* pMovie = [[pAVPlayer currentItem] asset]; + const int nVideoCount = [pMovie tracksWithMediaType:AVMediaTypeVideo].count; + if( nVideoCount <= 0 ) + return; + + // setup the AVPlayerLayer + [pAVPlayer retain]; + [pAVPlayer pause]; + mpPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:pAVPlayer]; + [mpPlayerLayer retain]; + NSRect viewFrame = [mpView frame]; + [mpPlayerLayer setFrame:CGRectMake(viewFrame.origin.x, viewFrame.origin.y, viewFrame.size.width, viewFrame.size.height)]; + [mpPlayerLayer setHidden:YES]; + [mpPlayerLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill]; + [mpPlayerLayer addObserver:getObserver() forKeyPath:@"readyForDisplay" options:0 context:this]; + + // setup the target view + [mpView setWantsLayer:YES]; + [mpView.layer addSublayer:mpPlayerLayer]; +} + + +Window::~Window() +{ + [mpPlayerLayer removeObserver:getObserver() forKeyPath:@"readyForDisplay"]; + [mpPlayerLayer release]; +} + + +bool Window::handleObservation( NSString* /*pKeyPath*/ ) +{ + const bool bReadyForDisplay = [mpPlayerLayer isReadyForDisplay]; + [mpPlayerLayer setHidden:!bReadyForDisplay]; + return true; +} + +// XPlayerWindow + +void SAL_CALL Window::update() +{} + + +sal_Bool SAL_CALL Window::setZoomLevel( media::ZoomLevel /* eZoomLevel */ ) +{ + return false; +} + + +media::ZoomLevel SAL_CALL Window::getZoomLevel( ) +{ + return meZoomLevel; +} + + +void SAL_CALL Window::setPointerType( sal_Int32 nPointerType ) +{ + mnPointerType = nPointerType; +} + +// XWindow + +void SAL_CALL Window::setPosSize( sal_Int32 /*X*/, sal_Int32 /*Y*/, sal_Int32 Width, sal_Int32 Height, sal_Int16 /* Flags */ ) +{ + if( !mpView ) + return; + NSRect aRect = [mpView frame]; + // NOTE: if( (Flags & awt::PosSize::WIDTH) ) + aRect.size.width = Width; + // NOTE: if( (Flags & awt::PosSize::HEIGHT) ) + aRect.size.height = Height; + + [mpView setFrameSize: aRect.size]; + NSRect viewFrame = [mpView frame]; + [mpPlayerLayer setFrame:CGRectMake(viewFrame.origin.x, viewFrame.origin.y, viewFrame.size.width, viewFrame.size.height)]; +} + + +awt::Rectangle SAL_CALL Window::getPosSize() +{ + awt::Rectangle aRet; + + NSRect aRect = [mpView frame]; + aRet.X = aRet.Y = 0; + aRet.Width = aRect.size.width; + aRet.Height = aRect.size.height; + + return aRet; +} + + +void SAL_CALL Window::setVisible( sal_Bool /*bVisible*/ ) +{ +} + + +void SAL_CALL Window::setEnable( sal_Bool /*bEnable*/ ) +{ +} + + +void SAL_CALL Window::setFocus() +{ +} + + +void SAL_CALL Window::addWindowListener( const uno::Reference< awt::XWindowListener >& xListener ) +{ + maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener ); +} + + +void SAL_CALL Window::removeWindowListener( const uno::Reference< awt::XWindowListener >& xListener ) +{ + maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener ); +} + + +void SAL_CALL Window::addFocusListener( const uno::Reference< awt::XFocusListener >& xListener ) +{ + maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener ); +} + + +void SAL_CALL Window::removeFocusListener( const uno::Reference< awt::XFocusListener >& xListener ) +{ + maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener ); +} + + +void SAL_CALL Window::addKeyListener( const uno::Reference< awt::XKeyListener >& xListener ) +{ + maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener ); +} + + +void SAL_CALL Window::removeKeyListener( const uno::Reference< awt::XKeyListener >& xListener ) +{ + maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener ); +} + + +void SAL_CALL Window::addMouseListener( const uno::Reference< awt::XMouseListener >& xListener ) +{ + maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener ); +} + + +void SAL_CALL Window::removeMouseListener( const uno::Reference< awt::XMouseListener >& xListener ) +{ + maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener ); +} + + +void SAL_CALL Window::addMouseMotionListener( const uno::Reference< awt::XMouseMotionListener >& xListener ) +{ + maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener ); +} + + +void SAL_CALL Window::removeMouseMotionListener( const uno::Reference< awt::XMouseMotionListener >& xListener ) +{ + maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener ); +} + + +void SAL_CALL Window::addPaintListener( const uno::Reference< awt::XPaintListener >& xListener ) +{ + maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener ); +} + + +void SAL_CALL Window::removePaintListener( const uno::Reference< awt::XPaintListener >& xListener ) +{ + maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener ); +} + + +// XComponent + +void SAL_CALL Window::dispose( ) +{ +} + + +void SAL_CALL Window::addEventListener( const uno::Reference< lang::XEventListener >& xListener ) +{ + maListeners.addInterface( cppu::UnoType<decltype(xListener)>::get(), xListener ); +} + + +void SAL_CALL Window::removeEventListener( const uno::Reference< lang::XEventListener >& xListener ) +{ + maListeners.removeInterface( cppu::UnoType<decltype(xListener)>::get(), xListener ); +} + +// XServiceInfo + +OUString SAL_CALL Window::getImplementationName( ) +{ + return AVMEDIA_MACAVF_WINDOW_IMPLEMENTATIONNAME; +} + + +sal_Bool SAL_CALL Window::supportsService( const OUString& ServiceName ) +{ + return ServiceName == AVMEDIA_MACAVF_WINDOW_SERVICENAME; +} + + +uno::Sequence< OUString > SAL_CALL Window::getSupportedServiceNames( ) +{ + return { AVMEDIA_MACAVF_WINDOW_SERVICENAME }; +} + +} // namespace avmedia::macavf + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |