]> git.sesse.net Git - casparcg/commitdiff
* Merged newtek iVGA consumer from 2.0.
authorHelge Norberg <helge.norberg@svt.se>
Mon, 15 Jun 2015 13:53:11 +0000 (15:53 +0200)
committerHelge Norberg <helge.norberg@svt.se>
Mon, 15 Jun 2015 14:03:59 +0000 (16:03 +0200)
* Merged possibility for consumers to not participate in frame presentation time synchronization by returning -1 as buffer depth, allowing for unnecessary lags to be avoided when adding/removing consumers that are not expected to present video/audio at a specific time.
* Fixed counter initialization in async destruction proxies (this time it should be fixed).

17 files changed:
core/consumer/frame_consumer.cpp
core/consumer/frame_consumer.h
core/consumer/output.cpp
core/producer/frame_producer.cpp
modules/CMakeLists.txt
modules/ffmpeg/consumer/ffmpeg_consumer.cpp
modules/image/consumer/image_consumer.cpp
modules/newtek/CMakeLists.txt [new file with mode: 0644]
modules/newtek/StdAfx.cpp [new file with mode: 0644]
modules/newtek/StdAfx.h [new file with mode: 0644]
modules/newtek/consumer/newtek_ivga_consumer.cpp [new file with mode: 0644]
modules/newtek/consumer/newtek_ivga_consumer.h [new file with mode: 0644]
modules/newtek/newtek.cpp [new file with mode: 0644]
modules/newtek/newtek.h [new file with mode: 0644]
modules/newtek/util/air_send.cpp [new file with mode: 0644]
modules/newtek/util/air_send.h [new file with mode: 0644]
shell/casparcg.config

index 214b53f0347d2e1ade898b9db6ca1504244db971..ccafbc6b31440c8569969f6878ab755218d9d36e 100644 (file)
@@ -63,12 +63,9 @@ public:
 
        ~destroy_consumer_proxy()
        {               
-               static tbb::atomic<int> counter = []
-               {
-                       tbb::atomic<int> c;
-                       c = 0;
-                       return c;
-               }();
+               static tbb::atomic<int> counter;
+               static std::once_flag counter_init_once;
+               std::call_once(counter_init_once, []{ counter = 0; });
                        
                ++counter;
                CASPAR_VERIFY(counter < 8);
index 39ffba2d5e711fde56b0e99393a282d31e4bb14b..a8a1638ba440b3cd659714c3aa3ecaf60a39b7f8 100644 (file)
@@ -67,7 +67,7 @@ public:
        virtual std::wstring                                    name() const = 0;
        virtual boost::property_tree::wptree    info() const = 0;
        virtual bool                                                    has_synchronization_clock() const {return true;}
-       virtual int                                                             buffer_depth() const = 0;
+       virtual int                                                             buffer_depth() const = 0; // -1 to not participate in frame presentation synchronization
        virtual int                                                             index() const = 0;
 };
 
index dac35395dc880ae90e3aa01ac1fcb50a40368caf..d939cca3a4ac8bfc740148919359adcd053e6efc 100644 (file)
@@ -139,6 +139,7 @@ public:
                return cpplinq::from(ports_)
                        .select(values())
                        .select(std::mem_fn(&port::buffer_depth))
+                       .where([](int v) { return v >= 0; })
                        .aggregate(minmax::initial_value<int>(), minmax());
        }
 
@@ -182,7 +183,8 @@ public:
                        for (auto it = ports_.begin(); it != ports_.end();)
                        {
                                auto& port      = it->second;
-                               auto& frame     = frames_.at(port.buffer_depth()-minmax.first);
+                               auto depth = port.buffer_depth();
+                               auto& frame = depth < 0 ? frames_.back() : frames_.at(depth - minmax.first);
                                        
                                try
                                {
index 9c66df6ae881d2995c958e61dee10887b09bef85..eecb81e6a0e475822763f56363a9bbf2782563b9 100644 (file)
@@ -200,12 +200,9 @@ public:
 
        virtual ~destroy_producer_proxy()
        {               
-               static tbb::atomic<int> counter = []
-               {
-                       tbb::atomic<int> c;
-                       c = 0;
-                       return c;
-               }();
+               static tbb::atomic<int> counter;
+               static std::once_flag counter_init_once;
+               std::call_once(counter_init_once, []{ counter = 0; });
                
                if(producer_ == core::frame_producer::empty())
                        return;
index 0facc20cebf16356bf3cd1859ea07112020b31ab..8b6c66c5dedff1c76e9c30bf4311cc6d0fd692f5 100644 (file)
@@ -16,6 +16,7 @@ add_subdirectory(psd)
 
 if (MSVC)
        add_subdirectory(flash)
+       add_subdirectory(newtek)
 endif ()
 
 add_subdirectory(reroute)
index aea4ba429617c0b73bcb8db36096133050dde747..ee34016992036eec9f43e2c16e837acecfa55e66 100644 (file)
@@ -835,7 +835,7 @@ public:
 
        int buffer_depth() const override
        {
-               return 1;
+               return -1;
        }
 
        int index() const override
index a34bebb6f63633a03c9425fd9b95f2484661d345..89cffa553fa3e2382220185c279e71910f833d3c 100644 (file)
@@ -135,7 +135,7 @@ public:
 
        int buffer_depth() const override
        {
-               return 0;
+               return -1;
        }
 
        int index() const override
diff --git a/modules/newtek/CMakeLists.txt b/modules/newtek/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a6b9ac3
--- /dev/null
@@ -0,0 +1,45 @@
+cmake_minimum_required (VERSION 2.6)
+project (newtek)
+
+set(SOURCES
+               consumer/newtek_ivga_consumer.cpp
+
+               util/air_send.cpp
+
+               newtek.cpp
+
+               StdAfx.cpp
+)
+set(HEADERS
+               consumer/newtek_ivga_consumer.h
+
+               util/air_send.h
+
+               newtek.h
+
+               StdAfx.h
+)
+
+add_library(newtek ${SOURCES} ${HEADERS})
+add_precompiled_header(newtek StdAfx.h FORCEINCLUDE)
+
+include_directories(..)
+include_directories(../..)
+include_directories(${BOOST_INCLUDE_PATH})
+include_directories(${TBB_INCLUDE_PATH})
+include_directories(${ASMLIB_INCLUDE_PATH})
+include_directories(${RXCPP_INCLUDE_PATH})
+
+set_target_properties(newtek PROPERTIES FOLDER modules)
+source_group(sources\\consumer consumer/*)
+source_group(sources\\util util/*)
+source_group(sources ./*)
+
+target_link_libraries(newtek
+       common
+       core
+)
+
+casparcg_add_include_statement("modules/newtek/newtek.h")
+casparcg_add_init_statement("newtek::init" "newtek")
+casparcg_add_module_project("newtek")
diff --git a/modules/newtek/StdAfx.cpp b/modules/newtek/StdAfx.cpp
new file mode 100644 (file)
index 0000000..04bd954
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+* Copyright 2013 Sveriges Television AB http://casparcg.com/
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+// stdafx.cpp : source file that includes just the standard includes
+//     dma.pch will be the pre-compiled header
+//     stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/modules/newtek/StdAfx.h b/modules/newtek/StdAfx.h
new file mode 100644 (file)
index 0000000..95bf2b0
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+* Copyright 2013 Sveriges Television AB http://casparcg.com/
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#ifdef _DEBUG
+#include <crtdbg.h>
+#endif
+
+#define NOMINMAX
+
+#include <memory>
+#include <array>
+#include <functional>
+#include <algorithm>
+#include <vector>
+#include <deque>
+#include <queue>
+#include <string>
+#include <math.h>
+
+#include <common/memory.h>
+//#include "../common/concurrency/executor.h" // Can't include this due to MSVC lambda bug
+
+#include <common/log.h>
+#include <common/except.h>
+
+#include <assert.h>
diff --git a/modules/newtek/consumer/newtek_ivga_consumer.cpp b/modules/newtek/consumer/newtek_ivga_consumer.cpp
new file mode 100644 (file)
index 0000000..feb126e
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+* Copyright 2013 NewTek
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag@live.com
+*/
+#include "../StdAfx.h"
+
+#include "newtek_ivga_consumer.h"
+
+#include <core/consumer/frame_consumer.h>
+#include <core/video_format.h>
+#include <core/frame/frame.h>
+#include <core/mixer/audio/audio_util.h>
+#include <core/monitor/monitor.h>
+
+#include <common/assert.h>
+#include <common/executor.h>
+#include <common/diagnostics/graph.h>
+#include <common/timer.h>
+#include <common/param.h>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/timer.hpp>
+#include <boost/property_tree/ptree.hpp>
+
+#include <tbb/atomic.h>
+
+#include "../util/air_send.h"
+
+namespace caspar { namespace newtek {
+
+struct newtek_ivga_consumer : public core::frame_consumer
+{
+       core::monitor::subject  monitor_subject_;
+       std::shared_ptr<void>                           air_send_;
+       core::video_format_desc                         format_desc_;
+       executor                                                        executor_;
+       bool                                                            provide_sync_;
+       tbb::atomic<bool>                                       connected_;
+       spl::shared_ptr<diagnostics::graph>     graph_;
+       timer                                                           tick_timer_;
+       timer                                                           frame_timer_;
+
+public:
+
+       newtek_ivga_consumer(bool provide_sync)
+               : executor_(print())
+               , provide_sync_(provide_sync)
+       {
+               if (!airsend::is_available())
+                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(airsend::dll_name() + L" not available"));
+
+               connected_ = false;
+
+               graph_->set_text(print());
+               graph_->set_color("frame-time", diagnostics::color(0.5f, 1.0f, 0.2f));
+               graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f));
+               diagnostics::register_graph(graph_);
+       }
+       
+       ~newtek_ivga_consumer()
+       {
+       }
+
+       // frame_consumer
+       
+       virtual void initialize(
+                       const core::video_format_desc& format_desc,
+                       int channel_index) override
+       {
+               air_send_.reset(
+                       airsend::create(
+                               format_desc.width,
+                               format_desc.height,
+                               format_desc.time_scale,
+                               format_desc.duration,
+                               format_desc.field_mode == core::field_mode::progressive,
+                               static_cast<float>(format_desc.square_width) / static_cast<float>(format_desc.square_height),
+                               true,
+                               format_desc.audio_channels,
+                               format_desc.audio_sample_rate),
+                               airsend::destroy);
+
+               CASPAR_VERIFY(air_send_);
+
+               format_desc_ = format_desc;
+
+               CASPAR_LOG(info) << print() << L" Successfully Initialized.";   
+       }
+
+       virtual std::future<bool> send(core::const_frame frame) override
+       {
+               CASPAR_VERIFY(format_desc_.height * format_desc_.width * 4 == frame.image_data().size());
+
+               return executor_.begin_invoke([=]() -> bool
+               {                       
+                       graph_->set_value("tick-time", tick_timer_.elapsed() * format_desc_.fps * 0.5);
+                       tick_timer_.restart();
+                       frame_timer_.restart();
+
+                       // AUDIO
+
+                       auto audio_buffer = core::audio_32_to_16(frame.audio_data());
+
+                       airsend::add_audio(air_send_.get(), audio_buffer.data(), static_cast<int>(audio_buffer.size()) / format_desc_.audio_channels);
+
+                       // VIDEO
+
+                       connected_ = airsend::add_frame_bgra(air_send_.get(), frame.image_data().begin());
+
+                       graph_->set_text(print());
+                       graph_->set_value("frame-time", frame_timer_.elapsed() * format_desc_.fps * 0.5);
+                       
+                       return true;
+               });
+       }
+
+       virtual core::monitor::subject& monitor_output() override
+       {
+               return monitor_subject_;
+       }
+
+       virtual std::wstring print() const override
+       {
+               return connected_ ?
+                               L"newtek-ivga[connected]" : L"newtek-ivga[not connected]";
+       }
+
+       virtual std::wstring name() const override
+       {
+               return L"newtek-ivga";
+       }
+
+       virtual boost::property_tree::wptree info() const override
+       {
+               boost::property_tree::wptree info;
+               info.add(L"type", L"newtek-ivga-consumer");
+               info.add(L"connected", connected_ ? L"true" : L"false");
+               return info;
+       }
+
+       virtual int buffer_depth() const override
+       {
+               return -1;
+       }
+       
+       virtual int index() const override
+       {
+               return 900;
+       }
+
+       virtual bool has_synchronization_clock() const override
+       {
+               return provide_sync_ && connected_;
+       }
+};     
+
+spl::shared_ptr<core::frame_consumer> create_ivga_consumer(const std::vector<std::wstring>& params, core::interaction_sink*)
+{
+       if(params.size() < 1 || params[0] != L"NEWTEK_IVGA")
+               return core::frame_consumer::empty();
+
+       const auto provide_sync = get_param(L"PROVIDE_SYNC", params, true);
+
+       return spl::make_shared<newtek_ivga_consumer>(provide_sync);
+}
+
+spl::shared_ptr<core::frame_consumer> create_preconfigured_ivga_consumer(const boost::property_tree::wptree& ptree, core::interaction_sink*)
+{      
+       const auto provide_sync = ptree.get(L"provide-sync", true);
+
+       return spl::make_shared<newtek_ivga_consumer>(provide_sync);
+}
+
+}}
\ No newline at end of file
diff --git a/modules/newtek/consumer/newtek_ivga_consumer.h b/modules/newtek/consumer/newtek_ivga_consumer.h
new file mode 100644 (file)
index 0000000..789a588
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+* Copyright 2013 Sveriges Television AB http://casparcg.com/
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+
+#include <boost/property_tree/ptree_fwd.hpp>
+
+#include <string>
+
+namespace caspar { 
+
+namespace core {
+       class frame_consumer;
+       struct interaction_sink;
+}
+        
+namespace newtek {
+
+spl::shared_ptr<core::frame_consumer> create_ivga_consumer(const std::vector<std::wstring>& params, core::interaction_sink*);
+spl::shared_ptr<core::frame_consumer> create_preconfigured_ivga_consumer(const boost::property_tree::wptree& ptree, core::interaction_sink*);
+
+}}
\ No newline at end of file
diff --git a/modules/newtek/newtek.cpp b/modules/newtek/newtek.cpp
new file mode 100644 (file)
index 0000000..839530c
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+* Copyright 2013 Sveriges Television AB http://casparcg.com/
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "newtek.h"
+
+#include "consumer/newtek_ivga_consumer.h"
+#include "util/air_send.h"
+
+#include <core/consumer/frame_consumer.h>
+
+namespace caspar { namespace newtek {
+
+void init(core::module_dependencies dependencies)
+{
+       try
+       {
+               if (airsend::is_available())
+                       core::register_consumer_factory(create_ivga_consumer);
+               dependencies.system_info_provider_repo->register_system_info_provider([](boost::property_tree::wptree& info)
+               {
+                       info.add(L"system.newtek-ivga.version", airsend::is_available()
+                                       ? L"available"
+                                       : L"unavailable (" + airsend::dll_name() + L")");
+               });
+               core::register_preconfigured_consumer_factory(L"newtek-ivga", create_preconfigured_ivga_consumer);
+       }
+       catch(...){}
+}
+
+}}
\ No newline at end of file
diff --git a/modules/newtek/newtek.h b/modules/newtek/newtek.h
new file mode 100644 (file)
index 0000000..777da3d
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+* Copyright 2013 Sveriges Television AB http://casparcg.com/
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <core/module_dependencies.h>
+
+namespace caspar { namespace newtek {
+
+void init(core::module_dependencies dependencies);
+
+}}
\ No newline at end of file
diff --git a/modules/newtek/util/air_send.cpp b/modules/newtek/util/air_send.cpp
new file mode 100644 (file)
index 0000000..9d0a459
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+* Copyright 2013 Sveriges Television AB http://casparcg.com/
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Helge Norberg, helge.norberg@svt.se
+*/
+
+#include "../StdAfx.h"
+
+#include "air_send.h"
+
+#include <memory>
+
+#include <Windows.h>
+
+#include <common/except.h>
+
+namespace caspar { namespace newtek { namespace airsend {
+
+void* (*create)(
+               const int width, const int height,
+               const int timescale, const int duration,
+               const bool progressive,
+               const float aspect_ratio,
+               const bool audio_enabled,
+               const int num_channels,
+               const int sample_rate) = nullptr;
+void (*destroy)(void* instance) = nullptr;
+bool (*add_audio)(
+               void* instance, const short* samples, const int num_samples) = nullptr;
+bool (*add_frame_bgra)(void* instance, const unsigned char* data) = nullptr;
+
+const std::wstring& dll_name()
+{
+       static std::wstring name = L"Processing.AirSend.x64.dll";
+
+       return name;
+}
+
+std::shared_ptr<void> load_library()
+{
+       auto module = LoadLibrary(dll_name().c_str());
+
+       if (!module)
+               return nullptr;
+
+       std::shared_ptr<void> lib(module, FreeLibrary);
+
+       wchar_t actualFilename[256];
+
+       GetModuleFileNameW(module, actualFilename, sizeof(actualFilename));
+
+       CASPAR_LOG(debug) << L"Loaded " << actualFilename;
+
+       create = reinterpret_cast<decltype(create)>(
+                       GetProcAddress(module, "AirSend_Create"));
+       destroy = reinterpret_cast<decltype(destroy)>(
+                       GetProcAddress(module, "AirSend_Destroy"));
+       add_audio = reinterpret_cast<decltype(add_audio)>(
+                       GetProcAddress(module, "AirSend_add_audio"));
+       add_frame_bgra = reinterpret_cast<decltype(add_frame_bgra)>(
+                       GetProcAddress(module, "AirSend_add_frame_bgra"));
+
+       if (create == nullptr
+                       || destroy == nullptr
+                       || add_audio == nullptr
+                       || add_frame_bgra == nullptr)
+       {
+               create = nullptr;
+               destroy = nullptr;
+               add_audio = nullptr;
+               add_frame_bgra = nullptr;
+
+               return nullptr;
+       }
+
+       return lib;
+}
+
+bool is_available()
+{
+       static std::shared_ptr<void> lib = load_library();
+
+       return static_cast<bool>(lib);
+}
+
+}}}
diff --git a/modules/newtek/util/air_send.h b/modules/newtek/util/air_send.h
new file mode 100644 (file)
index 0000000..8155fc5
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+* Copyright 2013 Sveriges Television AB http://casparcg.com/
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Helge Norberg, helge.norberg@svt.se
+*/
+#pragma once
+
+#include <string>
+
+namespace caspar { namespace newtek { namespace airsend {
+
+const std::wstring& dll_name();
+bool is_available();
+
+extern void* (*create)(
+               const int width, const int height,
+               const int timescale, const int duration,
+               const bool progressive,
+               const float aspect_ratio,
+               const bool audio_enabled,
+               const int num_channels,
+               const int sample_rate);
+extern void (*destroy)(void* instance);
+extern bool (*add_audio)(
+               void* instance, const short* samples, const int num_samples);
+extern bool (*add_frame_bgra)(void* instance, const unsigned char* data);
+
+}}}
index 414361724d6a1433789044429a26e9a2d48f784e..25e373a826aa0f7dd7cf08643b7fce4ab19cfdc5 100644 (file)
@@ -91,6 +91,9 @@
                 <vsync>false [true|false]</vsync>\r
                 <interactive>true [true|false]</interactive>\r
             </screen>\r
+            <newtek-ivga>\r
+                <provide-sync>true [true|false]</provide-sync>\r
+            </newtek-ivga>\r
             <file>\r
                 <path></path>\r
                 <vcodec>libx264 [libx264|qtrle]</vcodec>\r