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