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