#include "butler.h"
-#include "player.h"
-#include "util.h"
-#include "log.h"
-#include "dcpomatic_log.h"
-#include "cross.h"
#include "compose.hpp"
+#include "cross.h"
+#include "dcpomatic_log.h"
#include "exceptions.h"
+#include "log.h"
+#include "player.h"
+#include "util.h"
#include "video_content.h"
using std::cout;
-using std::pair;
+using std::function;
using std::make_pair;
+using std::pair;
+using std::shared_ptr;
using std::string;
using std::weak_ptr;
-using std::shared_ptr;
using boost::bind;
using boost::optional;
-using std::function;
using namespace dcpomatic;
#if BOOST_VERSION >= 106100
using namespace boost::placeholders;
*/
Butler::Butler (
weak_ptr<const Film> film,
- shared_ptr<Player> player,
+ Player& player,
AudioMapping audio_mapping,
int audio_channels,
function<AVPixelFormat (AVPixelFormat)> pixel_format,
VideoRange video_range,
Image::Alignment alignment,
bool fast,
- bool prepare_only_proxy
+ bool prepare_only_proxy,
+ Audio audio
)
: _film (film)
, _player (player)
, _stop_thread (false)
, _audio_mapping (audio_mapping)
, _audio_channels (audio_channels)
- , _disable_audio (false)
+ , _disable_audio (audio == Audio::DISABLED)
, _pixel_format (pixel_format)
, _video_range (video_range)
, _alignment (alignment)
, _fast (fast)
, _prepare_only_proxy (prepare_only_proxy)
{
- _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));
+ _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);
+ _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");
if (_audio.size() >= MAXIMUM_AUDIO_READAHEAD * 10) {
/* This is way too big */
- optional<DCPTime> pos = _audio.peek();
+ auto pos = _audio.peek();
if (pos) {
throw ProgrammingError
(__FILE__, __LINE__, String::compose ("Butler audio buffers reached %1 frames at %2 (video is %3)", _audio.size(), pos->get(), _video.size()));
/* Do any seek that has been requested */
if (_pending_seek_position) {
_finished = false;
- _player->seek (*_pending_seek_position, _pending_seek_accurate);
+ _player.seek(*_pending_seek_position, _pending_seek_accurate);
_pending_seek_position = optional<DCPTime> ();
}
*/
while (should_run() && !_pending_seek_position) {
lm.unlock ();
- bool const r = _player->pass ();
+ bool const r = _player.pass();
lm.lock ();
if (r) {
_finished = true;
}
-/** @param blocking true if we should block until video is available. If blocking is false
+/** @param behaviour BLOCKING if we should block until video is available. If behaviour is NON_BLOCKING
* and no video is immediately available the method will return a 0 PlayerVideo and the error AGAIN.
* @param e if non-0 this is filled with an error code (if an error occurs) or is untouched if no error occurs.
*/
pair<shared_ptr<PlayerVideo>, DCPTime>
-Butler::get_video (bool blocking, Error* e)
+Butler::get_video (Behaviour behaviour, Error* e)
{
boost::mutex::scoped_lock lm (_mutex);
}
};
- if (_video.empty() && (_finished || _died || (_suspended && !blocking))) {
+ if (_video.empty() && (_finished || _died || (_suspended && behaviour == Behaviour::NON_BLOCKING))) {
setup_error (e, Error::Code::AGAIN);
return make_pair(shared_ptr<PlayerVideo>(), DCPTime());
}
}
-/** Try to get `frames' frames of audio and copy it into `out'. Silence
- * will be filled if no audio is available.
- * @return time of this audio, or unset if there was a buffer underrun.
+/** Try to get `frames' frames of audio and copy it into `out'.
+ * @param behaviour BLOCKING if we should block until audio is available. If behaviour is NON_BLOCKING
+ * and no audio is immediately available the buffer will be filled with silence and boost::none
+ * will be returned.
+ * @return time of this audio, or unset if blocking was false and no data was available.
*/
optional<DCPTime>
-Butler::get_audio (float* out, Frame frames)
+Butler::get_audio (Behaviour behaviour, float* out, Frame frames)
{
+ boost::mutex::scoped_lock lm (_mutex);
+
+ while (behaviour == Behaviour::BLOCKING && !_finished && !_died && _audio.size() < frames) {
+ _arrived.wait (lm);
+ }
+
auto t = _audio.get (out, _audio_channels, frames);
_summon.notify_all ();
return t;
}
-void
-Butler::disable_audio ()
-{
- boost::mutex::scoped_lock lm (_mutex);
- _disable_audio = true;
-}
-
-
pair<size_t, string>
Butler::memory_used () const
{
if (type == ChangeType::DONE) {
auto film = _film.lock();
if (film) {
- _video.reset_metadata (film, _player->video_container_size());
+ _video.reset_metadata(film, _player.video_container_size());
}
}
return;