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