- _player_video_connection = _player->Video.connect (bind (&Butler::video, this, _1, _2));
- _player_audio_connection = _player->Audio.connect (bind (&Butler::audio, this, _1, _2));
- _player_changed_connection = _player->Changed.connect (bind (&Butler::player_changed, this));
- _thread = new boost::thread (bind (&Butler::thread, this));
+ _player_video_connection = _player.Video.connect(bind(&Butler::video, this, _1, _2));
+ _player_audio_connection = _player.Audio.connect(bind(&Butler::audio, this, _1, _2, _3));
+ _player_text_connection = _player.Text.connect(bind(&Butler::text, this, _1, _2, _3, _4));
+ /* The butler must hear about things first, otherwise it might not sort out suspensions in time for
+ get_video() to be called in response to this signal.
+ */
+ _player_change_connection = _player.Change.connect(bind(&Butler::player_change, this, _1, _2), boost::signals2::at_front);
+ _thread = boost::thread (bind(&Butler::thread, this));
+#ifdef DCPOMATIC_LINUX
+ pthread_setname_np (_thread.native_handle(), "butler");
+#endif
+
+ /* Create some threads to do work on the PlayerVideos we are creating; at present this is used to
+ multi-thread JPEG2000 decoding.
+ */
+
+ LOG_TIMING("start-prepare-threads %1", boost::thread::hardware_concurrency() * 2);
+
+ for (size_t i = 0; i < boost::thread::hardware_concurrency() * 2; ++i) {
+ _prepare_pool.create_thread (bind (&boost::asio::io_service::run, &_prepare_service));
+ }