]> git.sesse.net Git - casparcg/blob - mixer/frame_mixer_device.cpp
adbd1bb531974b0853fc5ea13425e9baedc57a0d
[casparcg] / mixer / frame_mixer_device.cpp
1 #include "StdAfx.h"\r
2 \r
3 #include "frame_mixer_device.h"\r
4 \r
5 #include "audio/audio_mixer.h"\r
6 #include "audio/audio_transform.h"\r
7 #include "frame/write_frame.h"\r
8 #include "frame/read_frame.h"\r
9 #include "image/image_mixer.h"\r
10 #include "image/image_transform.h"\r
11 \r
12 #include <common/exception/exceptions.h>\r
13 #include <common/concurrency/executor.h>\r
14 #include <common/diagnostics/graph.h>\r
15 #include <common/utility/timer.h>\r
16 #include <common/gl/gl_check.h>\r
17 \r
18 #include <core/video_format.h>\r
19 \r
20 #include <tbb/concurrent_queue.h>\r
21 #include <tbb/concurrent_unordered_map.h>\r
22 \r
23 #include <boost/range/algorithm.hpp>\r
24 \r
25 #include <unordered_map>\r
26 \r
27 namespace caspar { namespace core {\r
28         \r
29 struct frame_mixer_device::implementation : boost::noncopyable\r
30 {               \r
31         const video_format_desc format_desc_;\r
32 \r
33         safe_ptr<diagnostics::graph> graph_;\r
34         timer perf_timer_;\r
35         timer wait_perf_timer_;\r
36 \r
37         audio_mixer     audio_mixer_;\r
38         image_mixer image_mixer_;\r
39 \r
40         output_func output_;\r
41 \r
42         std::unordered_map<int, image_transform> image_transforms_;\r
43         std::unordered_map<int, audio_transform> audio_transforms_;\r
44 \r
45         executor executor_;\r
46 public:\r
47         implementation(const video_format_desc& format_desc, const output_func& output) \r
48                 : format_desc_(format_desc)\r
49                 , graph_(diagnostics::create_graph(narrow(print())))\r
50                 , image_mixer_(format_desc)\r
51                 , output_(output)\r
52                 , executor_(L"frame_mixer_device")\r
53         {\r
54                 graph_->guide("frame-time", 0.5f);      \r
55                 graph_->set_color("frame-time", diagnostics::color(1.0f, 0.0f, 0.0f));\r
56                 graph_->set_color("tick-time", diagnostics::color(0.1f, 0.7f, 0.8f));\r
57                 graph_->set_color("input-buffer", diagnostics::color(1.0f, 1.0f, 0.0f));                \r
58                 executor_.start();\r
59                 executor_.set_capacity(2);\r
60                 CASPAR_LOG(info) << print() << L" Successfully initialized.";   \r
61         }\r
62                 \r
63         ~implementation()\r
64         {\r
65                 CASPAR_LOG(info) << print() << L" Shutting down.";      \r
66         }\r
67 \r
68         void send(const std::vector<safe_ptr<draw_frame>>& frames)\r
69         {                       \r
70                 executor_.begin_invoke([=]\r
71                 {\r
72                         perf_timer_.reset();\r
73                         auto image = image_mixer_.begin_pass();\r
74                         BOOST_FOREACH(auto& frame, frames)\r
75                         {\r
76                                 image_mixer_.begin(image_transforms_[frame->get_layer_index()]);\r
77                                 frame->process_image(image_mixer_);\r
78                                 image_mixer_.end();\r
79                         }\r
80                         image_mixer_.end_pass();\r
81 \r
82                         auto audio = audio_mixer_.begin_pass();\r
83                         BOOST_FOREACH(auto& frame, frames)\r
84                         {\r
85                                 audio_mixer_.begin(audio_transforms_[frame->get_layer_index()]);\r
86                                 frame->process_audio(audio_mixer_);\r
87                                 audio_mixer_.end();\r
88                         }\r
89                         audio_mixer_.end_pass();\r
90                         graph_->update("frame-time", static_cast<float>(perf_timer_.elapsed()/format_desc_.interval*0.5));\r
91 \r
92                         output_(make_safe<const read_frame>(std::move(image.get()), std::move(audio)));\r
93                         graph_->update("tick-time", static_cast<float>(wait_perf_timer_.elapsed()/format_desc_.interval*0.5));\r
94                         wait_perf_timer_.reset();\r
95 \r
96                         graph_->set("input-buffer", static_cast<float>(executor_.size())/static_cast<float>(executor_.capacity()));\r
97                 });\r
98                 graph_->set("input-buffer", static_cast<float>(executor_.size())/static_cast<float>(executor_.capacity()));\r
99         }\r
100                 \r
101         safe_ptr<write_frame> create_frame(const pixel_format_desc& desc)\r
102         {\r
103                 return make_safe<write_frame>(desc, image_mixer_.create_buffers(desc));\r
104         }\r
105                 \r
106         image_transform get_image_transform(int index)\r
107         {\r
108                 return executor_.invoke([&]{return image_transforms_[index];});\r
109         }\r
110 \r
111         audio_transform get_audio_transform(int index)\r
112         {\r
113                 return executor_.invoke([&]{return audio_transforms_[index];});\r
114         }\r
115 \r
116         void set_image_transform(int index, image_transform&& transform)\r
117         {\r
118                 return executor_.invoke([&]{image_transforms_[index] = std::move(transform);});\r
119         }\r
120 \r
121         void set_audio_transform(int index, audio_transform&& transform)\r
122         {\r
123                 return executor_.invoke([&]{audio_transforms_[index] = std::move(transform);});\r
124         }\r
125 \r
126         std::wstring print() const\r
127         {\r
128                 return L"Video/Audio Mixer [" + format_desc_.name + L"]";\r
129         }\r
130 };\r
131         \r
132 frame_mixer_device::frame_mixer_device(const video_format_desc& format_desc, const output_func& output) : impl_(new implementation(format_desc, output)){}\r
133 frame_mixer_device::frame_mixer_device(frame_mixer_device&& other) : impl_(std::move(other.impl_)){}\r
134 void frame_mixer_device::send(const std::vector<safe_ptr<draw_frame>>& frames){impl_->send(frames);}\r
135 const video_format_desc& frame_mixer_device::get_video_format_desc() const { return impl_->format_desc_; }\r
136 safe_ptr<write_frame> frame_mixer_device::create_frame(const pixel_format_desc& desc){ return impl_->create_frame(desc); }              \r
137 safe_ptr<write_frame> frame_mixer_device::create_frame(size_t width, size_t height, pixel_format::type pix_fmt)\r
138 {\r
139         // Create bgra frame\r
140         pixel_format_desc desc;\r
141         desc.pix_fmt = pix_fmt;\r
142         desc.planes.push_back(pixel_format_desc::plane(width, height, 4));\r
143         return create_frame(desc);\r
144 }\r
145                         \r
146 safe_ptr<write_frame> frame_mixer_device::create_frame(pixel_format::type pix_fmt)\r
147 {\r
148         // Create bgra frame with output resolution\r
149         pixel_format_desc desc;\r
150         desc.pix_fmt = pix_fmt;\r
151         desc.planes.push_back(pixel_format_desc::plane(get_video_format_desc().width, get_video_format_desc().height, 4));\r
152         return create_frame(desc);\r
153 }\r
154 image_transform frame_mixer_device::get_image_transform(int index){return impl_->get_image_transform(index);}\r
155 audio_transform frame_mixer_device::get_audio_transform(int index){return impl_->get_audio_transform(index);}\r
156 void frame_mixer_device::set_image_transform(int index, image_transform&& transform){impl_->set_image_transform(index, std::move(transform));}\r
157 void frame_mixer_device::set_audio_transform(int index, audio_transform&& transform){impl_->set_audio_transform(index, std::move(transform));}\r
158 \r
159 }}