]> git.sesse.net Git - casparcg/blob - core/producer/layer.cpp
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches...
[casparcg] / core / producer / layer.cpp
1 #include "../stdafx.h"\r
2 \r
3 #include "layer.h"\r
4 #include "frame_producer.h"\r
5 \r
6 #include "../video_format.h"\r
7 \r
8 #include <common/concurrency/executor.h>\r
9 #include <common/utility/assert.h>\r
10 #include <common/utility/printable.h>\r
11 \r
12 #include <mixer/frame/draw_frame.h>\r
13 #include <mixer/image/image_mixer.h>\r
14 #include <mixer/audio/audio_mixer.h>\r
15 #include <mixer/audio/audio_transform.h>\r
16 \r
17 #include <tbb/spin_mutex.h>\r
18 \r
19 namespace caspar { namespace core {\r
20 \r
21 class frame_producer_remover\r
22 {\r
23         executor executor_;\r
24         tbb::atomic<int> count_;\r
25 \r
26         void do_remove(safe_ptr<frame_producer>& producer)\r
27         {\r
28                 auto name = producer->print();\r
29                 producer = frame_producer::empty();\r
30                 CASPAR_LOG(info) << name << L" Removed.";\r
31         }\r
32 public:\r
33 \r
34         frame_producer_remover()\r
35         {\r
36                 executor_.start();\r
37                 count_ = 0;\r
38         }\r
39 \r
40         void remove(safe_ptr<frame_producer>&& producer)\r
41         {\r
42                 CASPAR_ASSERT(producer.unique());\r
43                 executor_.begin_invoke(std::bind(&frame_producer_remover::do_remove, this, std::move(producer)));\r
44         }\r
45 };\r
46 \r
47 frame_producer_remover g_remover;\r
48 \r
49 \r
50 struct layer::implementation : boost::noncopyable\r
51 {                               \r
52         mutable tbb::spin_mutex         printer_mutex_;\r
53         printer                                         parent_printer_;\r
54         int                                                     index_;\r
55         \r
56         safe_ptr<frame_producer>        foreground_;\r
57         safe_ptr<frame_producer>        background_;\r
58         safe_ptr<draw_frame>            last_frame_;\r
59         bool                                            is_paused_;\r
60 public:\r
61         implementation(int index, const printer& parent_printer) \r
62                 : parent_printer_(parent_printer)\r
63                 , index_(index)\r
64                 , foreground_(frame_producer::empty())\r
65                 , background_(frame_producer::empty())\r
66                 , last_frame_(draw_frame::empty())\r
67                 , is_paused_(false){}\r
68         \r
69         void load(const safe_ptr<frame_producer>& frame_producer, bool play_on_load)\r
70         {               \r
71                 background_ = frame_producer;\r
72                 is_paused_ = false;\r
73                 if(play_on_load)\r
74                         play();         \r
75         }\r
76 \r
77         void preview(const safe_ptr<frame_producer>& frame_producer)\r
78         {\r
79                 load(frame_producer, true);\r
80                 receive();\r
81                 pause();\r
82         }\r
83         \r
84         void play()\r
85         {                       \r
86                 if(!is_paused_)                 \r
87                 {\r
88                         background_->set_leading_producer(foreground_);\r
89                         foreground_ = background_;\r
90                         CASPAR_LOG(info) << foreground_->print() << L" Added.";\r
91                         background_ = frame_producer::empty();\r
92                 }\r
93                 is_paused_ = false;\r
94         }\r
95 \r
96         void pause()\r
97         {\r
98                 is_paused_ = true;\r
99         }\r
100 \r
101         void stop()\r
102         {\r
103                 pause();\r
104                 last_frame_ = draw_frame::empty();\r
105                 foreground_ = frame_producer::empty();\r
106         }\r
107 \r
108         void clear()\r
109         {               \r
110                 foreground_ = frame_producer::empty();\r
111                 background_ = frame_producer::empty();\r
112                 last_frame_ = draw_frame::empty();\r
113                 is_paused_ = false;\r
114         }\r
115         \r
116         safe_ptr<draw_frame> receive()\r
117         {               \r
118                 if(is_paused_)\r
119                 {\r
120                         last_frame_->get_audio_transform().set_gain(0.0);\r
121                         return last_frame_;\r
122                 }\r
123 \r
124                 try\r
125                 {\r
126                         last_frame_ = foreground_->receive(); \r
127                         if(last_frame_ == draw_frame::eof())\r
128                         {\r
129                                 CASPAR_ASSERT(foreground_ != frame_producer::empty());\r
130 \r
131                                 auto following = foreground_->get_following_producer();\r
132                                 following->set_leading_producer(foreground_);\r
133                                 following->set_parent_printer(boost::bind(&implementation::print, this));\r
134                                 g_remover.remove(std::move(foreground_));\r
135                                 foreground_ = following;\r
136                                 CASPAR_LOG(info) << foreground_->print() << L" Added.";\r
137 \r
138                                 last_frame_ = receive();\r
139                         }\r
140                 }\r
141                 catch(...)\r
142                 {\r
143                         CASPAR_LOG(error) << print() << L" Unhandled Exception: ";\r
144                         CASPAR_LOG_CURRENT_EXCEPTION();\r
145                         stop();\r
146                 }\r
147 \r
148                 return last_frame_;\r
149         }\r
150                 \r
151         std::wstring print() const\r
152         {\r
153                 tbb::spin_mutex::scoped_lock lock(printer_mutex_); // Child-producers may call print asynchronously to the producer thread.\r
154                 return (parent_printer_ ? parent_printer_() + L"/" : L"") + L"layer[" + boost::lexical_cast<std::wstring>(index_) + L"]";\r
155         }\r
156 };\r
157 \r
158 layer::layer(int index, const printer& parent_printer) : impl_(new implementation(index, parent_printer)){}\r
159 layer::layer(layer&& other) : impl_(std::move(other.impl_)){}\r
160 layer& layer::operator=(layer&& other)\r
161 {\r
162         impl_ = std::move(other.impl_);\r
163         return *this;\r
164 }\r
165 void layer::swap(layer& other)\r
166 {\r
167         impl_.swap(other.impl_);\r
168         tbb::spin_mutex::scoped_lock lock(impl_->printer_mutex_);\r
169         std::swap(impl_->parent_printer_, other.impl_->parent_printer_);\r
170         std::swap(impl_->index_, other.impl_->index_);\r
171 }\r
172 void layer::load(const safe_ptr<frame_producer>& frame_producer, bool play_on_load){return impl_->load(frame_producer, play_on_load);}  \r
173 void layer::preview(const safe_ptr<frame_producer>& frame_producer){return impl_->preview(frame_producer);}     \r
174 void layer::play(){impl_->play();}\r
175 void layer::pause(){impl_->pause();}\r
176 void layer::stop(){impl_->stop();}\r
177 void layer::clear(){impl_->clear();}\r
178 safe_ptr<draw_frame> layer::receive() {return impl_->receive();}\r
179 safe_ptr<frame_producer> layer::foreground() const { return impl_->foreground_;}\r
180 safe_ptr<frame_producer> layer::background() const { return impl_->background_;}\r
181 std::wstring layer::print() const { return impl_->print();}\r
182 }}