]> git.sesse.net Git - casparcg/blob - mixer/frame_mixer_device.cpp
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches...
[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         safe_ptr<diagnostics::graph> graph_;\r
32         timer perf_timer_;\r
33         timer wait_perf_timer_;\r
34 \r
35         const video_format_desc format_desc_;\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                 : graph_(diagnostics::create_graph("mixer"))\r
49                 , format_desc_(format_desc)\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("output-wait", diagnostics::color(0.1f, 0.7f, 0.8f));\r
57                 graph_->set_color("output-buffer", diagnostics::color( 0.0f, 1.0f, 0.0f));              \r
58                 executor_.start();\r
59                 executor_.set_capacity(2);\r
60         }\r
61                 \r
62         ~implementation()\r
63         {\r
64                 CASPAR_LOG(info) << "Shutting down mixer-device.";\r
65         }\r
66 \r
67         void send(const std::vector<safe_ptr<draw_frame>>& frames)\r
68         {                       \r
69                 executor_.begin_invoke([=]\r
70                 {\r
71                         perf_timer_.reset();\r
72                         auto image = image_mixer_.begin_pass();\r
73                         BOOST_FOREACH(auto& frame, frames)\r
74                         {\r
75                                 image_mixer_.begin(image_transforms_[frame->get_layer_index()]);\r
76                                 frame->process_image(image_mixer_);\r
77                                 image_mixer_.end();\r
78                         }\r
79                         image_mixer_.end_pass();\r
80 \r
81                         auto audio = audio_mixer_.begin_pass();\r
82                         BOOST_FOREACH(auto& frame, frames)\r
83                         {\r
84                                 audio_mixer_.begin(audio_transforms_[frame->get_layer_index()]);\r
85                                 frame->process_audio(audio_mixer_);\r
86                                 audio_mixer_.end();\r
87                         }\r
88                         audio_mixer_.end_pass();\r
89                         graph_->update("frame-time", static_cast<float>(perf_timer_.elapsed()/format_desc_.interval*0.5));\r
90 \r
91                         wait_perf_timer_.reset();\r
92                         output_(make_safe<const read_frame>(std::move(image.get()), std::move(audio)));\r
93                         graph_->update("output-wait", static_cast<float>(wait_perf_timer_.elapsed()/format_desc_.interval*0.5));\r
94                 });\r
95                 graph_->update("output-buffer", static_cast<float>(executor_.size())/static_cast<float>(executor_.capacity()));\r
96         }\r
97                 \r
98         safe_ptr<write_frame> create_frame(const pixel_format_desc& desc)\r
99         {\r
100                 return make_safe<write_frame>(desc, image_mixer_.create_buffers(desc));\r
101         }\r
102                 \r
103         image_transform get_image_transform(int index)\r
104         {\r
105                 return executor_.invoke([&]{return image_transforms_[index];});\r
106         }\r
107 \r
108         audio_transform get_audio_transform(int index)\r
109         {\r
110                 return executor_.invoke([&]{return audio_transforms_[index];});\r
111         }\r
112 \r
113         void set_image_transform(int index, image_transform&& transform)\r
114         {\r
115                 return executor_.invoke([&]{image_transforms_[index] = std::move(transform);});\r
116         }\r
117 \r
118         void set_audio_transform(int index, audio_transform&& transform)\r
119         {\r
120                 return executor_.invoke([&]{audio_transforms_[index] = std::move(transform);});\r
121         }\r
122 };\r
123         \r
124 frame_mixer_device::frame_mixer_device(const video_format_desc& format_desc, const output_func& output) : impl_(new implementation(format_desc, output)){}\r
125 frame_mixer_device::frame_mixer_device(frame_mixer_device&& other) : impl_(std::move(other.impl_)){}\r
126 void frame_mixer_device::send(const std::vector<safe_ptr<draw_frame>>& frames){impl_->send(frames);}\r
127 const video_format_desc& frame_mixer_device::get_video_format_desc() const { return impl_->format_desc_; }\r
128 safe_ptr<write_frame> frame_mixer_device::create_frame(const pixel_format_desc& desc){ return impl_->create_frame(desc); }              \r
129 safe_ptr<write_frame> frame_mixer_device::create_frame(size_t width, size_t height, pixel_format::type pix_fmt)\r
130 {\r
131         // Create bgra frame\r
132         pixel_format_desc desc;\r
133         desc.pix_fmt = pix_fmt;\r
134         desc.planes.push_back(pixel_format_desc::plane(width, height, 4));\r
135         return create_frame(desc);\r
136 }\r
137                         \r
138 safe_ptr<write_frame> frame_mixer_device::create_frame(pixel_format::type pix_fmt)\r
139 {\r
140         // Create bgra frame with output resolution\r
141         pixel_format_desc desc;\r
142         desc.pix_fmt = pix_fmt;\r
143         desc.planes.push_back(pixel_format_desc::plane(get_video_format_desc().width, get_video_format_desc().height, 4));\r
144         return create_frame(desc);\r
145 }\r
146 image_transform frame_mixer_device::get_image_transform(int index){return impl_->get_image_transform(index);}\r
147 audio_transform frame_mixer_device::get_audio_transform(int index){return impl_->get_audio_transform(index);}\r
148 void frame_mixer_device::set_image_transform(int index, image_transform&& transform){impl_->set_image_transform(index, std::move(transform));}\r
149 void frame_mixer_device::set_audio_transform(int index, audio_transform&& transform){impl_->set_audio_transform(index, std::move(transform));}\r
150 \r
151 }}