]> git.sesse.net Git - casparcg/blob - modules/newtek/consumer/newtek_ivga_consumer.cpp
#187
[casparcg] / modules / newtek / consumer / newtek_ivga_consumer.cpp
1 /*
2 * Copyright 2013 NewTek
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Robert Nagy, ronag@live.com
20 */
21  
22 #include "../StdAfx.h"
23
24 #include "newtek_ivga_consumer.h"
25
26 #include <core/consumer/frame_consumer.h>
27 #include <core/parameters/parameters.h>
28 #include <core/video_format.h>
29 #include <core/mixer/read_frame.h>
30
31 #include <common/utility/assert.h>
32 #include <common/concurrency/executor.h>
33
34 #include <boost/algorithm/string.hpp>
35
36 #include "../util/air_send.h"
37
38 namespace caspar { namespace newtek {
39
40 struct newtek_ivga_consumer : public core::frame_consumer
41 {
42         std::shared_ptr<void>   air_send_;
43         core::video_format_desc format_desc_;
44         core::channel_layout    channel_layout_;
45         executor                                executor_;
46
47 public:
48
49         newtek_ivga_consumer(core::channel_layout channel_layout)
50                 : executor_(print())
51                 , channel_layout_(channel_layout)
52         {
53                 if (!airsend::is_available())
54                         BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(airsend::dll_name()) + " not available"));
55         }
56         
57         ~newtek_ivga_consumer()
58         {
59         }
60
61         // frame_consumer
62         
63         virtual void initialize(const core::video_format_desc& format_desc, int channel_index) override
64         {
65                 air_send_.reset(
66                         airsend::create(
67                                 format_desc.width,
68                                 format_desc.height,
69                                 format_desc.time_scale,
70                                 format_desc.duration,
71                                 format_desc.field_mode == core::field_mode::progressive,
72                                 static_cast<float>(format_desc.square_width) / static_cast<float>(format_desc.square_height),
73                                 true,
74                                 channel_layout_.num_channels,
75                                 format_desc.audio_sample_rate),
76                                 airsend::destroy);
77
78                 CASPAR_VERIFY(air_send_);
79
80                 format_desc_ = format_desc;
81
82                 CASPAR_LOG(info) << print() << L" Successfully Initialized.";   
83         }
84
85         virtual boost::unique_future<bool> send(const safe_ptr<core::read_frame>& frame) override
86         {
87                 CASPAR_VERIFY(format_desc_.height * format_desc_.width * 4 == static_cast<unsigned>(frame->image_data().size()));
88
89                 return executor_.begin_invoke([=]() -> bool
90                 {                       
91                         // AUDIO
92
93                         std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>> audio_buffer;
94
95                         if (core::needs_rearranging(
96                                         frame->multichannel_view(),
97                                         channel_layout_,
98                                         channel_layout_.num_channels))
99                         {
100                                 core::audio_buffer downmixed;
101
102                                 downmixed.resize(
103                                                 frame->multichannel_view().num_samples() 
104                                                                 * channel_layout_.num_channels,
105                                                 0);
106
107                                 auto dest_view = core::make_multichannel_view<int32_t>(
108                                                 downmixed.begin(), downmixed.end(), channel_layout_);
109
110                                 core::rearrange_or_rearrange_and_mix(
111                                                 frame->multichannel_view(),
112                                                 dest_view,
113                                                 core::default_mix_config_repository());
114
115                                 audio_buffer = core::audio_32_to_16(downmixed);
116                         }
117                         else
118                         {
119                                 audio_buffer = core::audio_32_to_16(frame->audio_data());
120                         }
121
122                         airsend::add_audio(air_send_.get(), audio_buffer.data(), audio_buffer.size() / channel_layout_.num_channels);
123
124                         // VIDEO
125
126                         airsend::add_frame_bgra(air_send_.get(), frame->image_data().begin());
127                         
128                         return true;
129                 });
130         }
131                 
132         virtual std::wstring print() const override
133         {
134                 return L"newtek-ivga";
135         }
136
137         virtual boost::property_tree::wptree info() const override
138         {
139                 boost::property_tree::wptree info;
140                 info.add(L"type", L"newtek-ivga-consumer");
141                 return info;
142         }
143
144         virtual size_t buffer_depth() const override
145         {
146                 return 0;
147         }
148         
149         virtual int index() const override
150         {
151                 return 900;
152         }
153
154         virtual int64_t presentation_frame_age_millis() const override
155         {
156                 return 0;
157         }
158 };      
159
160 safe_ptr<core::frame_consumer> create_ivga_consumer(const core::parameters& params)
161 {
162         if(params.size() < 1 || params[0] != L"NEWTEK_IVGA")
163                 return core::frame_consumer::empty();
164                 
165         const auto channel_layout = core::default_channel_layout_repository()
166                 .get_by_name(
167                         params.get(L"CHANNEL_LAYOUT", L"STEREO"));
168
169         return make_safe<newtek_ivga_consumer>(channel_layout);
170 }
171
172 safe_ptr<core::frame_consumer> create_ivga_consumer(const boost::property_tree::wptree& ptree) 
173 {       
174         const auto channel_layout =
175                 core::default_channel_layout_repository()
176                         .get_by_name(
177                                 boost::to_upper_copy(ptree.get(L"channel-layout", L"STEREO")));
178
179         return make_safe<newtek_ivga_consumer>(channel_layout);
180 }
181
182 }}