Skip to content

Commit 331ce38

Browse files
committed
Added the ability to manage the lifetime of MediaFoundation manually. Previously MediaFoundation was started up and shutdown automatically when the first and last MediaPlayer instance was created and deleted respectively, however these are heavy blocking operations and can introduce noticeable hitches. You can now opt out of the automatic management with MediaPlayer::Format::AutoInitialize(), however you are then required to manually call MediaPlayer::StaticInitialize() / MediaPlayer::StaticShutdown() at the beginning and end of your app's lifetime. This is useful when your application creates and deletes a lot of video player instances. Affects the MF backend only, on macOS this is a no-op.
1 parent ba7973a commit 331ce38

File tree

4 files changed

+47
-3
lines changed

4 files changed

+47
-3
lines changed

src/AX-MediaPlayer.cxx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ namespace AX
5656
return *this;
5757
}
5858

59+
void MediaPlayer::StaticInitialize ( )
60+
{
61+
MediaPlayer::Impl::StaticInitialize ( );
62+
}
63+
64+
void MediaPlayer::StaticShutdown ( )
65+
{
66+
MediaPlayer::Impl::StaticShutdown ( );
67+
}
68+
5969
MediaPlayerRef MediaPlayer::Create ( const ci::DataSourceRef & source, const MediaPlayer::Format& fmt )
6070
{
6171
return MediaPlayerRef ( new MediaPlayer ( source, fmt ) );

src/AX-MediaPlayer.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,13 @@ namespace AX::Video
6262
Format & AudioOnly ( bool audioOnly ) { _audioOnly = audioOnly; return *this; }
6363
Format & AudioDevice ( const ci::audio::DeviceFwdRef & device );
6464
Format & HardwareAccelerated ( bool accelerated ) { _hardwareAccelerated = accelerated; return *this; }
65+
Format & AutoInitialize ( bool autoInit ) { _autoInit = autoInit; return *this; }
6566

6667
bool IsAudioEnabled ( ) const { return _audioEnabled; }
6768
bool IsAudioOnly ( ) const { return _audioOnly; }
6869
bool IsHardwareAccelerated ( ) const { return _hardwareAccelerated; }
6970
const std::string & AudioDeviceID ( ) const { return _audioDeviceId; }
71+
bool IsAutoInitialized ( ) const { return _autoInit; };
7072

7173
Format ( ) { };
7274

@@ -76,6 +78,7 @@ namespace AX::Video
7678
bool _audioOnly{ false };
7779
bool _hardwareAccelerated{ false };
7880
std::string _audioDeviceId{ "" };
81+
bool _autoInit{ true };
7982
};
8083

8184
using FrameLeaseRef = std::unique_ptr<FrameLease>;
@@ -85,6 +88,13 @@ namespace AX::Video
8588

8689
static MediaPlayerRef Create ( const ci::DataSourceRef & source, const Format & fmt = Format ( ) );
8790
static MediaPlayerRef Create ( const ci::fs::path & filePath, const Format & fmt = Format ( ) );
91+
92+
// @note(andrew): If !fmt.IsAutoInitialized(), these are required to be called manually.
93+
// The use case is to have any heavy initialization / shutdown not be tied to the lifetime
94+
// of a specific MediaPlayer instance to remove hitches when creating and destroying
95+
// video players often.
96+
static void StaticInitialize ( );
97+
static void StaticShutdown ( );
8898

8999
static const std::string & ErrorToString ( Error error );
90100
inline const Format & GetFormat ( ) const { return _format; }

src/msw/AX-MediaPlayerMSWImpl.cxx

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,13 @@ using namespace ci;
2828
namespace
2929
{
3030
static std::atomic_int kNumMediaFoundationInstances = 0;
31+
static std::atomic_bool kIsMFInitialized = false;
3132

3233
static void OnMediaPlayerCreated ( )
3334
{
3435
if ( kNumMediaFoundationInstances++ == 0 )
3536
{
36-
MFStartup ( MF_VERSION );
37+
kIsMFInitialized = SUCCEEDED ( MFStartup ( MF_VERSION ) );
3738
}
3839
}
3940

@@ -42,6 +43,7 @@ namespace
4243
if ( --kNumMediaFoundationInstances == 0 )
4344
{
4445
MFShutdown ( );
46+
kIsMFInitialized = false;
4547
}
4648
}
4749

@@ -259,12 +261,31 @@ namespace AX::Video
259261
app::App::get ( )->dispatchSync ( [&] { callback ( ); } );
260262
}
261263

264+
void MediaPlayer::Impl::StaticInitialize ( )
265+
{
266+
if ( !kIsMFInitialized )
267+
{
268+
kIsMFInitialized = SUCCEEDED (MFStartup (MF_VERSION));
269+
}
270+
}
271+
272+
void MediaPlayer::Impl::StaticShutdown ( )
273+
{
274+
if ( kIsMFInitialized ) MFShutdown ( );
275+
kIsMFInitialized = false;
276+
}
277+
262278
MediaPlayer::Impl::Impl ( MediaPlayer & owner, const DataSourceRef & source, const Format& format )
263279
: _owner ( owner )
264280
, _source ( source )
265281
, _format( format )
266282
{
267-
OnMediaPlayerCreated ( );
283+
if ( _format.IsAutoInitialized() ) OnMediaPlayerCreated ();
284+
if ( !kIsMFInitialized )
285+
{
286+
throw std::runtime_error ("MediaFoundation not initialized! Set MediaPlayer::Format::AutoInitialize or call MediaPlayer::StaticInitialize() to manually manage lifetime!");
287+
return;
288+
}
268289

269290
ComPtr<IMFMediaEngineClassFactory> factory;
270291
if ( SUCCEEDED ( CoCreateInstance ( CLSID_MFMediaEngineClassFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS ( &factory ) ) ) )
@@ -745,6 +766,6 @@ namespace AX::Video
745766
_mediaEngine = nullptr;
746767
}
747768

748-
OnMediaPlayerDestroyed ( );
769+
if ( _format.IsAutoInitialized() ) OnMediaPlayerDestroyed ( );
749770
}
750771
}

src/msw/AX-MediaPlayerMSWImpl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ namespace AX::Video
7474
friend class DXGIRenderPath;
7575
friend class WICRenderPath;
7676

77+
static void StaticInitialize ( );
78+
static void StaticShutdown ( );
79+
7780
Impl ( MediaPlayer & owner, const ci::DataSourceRef & source, const Format& format );
7881

7982
bool Update ( );

0 commit comments

Comments
 (0)