1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
/*
Copyright (C) 2016-2017 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
DCP-o-matic is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
DCP-o-matic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
*/
#include "video_ring_buffers.h"
#include "audio_ring_buffers.h"
#include "text_ring_buffers.h"
#include "audio_mapping.h"
#include "exception_store.h"
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/thread/condition.hpp>
#include <boost/signals2.hpp>
#include <boost/asio.hpp>
class Player;
class PlayerVideo;
class Butler : public ExceptionStore, public boost::noncopyable
{
public:
Butler (
boost::shared_ptr<Player> player,
AudioMapping map,
int audio_channels,
boost::function<AVPixelFormat (AVPixelFormat)> pixel_format,
bool aligned,
bool fast
);
~Butler ();
void seek (dcpomatic::DCPTime position, bool accurate);
class Error {
public:
enum Code{
NONE,
AGAIN,
DIED,
FINISHED
};
Error()
: code (NONE)
{}
Code code;
std::string message;
std::string summary () const;
};
std::pair<boost::shared_ptr<PlayerVideo>, dcpomatic::DCPTime> get_video (bool blocking, Error* e = 0);
boost::optional<dcpomatic::DCPTime> get_audio (float* out, Frame frames);
boost::optional<TextRingBuffers::Data> get_closed_caption ();
void disable_audio ();
std::pair<size_t, std::string> memory_used () const;
private:
void thread ();
void video (boost::shared_ptr<PlayerVideo> video, dcpomatic::DCPTime time);
void audio (boost::shared_ptr<AudioBuffers> audio, dcpomatic::DCPTime time, int frame_rate);
void text (PlayerText pt, TextType type, boost::optional<DCPTextTrack> track, dcpomatic::DCPTimePeriod period);
bool should_run () const;
void prepare (boost::weak_ptr<PlayerVideo> video);
void player_change (ChangeType type);
void seek_unlocked (dcpomatic::DCPTime position, bool accurate);
boost::shared_ptr<Player> _player;
boost::thread _thread;
VideoRingBuffers _video;
AudioRingBuffers _audio;
TextRingBuffers _closed_caption;
boost::thread_group _prepare_pool;
boost::asio::io_service _prepare_service;
boost::shared_ptr<boost::asio::io_service::work> _prepare_work;
/** mutex to protect _pending_seek_position, _pending_seek_accurate, _finished, _died, _stop_thread */
boost::mutex _mutex;
boost::condition _summon;
boost::condition _arrived;
boost::optional<dcpomatic::DCPTime> _pending_seek_position;
bool _pending_seek_accurate;
int _suspended;
bool _finished;
bool _died;
std::string _died_message;
bool _stop_thread;
AudioMapping _audio_mapping;
int _audio_channels;
bool _disable_audio;
boost::function<AVPixelFormat (AVPixelFormat)> _pixel_format;
bool _aligned;
bool _fast;
/** If we are waiting to be refilled following a seek, this is the time we were
seeking to.
*/
boost::optional<dcpomatic::DCPTime> _awaiting;
boost::signals2::scoped_connection _player_video_connection;
boost::signals2::scoped_connection _player_audio_connection;
boost::signals2::scoped_connection _player_text_connection;
boost::signals2::scoped_connection _player_change_connection;
};
|