From 940b4d1848e8c70ab7642901a68594e8016caffc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 18:51:28 +0200 Subject: Adding upstream version 1:7.0.4. Signed-off-by: Daniel Baumann --- avmedia/source/macavf/avmediaMacAVF.component | 25 ++ avmedia/source/macavf/framegrabber.hxx | 56 ++++ avmedia/source/macavf/framegrabber.mm | 106 ++++++++ avmedia/source/macavf/macavfcommon.hxx | 89 +++++++ avmedia/source/macavf/macavfuno.mm | 55 ++++ avmedia/source/macavf/manager.hxx | 52 ++++ avmedia/source/macavf/manager.mm | 71 +++++ avmedia/source/macavf/player.hxx | 84 ++++++ avmedia/source/macavf/player.mm | 364 ++++++++++++++++++++++++++ avmedia/source/macavf/window.hxx | 111 ++++++++ avmedia/source/macavf/window.mm | 261 ++++++++++++++++++ 11 files changed, 1274 insertions(+) create mode 100644 avmedia/source/macavf/avmediaMacAVF.component create mode 100644 avmedia/source/macavf/framegrabber.hxx create mode 100644 avmedia/source/macavf/framegrabber.mm create mode 100644 avmedia/source/macavf/macavfcommon.hxx create mode 100644 avmedia/source/macavf/macavfuno.mm create mode 100644 avmedia/source/macavf/manager.hxx create mode 100644 avmedia/source/macavf/manager.mm create mode 100644 avmedia/source/macavf/player.hxx create mode 100644 avmedia/source/macavf/player.mm create mode 100644 avmedia/source/macavf/window.hxx create mode 100644 avmedia/source/macavf/window.mm (limited to 'avmedia/source/macavf') diff --git a/avmedia/source/macavf/avmediaMacAVF.component b/avmedia/source/macavf/avmediaMacAVF.component new file mode 100644 index 000000000..376576ff5 --- /dev/null +++ b/avmedia/source/macavf/avmediaMacAVF.component @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/avmedia/source/macavf/framegrabber.hxx b/avmedia/source/macavf/framegrabber.hxx new file mode 100644 index 000000000..0b199991e --- /dev/null +++ b/avmedia/source/macavf/framegrabber.hxx @@ -0,0 +1,56 @@ +/* -*- 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 + +#include + +namespace avmedia::macavf { + +class FrameGrabber : public ::cppu::WeakImplHelper< css::media::XFrameGrabber, + css::lang::XServiceInfo > +{ +public: + + explicit FrameGrabber( const css::uno::Reference< css::lang::XMultiServiceFactory >& ); + 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: + + css::uno::Reference< css::lang::XMultiServiceFactory > mxMgr; + + 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..711800103 --- /dev/null +++ b/avmedia/source/macavf/framegrabber.mm @@ -0,0 +1,106 @@ +/* -*- 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 +#include +#include +#include +#include + +using namespace ::com::sun::star; + +namespace avmedia::macavf { + +FrameGrabber::FrameGrabber( const uno::Reference< lang::XMultiServiceFactory >& /*rxMgr*/ ) +: 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 ); + CGImageDestination* pCGImgDest = CGImageDestinationCreateWithData( pCFData, kUTTypeTIFF, 1, nullptr ); + CGImageDestinationAddImage( pCGImgDest, pCGImage, nullptr ); + CGImageDestinationFinalize( pCGImgDest ); + CFRelease( pCGImgDest ); + const long nBitmapLen = CFDataGetLength( pCFData ); + UInt8 * pBitmapBytes = const_cast(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..699f495a0 --- /dev/null +++ b/avmedia/source/macavf/macavfcommon.hxx @@ -0,0 +1,89 @@ +/* -*- 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 +#import +#import +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define AVMEDIA_MACAVF_MANAGER_IMPLEMENTATIONNAME "com.sun.star.comp.avmedia.Manager_MacAVF" +#define AVMEDIA_MACAVF_MANAGER_SERVICENAME "com.sun.star.media.Manager_MacAVF" + +#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 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/macavfuno.mm b/avmedia/source/macavf/macavfuno.mm new file mode 100644 index 000000000..dbee2e8ce --- /dev/null +++ b/avmedia/source/macavf/macavfuno.mm @@ -0,0 +1,55 @@ +/* -*- 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 "macavfcommon.hxx" +#include "manager.hxx" +#include + +using namespace ::com::sun::star; + +static uno::Reference< uno::XInterface > create_MediaPlayer( const uno::Reference< lang::XMultiServiceFactory >& rxFact ) +{ + return uno::Reference< uno::XInterface >( *new ::avmedia::macavf::Manager( rxFact ) ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT void* avmediaMacAVF_component_getFactory( const char* pImplName, void* pServiceManager, void* /* pRegistryKey */ ) +{ + uno::Reference< lang::XSingleServiceFactory > xFactory; + void* pRet = nullptr; + + if( rtl_str_compare( pImplName, AVMEDIA_MACAVF_MANAGER_IMPLEMENTATIONNAME ) == 0 ) + { + const OUString aServiceName( AVMEDIA_MACAVF_MANAGER_SERVICENAME ); + + xFactory.set( ::cppu::createSingleFactory( + static_cast< lang::XMultiServiceFactory* >( pServiceManager ), + AVMEDIA_MACAVF_MANAGER_IMPLEMENTATIONNAME, + create_MediaPlayer, uno::Sequence< OUString >( &aServiceName, 1 ) ) ); + } + + if( xFactory.is() ) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + + return pRet; +} + +/* 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..fbdcb61b3 --- /dev/null +++ b/avmedia/source/macavf/manager.hxx @@ -0,0 +1,52 @@ +/* -*- 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 + +#include + + +namespace avmedia::macavf { + +class Manager : public ::cppu::WeakImplHelper< css::media::XManager, + css::lang::XServiceInfo > +{ +public: + + Manager( const css::uno::Reference< css::lang::XMultiServiceFactory >& rxMgr ); + 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; +private: + + css::uno::Reference< css::lang::XMultiServiceFactory > mxMgr; +}; + +} // 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..7f3036c86 --- /dev/null +++ b/avmedia/source/macavf/manager.mm @@ -0,0 +1,71 @@ +/* -*- 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 +#include + +using namespace ::com::sun::star; + +namespace avmedia::macavf { + +Manager::Manager( const uno::Reference< lang::XMultiServiceFactory >& rxMgr ) : + mxMgr( rxMgr ) +{ +} + + +Manager::~Manager() +{} + + +uno::Reference< media::XPlayer > SAL_CALL Manager::createPlayer( const OUString& rURL ) +{ + Player* pPlayer( new Player( mxMgr ) ); + uno::Reference< media::XPlayer > xRet( pPlayer ); + INetURLObject aURL( rURL ); + + if( !pPlayer->create( aURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ) ) ) + xRet.clear(); + + return xRet; +} + + +OUString SAL_CALL Manager::getImplementationName( ) +{ + return AVMEDIA_MACAVF_MANAGER_IMPLEMENTATIONNAME; +} + + +sal_Bool SAL_CALL Manager::supportsService( const OUString& ServiceName ) +{ + return ServiceName == AVMEDIA_MACAVF_MANAGER_SERVICENAME; +} + + +uno::Sequence< OUString > SAL_CALL Manager::getSupportedServiceNames( ) +{ + return { AVMEDIA_MACAVF_MANAGER_SERVICENAME }; +} + +} // namespace avmedia::macavf + +/* 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..b9b49cc8c --- /dev/null +++ b/avmedia/source/macavf/player.hxx @@ -0,0 +1,84 @@ +/* -*- 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 +#include "macavfcommon.hxx" +#include + +#include + +namespace avmedia::macavf { + +class Player +: public MacAVObserverHandler +, public ::cppu::WeakImplHelper< css::media::XPlayer, + css::lang::XServiceInfo > +{ +public: + explicit Player( const css::uno::Reference< css::lang::XMultiServiceFactory >& ); + 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: + css::uno::Reference< css::lang::XMultiServiceFactory > mxMgr; + + 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..dfe558524 --- /dev/null +++ b/avmedia/source/macavf/player.mm @@ -0,0 +1,364 @@ +/* -*- 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 // 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(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( const uno::Reference< lang::XMultiServiceFactory >& rxMgr ) +: mxMgr( rxMgr ) +, 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(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(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([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(nNSViewPtr); + + // check the window parameters + uno::Reference< ::media::XPlayerWindow > xRet; + if( (aSize.Width <= 0) || (aSize.Height <= 0) || (pParentView == nullptr) ) + 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() +{ + uno::Reference< media::XFrameGrabber > xRet; + + FrameGrabber* pGrabber = new FrameGrabber( mxMgr ); + AVAsset* pMovie = [[mpPlayer currentItem] asset]; + if( pGrabber->create( pMovie ) ) + xRet = pGrabber; + + return xRet; +} + + +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..c494b6def --- /dev/null +++ b/avmedia/source/macavf/window.hxx @@ -0,0 +1,111 @@ +/* -*- 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 +#include + +#include + + +@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( const css::uno::Reference< css::lang::XMultiServiceFactory >& i_rxMgr, + 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: + + css::uno::Reference< css::lang::XMultiServiceFactory > mxMgr; + + ::osl::Mutex maMutex; + ::cppu::OMultiTypeInterfaceContainerHelper 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..3c39a0725 --- /dev/null +++ b/avmedia/source/macavf/window.mm @@ -0,0 +1,261 @@ +/* -*- 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 +#include + +#include "window.hxx" +#include "player.hxx" + +using namespace ::com::sun::star; + + +namespace avmedia::macavf { + +Window::Window( const uno::Reference< lang::XMultiServiceFactory >& i_rxMgr, Player& i_rPlayer, NSView* i_pParentView ) +: mxMgr( i_rxMgr ) +, 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::get(), xListener ); +} + + +void SAL_CALL Window::removeWindowListener( const uno::Reference< awt::XWindowListener >& xListener ) +{ + maListeners.removeInterface( cppu::UnoType::get(), xListener ); +} + + +void SAL_CALL Window::addFocusListener( const uno::Reference< awt::XFocusListener >& xListener ) +{ + maListeners.addInterface( cppu::UnoType::get(), xListener ); +} + + +void SAL_CALL Window::removeFocusListener( const uno::Reference< awt::XFocusListener >& xListener ) +{ + maListeners.removeInterface( cppu::UnoType::get(), xListener ); +} + + +void SAL_CALL Window::addKeyListener( const uno::Reference< awt::XKeyListener >& xListener ) +{ + maListeners.addInterface( cppu::UnoType::get(), xListener ); +} + + +void SAL_CALL Window::removeKeyListener( const uno::Reference< awt::XKeyListener >& xListener ) +{ + maListeners.removeInterface( cppu::UnoType::get(), xListener ); +} + + +void SAL_CALL Window::addMouseListener( const uno::Reference< awt::XMouseListener >& xListener ) +{ + maListeners.addInterface( cppu::UnoType::get(), xListener ); +} + + +void SAL_CALL Window::removeMouseListener( const uno::Reference< awt::XMouseListener >& xListener ) +{ + maListeners.removeInterface( cppu::UnoType::get(), xListener ); +} + + +void SAL_CALL Window::addMouseMotionListener( const uno::Reference< awt::XMouseMotionListener >& xListener ) +{ + maListeners.addInterface( cppu::UnoType::get(), xListener ); +} + + +void SAL_CALL Window::removeMouseMotionListener( const uno::Reference< awt::XMouseMotionListener >& xListener ) +{ + maListeners.removeInterface( cppu::UnoType::get(), xListener ); +} + + +void SAL_CALL Window::addPaintListener( const uno::Reference< awt::XPaintListener >& xListener ) +{ + maListeners.addInterface( cppu::UnoType::get(), xListener ); +} + + +void SAL_CALL Window::removePaintListener( const uno::Reference< awt::XPaintListener >& xListener ) +{ + maListeners.removeInterface( cppu::UnoType::get(), xListener ); +} + + +// XComponent + +void SAL_CALL Window::dispose( ) +{ +} + + +void SAL_CALL Window::addEventListener( const uno::Reference< lang::XEventListener >& xListener ) +{ + maListeners.addInterface( cppu::UnoType::get(), xListener ); +} + + +void SAL_CALL Window::removeEventListener( const uno::Reference< lang::XEventListener >& xListener ) +{ + maListeners.removeInterface( cppu::UnoType::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: */ -- cgit v1.2.3