<ClInclude Include="compiler\vs\disable_silly_warnings.h" />\r
<ClInclude Include="concurrency\executor.h" />\r
<ClInclude Include="concurrency\Thread.h" />\r
- <ClInclude Include="config.h" />\r
<ClInclude Include="exception\exceptions.h" />\r
<ClInclude Include="exception\win32_exception.h" />\r
- <ClInclude Include="gl\utility.h" />\r
+ <ClInclude Include="gl\gl_check.h" />\r
<ClInclude Include="io\AsyncEventServer.h" />\r
<ClInclude Include="io\ClientInfo.h" />\r
<ClInclude Include="io\ProtocolStrategy.h" />\r
<ClInclude Include="log\log.h" />\r
<ClInclude Include="stdafx.h" />\r
<ClInclude Include="utility\safe_ptr.h" />\r
- <ClInclude Include="utility\singleton_pool.h" />\r
<ClInclude Include="utility\string_convert.h" />\r
<ClInclude Include="utility\timer.h" />\r
</ItemGroup>\r
</Filter>\r
</ItemGroup>\r
<ItemGroup>\r
- <ClCompile Include="log\log.cpp">\r
- <Filter>Source\log</Filter>\r
- </ClCompile>\r
<ClCompile Include="io\SocketInfo.cpp">\r
<Filter>Source\io</Filter>\r
</ClCompile>\r
<ClCompile Include="stdafx.cpp">\r
<Filter>Afx</Filter>\r
</ClCompile>\r
+ <ClCompile Include="log\log.cpp">\r
+ <Filter>Source\log</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
<ItemGroup>\r
- <ClInclude Include="log\log.h">\r
- <Filter>Source\log</Filter>\r
- </ClInclude>\r
<ClInclude Include="io\AsyncEventServer.h">\r
<Filter>Source\io</Filter>\r
</ClInclude>\r
<ClInclude Include="exception\win32_exception.h">\r
<Filter>Source\exception</Filter>\r
</ClInclude>\r
- <ClInclude Include="config.h">\r
- <Filter>Source</Filter>\r
- </ClInclude>\r
- <ClInclude Include="gl\utility.h">\r
- <Filter>Source\gl</Filter>\r
- </ClInclude>\r
<ClInclude Include="compiler\vs\disable_silly_warnings.h">\r
<Filter>Source\compiler\vs</Filter>\r
</ClInclude>\r
<ClInclude Include="concurrency\executor.h">\r
<Filter>Source\concurrency</Filter>\r
</ClInclude>\r
- <ClInclude Include="utility\string_convert.h">\r
+ <ClInclude Include="log\log.h">\r
+ <Filter>Source\log</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="utility\timer.h">\r
<Filter>Source\utility</Filter>\r
</ClInclude>\r
<ClInclude Include="utility\safe_ptr.h">\r
<Filter>Source\utility</Filter>\r
</ClInclude>\r
- <ClInclude Include="utility\singleton_pool.h">\r
+ <ClInclude Include="utility\string_convert.h">\r
<Filter>Source\utility</Filter>\r
</ClInclude>\r
- <ClInclude Include="utility\timer.h">\r
- <Filter>Source\utility</Filter>\r
+ <ClInclude Include="gl\gl_check.h">\r
+ <Filter>Source\gl</Filter>\r
</ClInclude>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
+++ /dev/null
-#pragma once\r
-\r
-#define TBB_USE_THREADING_TOOLS 1\r
\r
typedef boost::error_info<struct tag_arg_name_info, std::string> arg_name_info;\r
typedef boost::error_info<struct tag_arg_value_info, std::string> arg_value_info;\r
-typedef boost::error_info<struct tag_arg_name_info, std::wstring> warg_name_info;\r
-typedef boost::error_info<struct tag_arg_value_info, std::wstring> warg_value_info;\r
typedef boost::error_info<struct tag_msg_info, std::string> msg_info;\r
typedef boost::error_info<struct tag_inner_info, std::exception_ptr> inner_info;\r
typedef boost::error_info<struct tag_line_info, int> line_info;\r
\r
#include "compiler\vs\disable_silly_warnings.h"\r
\r
-#include "config.h"\r
-\r
#include <string>\r
#include <cassert>\r
+++ /dev/null
-#pragma once\r
- \r
-#include <tbb/concurrent_queue.h>\r
-#include <tbb/scalable_allocator.h>\r
-\r
-namespace caspar {\r
-\r
-template <typename T>\r
-class singleton_pool\r
-{\r
-public:\r
- \r
- static T* allocate()\r
- {\r
- T* ptr;\r
- if(!get_pool().try_pop(ptr))\r
- ptr = static_cast<T*>(scalable_malloc(sizeof(T)));\r
- return ptr;\r
- }\r
- \r
- static void deallocate(T* ptr)\r
- {\r
- if(!get_pool().try_push(ptr))\r
- scalable_free(ptr);\r
- }\r
-\r
- static void destroy(T* ptr)\r
- {\r
- ptr->~T();\r
- deallocate(ptr);\r
- }\r
-\r
- static std::shared_ptr<T> make_shared()\r
- {\r
- return std::shared_ptr<T>(new(allocate()) T(), destroy);\r
- }\r
- \r
- template<typename P0>\r
- static std::shared_ptr<T> make_shared(P0 p0)\r
- {\r
- return std::shared_ptr<T>(new(allocate()) T(std::forward<P0>(p0)), destroy);\r
- }\r
- \r
- template<typename P0, typename P1>\r
- static std::shared_ptr<T> make_shared(P0 p0, P1 p1)\r
- {\r
- return std::shared_ptr<T>(new(allocate()) T(std::forward<P0>(p0), std::forward<P1>(p1)), destroy);\r
- }\r
- \r
- template<typename P0, typename P1, typename P2>\r
- static std::shared_ptr<T> make_shared(P0 p0, P1 p1, P2 p2)\r
- {\r
- return std::shared_ptr<T>(new(allocate()) T(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2)), destroy);\r
- }\r
- \r
- template<typename P0, typename P1, typename P2, typename P3>\r
- static std::shared_ptr<T> make_shared(P0 p0, P1 p1, P2 p2, P3 p3)\r
- {\r
- return std::shared_ptr<T>(new(allocate()) T(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3)), destroy);\r
- }\r
-\r
-private:\r
- struct pool\r
- {\r
- ~pool()\r
- {\r
- T* ptr;\r
- while(value.try_pop(ptr))\r
- scalable_free(ptr);\r
- }\r
- tbb::concurrent_bounded_queue<T*> value;\r
- };\r
-\r
- static tbb::concurrent_bounded_queue<T*>& get_pool()\r
- {\r
- static pool global_pool;\r
- return global_pool.value;\r
- }\r
-};\r
-\r
-}
\ No newline at end of file
\r
#include "channel.h"\r
\r
-#include "producer/layer.h"\r
-\r
#include "consumer/frame_consumer_device.h"\r
\r
#include "processor/draw_frame.h"\r
#include "processor/frame_processor_device.h"\r
\r
+#include "producer/layer.h"\r
+\r
#include <common/concurrency/executor.h>\r
\r
#include <boost/range/algorithm_ext/erase.hpp>\r
\r
#include <tbb/parallel_for.h>\r
\r
+#include <map>\r
#include <memory>\r
\r
namespace caspar { namespace core {\r
\r
struct channel::implementation : boost::noncopyable\r
{ \r
+ mutable executor executor_;\r
+ \r
+ safe_ptr<frame_processor_device> processor_device_;\r
+ frame_consumer_device consumer_device_;\r
+ \r
+ std::map<int, layer> layers_; \r
+\r
+ const video_format_desc format_desc_;\r
+\r
+public:\r
implementation(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers) \r
- : format_desc_(format_desc), processor_device_(frame_processor_device(format_desc)), consumer_device_(format_desc, consumers)\r
+ : format_desc_(format_desc)\r
+ , processor_device_(frame_processor_device(format_desc))\r
+ , consumer_device_(format_desc, consumers)\r
{\r
executor_.start();\r
executor_.begin_invoke([=]{tick();});\r
auto it = layers_.find(index);\r
return it != layers_.end() ? it->second.background() : frame_producer::empty();\r
});\r
- }\r
-\r
- mutable executor executor_;\r
- \r
- safe_ptr<frame_processor_device> processor_device_;\r
- frame_consumer_device consumer_device_;\r
- \r
- std::map<int, layer> layers_; \r
-\r
- const video_format_desc format_desc_;\r
+ };\r
};\r
\r
channel::channel(channel&& other) : impl_(std::move(other.impl_)){}\r
class channel : boost::noncopyable\r
{\r
public:\r
+ explicit channel(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers);\r
channel(channel&& other);\r
- channel(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers);\r
\r
void load(int index, const safe_ptr<frame_producer>& producer, bool autoplay = false);\r
void preview(int index, const safe_ptr<frame_producer>& producer);\r
consumers.push_back(bluefish::consumer(format_desc, xml_consumer.second.get("device", 0), xml_consumer.second.get("embedded-audio", false))); \r
#endif\r
else if(name == "decklink")\r
- consumers.push_back(make_safe<decklink::decklink_consumer>(format_desc, xml_consumer.second.get("internalkey", false)));\r
+ consumers.push_back(make_safe<decklink::decklink_consumer>(format_desc, xml_consumer.second.get("device", 0), xml_consumer.second.get("internalkey", false)));\r
else if(name == "audio")\r
consumers.push_back(oal::consumer(format_desc)); \r
}\r
executor_.start();\r
\r
CASPAR_LOG(info) << TEXT("BLUECARD INFO: Successfully initialized device ") << device_index_;\r
+ active_ = executor_.begin_invoke([=]{});\r
}\r
\r
~implementation()\r
static size_t audio_samples = 1920;\r
static size_t audio_nchannels = 2;\r
static std::vector<short> silence(audio_samples*audio_nchannels*2, 0);\r
-\r
+ \r
+ active_.get();\r
active_ = executor_.begin_invoke([=]\r
{\r
try\r
});\r
}\r
\r
- frame_consumer::sync_mode synchronize()\r
- {\r
- active_.get();\r
- return frame_consumer::clock;\r
- }\r
-\r
size_t buffer_depth() const\r
{\r
return 1;\r
consumer::consumer(consumer&& other) : impl_(std::move(other.impl_)){}\r
consumer::consumer(const video_format_desc& format_desc, unsigned int device_index, bool embed_audio) : impl_(new implementation(format_desc, device_index, embed_audio)){} \r
void consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
-frame_consumer::sync_mode consumer::synchronize(){return impl_->synchronize();}\r
size_t consumer::buffer_depth() const{return impl_->buffer_depth();}\r
}}}\r
\r
class consumer : public frame_consumer\r
{\r
public:\r
+ explicit consumer(const video_format_desc& format_desc, unsigned int device_index, bool embed_audio = false);\r
consumer(consumer&& other);\r
- consumer(const video_format_desc& format_desc, unsigned int deviceIndex, bool embed_audio = false);\r
\r
virtual void send(const safe_ptr<const read_frame>&);\r
- virtual sync_mode synchronize();\r
virtual size_t buffer_depth() const;\r
private:\r
struct implementation;\r
#include "../../format/video_format.h"\r
#include "exception.h"\r
\r
+#include <tbb/mutex.h>\r
+\r
namespace caspar { namespace core { namespace bluefish {\r
\r
static const size_t MAX_HANC_BUFFER_SIZE = 256*1024;\r
struct page_locked_buffer\r
{\r
public:\r
- page_locked_buffer(size_t size) : size_(size), data_(static_cast<unsigned char*>(::VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)))\r
+ page_locked_buffer(size_t size) \r
+ : size_(size)\r
+ , data_(static_cast<unsigned char*>(::VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)))\r
{\r
if(!data_) \r
BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("Failed to allocate memory for paged locked buffer.")); \r
if(::VirtualLock(data_.get(), size_) == 0) \r
BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("Failed to lock memory for paged locked buffer."));\r
}\r
-\r
+ \r
static void reserve_working_size(size_t size)\r
{\r
+ auto lock = get_lock();\r
SIZE_T workingSetMinSize = 0, workingSetMaxSize = 0;\r
if(::GetProcessWorkingSetSize(::GetCurrentProcess(), &workingSetMinSize, &workingSetMaxSize))\r
{\r
}\r
}\r
\r
+ static void unreserve_working_size(size_t size)\r
+ {\r
+ auto lock = get_lock();\r
+ SIZE_T workingSetMinSize = 0, workingSetMaxSize = 0;\r
+ if(::GetProcessWorkingSetSize(::GetCurrentProcess(), &workingSetMinSize, &workingSetMaxSize))\r
+ {\r
+ CASPAR_LOG(debug) << TEXT("WorkingSet size: min = ") << workingSetMinSize << TEXT(", max = ") << workingSetMaxSize;\r
+ \r
+ workingSetMinSize += static_cast<SIZE_T>(static_cast<int>(workingSetMinSize) - static_cast<int>(size));\r
+ workingSetMaxSize += static_cast<SIZE_T>(static_cast<int>(workingSetMaxSize) - static_cast<int>(size));\r
+\r
+ if(!::SetProcessWorkingSetSize(::GetCurrentProcess(), workingSetMinSize, workingSetMaxSize)) \r
+ BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("Failed set workingset.")); \r
+ }\r
+ }\r
+\r
PBYTE data() const { return data_.get(); }\r
size_t size() const { return size_; }\r
private:\r
\r
+ static std::unique_ptr<tbb::mutex::scoped_lock> get_lock()\r
+ {\r
+ static tbb::mutex mutex;\r
+ return std::move(std::unique_ptr<tbb::mutex::scoped_lock>(new tbb::mutex::scoped_lock(mutex)));\r
+ }\r
+ \r
struct virtual_free\r
{\r
void operator()(LPVOID lpAddress)\r
\r
#include "../../stdafx.h"\r
\r
-#if defined(_MSC_VER)\r
-#pragma warning (push, 1) // TODO: Legacy code, just disable warnings\r
-#pragma warning (disable : 4244)\r
-#endif\r
-\r
#include "decklink_consumer.h"\r
\r
#include "util.h"\r
\r
namespace caspar { namespace core { namespace decklink{\r
\r
-struct decklink_consumer::Implementation : boost::noncopyable\r
-{\r
- Implementation(const video_format_desc& format_desc, bool internalKey) : format_desc_(format_desc), currentFormat_(video_format::pal), internalKey_(internalKey)\r
+struct decklink_consumer::implementation : boost::noncopyable\r
+{ \r
+ boost::unique_future<void> active_;\r
+ executor executor_;\r
+\r
+ std::array<std::pair<void*, CComPtr<IDeckLinkMutableVideoFrame>>, 3> reserved_frames_;\r
+\r
+ bool internal_key;\r
+ CComPtr<IDeckLink> decklink_;\r
+ CComQIPtr<IDeckLinkOutput> output_;\r
+ CComQIPtr<IDeckLinkKeyer> keyer_;\r
+ \r
+ video_format::type current_format_;\r
+ video_format_desc format_desc_;\r
+\r
+public:\r
+ implementation(const video_format_desc& format_desc, size_t device_index, bool internalKey) \r
+ : format_desc_(format_desc)\r
+ , current_format_(video_format::pal)\r
+ , internal_key(internalKey)\r
{ \r
executor_.start();\r
executor_.invoke([=]\r
if(FAILED(pDecklinkIterator.CoCreateInstance(CLSID_CDeckLinkIterator)))\r
BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("DECKLINK: No Decklink drivers installed."));\r
\r
- while(pDecklinkIterator->Next(&decklink_) == S_OK && !decklink_){} \r
+ size_t n = 0;\r
+ while(n < device_index && pDecklinkIterator->Next(&decklink_) == S_OK){++n;} \r
\r
- if(decklink_ == nullptr)\r
- BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("DECKLINK: No Decklink card found."));\r
+ if(n != device_index || !decklink_)\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("DECKLINK: No Decklink card found.") << arg_name_info("device_index") << arg_value_info(boost::lexical_cast<std::string>(device_index)));\r
\r
output_ = decklink_;\r
keyer_ = decklink_;\r
if(decklinkVideoFormat == ULONG_MAX) \r
BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("DECKLINK: Card does not support requested videoformat."));\r
\r
- currentFormat_ = format_desc_.format;\r
+ current_format_ = format_desc_.format;\r
\r
BMDDisplayModeSupport displayModeSupport;\r
if(FAILED(output_->DoesSupportVideoMode((BMDDisplayMode)decklinkVideoFormat, bmdFormat8BitBGRA, &displayModeSupport)))\r
if(FAILED(output_->EnableVideoOutput((BMDDisplayMode)decklinkVideoFormat, bmdVideoOutputFlagDefault))) \r
BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("DECKLINK: Could not enable video output."));\r
\r
- if(internalKey_) \r
+ if(internal_key) \r
{\r
if(FAILED(keyer_->Enable(FALSE))) \r
CASPAR_LOG(error) << "DECKLINK: Failed to enable internal keye.r"; \r
CASPAR_LOG(info) << "DECKLINK: Successfully configured external keyer."; \r
}\r
\r
- for(int n = 0; n < reserved_frames_.size(); ++n)\r
+ for(size_t n = 0; n < reserved_frames_.size(); ++n)\r
{\r
if(FAILED(output_->CreateVideoFrame(format_desc_.width, format_desc_.height, format_desc_.size/format_desc_.height, bmdFormat8BitBGRA, bmdFrameFlagDefault, &reserved_frames_[n].second)))\r
BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("DECKLINK: Failed to create frame."));\r
\r
CASPAR_LOG(info) << "DECKLINK: Successfully initialized decklink for " << format_desc_.name;\r
});\r
+ active_ = executor_.begin_invoke([]{});\r
}\r
\r
- ~Implementation()\r
+ ~implementation()\r
{ \r
executor_.invoke([this]\r
{\r
- if(output_) \r
+ if(output_ != nullptr) \r
output_->DisableVideoOutput();\r
\r
for(size_t n = 0; n < reserved_frames_.size(); ++n)\r
\r
void send(const safe_ptr<const read_frame>& frame)\r
{\r
+ active_.get();\r
active_ = executor_.begin_invoke([=]\r
{ \r
std::copy(frame->image_data().begin(), frame->image_data().end(), static_cast<char*>(reserved_frames_.front().first));\r
std::rotate(reserved_frames_.begin(), reserved_frames_.begin() + 1, reserved_frames_.end());\r
});\r
}\r
- \r
- frame_consumer::sync_mode synchronize()\r
- {\r
- active_.get();\r
- return frame_consumer::ready;\r
- }\r
\r
size_t buffer_depth() const\r
{\r
return 1;\r
}\r
- \r
- boost::unique_future<void> active_;\r
- executor executor_;\r
-\r
- std::array<std::pair<void*, CComPtr<IDeckLinkMutableVideoFrame>>, 3> reserved_frames_;\r
-\r
- bool internalKey_;\r
- CComPtr<IDeckLink> decklink_;\r
- CComQIPtr<IDeckLinkOutput> output_;\r
- CComQIPtr<IDeckLinkKeyer> keyer_;\r
- \r
- video_format::type currentFormat_;\r
- video_format_desc format_desc_;\r
};\r
\r
-decklink_consumer::decklink_consumer(const video_format_desc& format_desc, bool internalKey) : pImpl_(new Implementation(format_desc, internalKey)){}\r
-void decklink_consumer::send(const safe_ptr<const read_frame>& frame){pImpl_->send(frame);}\r
-frame_consumer::sync_mode decklink_consumer::synchronize(){return pImpl_->synchronize();}\r
-size_t decklink_consumer::buffer_depth() const{return pImpl_->buffer_depth();}\r
+decklink_consumer::decklink_consumer(const video_format_desc& format_desc, size_t device_index, bool internalKey) : impl_(new implementation(format_desc, device_index, internalKey)){}\r
+decklink_consumer::decklink_consumer(decklink_consumer&& other) : impl_(std::move(other.impl_)){}\r
+void decklink_consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
+size_t decklink_consumer::buffer_depth() const{return impl_->buffer_depth();}\r
\r
}}}
\ No newline at end of file
class decklink_consumer : public frame_consumer\r
{\r
public:\r
- explicit decklink_consumer(const video_format_desc& format_desc, bool internalKey = false);\r
+ explicit decklink_consumer(const video_format_desc& format_desc, size_t device_index, bool internal_key = false);\r
+ decklink_consumer(decklink_consumer&& other);\r
\r
virtual void send(const safe_ptr<const read_frame>&);\r
- virtual sync_mode synchronize();\r
virtual size_t buffer_depth() const;\r
private:\r
- struct Implementation;\r
- std::tr1::shared_ptr<Implementation> pImpl_;\r
+ struct implementation;\r
+ std::tr1::shared_ptr<implementation> impl_;\r
};\r
\r
}}}
\ No newline at end of file
\r
struct frame_consumer : boost::noncopyable\r
{\r
- enum sync_mode\r
- {\r
- ready = 0,\r
- clock \r
- };\r
-\r
virtual ~frame_consumer() {}\r
\r
virtual void send(const safe_ptr<const read_frame>& frame) = 0;\r
- virtual sync_mode synchronize() = 0;\r
virtual size_t buffer_depth() const = 0;\r
};\r
\r
-#include "../StdAfx.h"\r
+/*\r
+* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
+*\r
+* This file is part of CasparCG.\r
+*\r
+* CasparCG is free software: you can redistribute it and/or modify\r
+* it under the terms of the GNU General Public License as published by\r
+* the Free Software Foundation, either version 3 of the License, or\r
+* (at your option) any later version.\r
+*\r
+* CasparCG is distributed in the hope that it will be useful,\r
+* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+* GNU General Public License for more details.\r
\r
-#ifdef _MSC_VER\r
-#pragma warning (disable : 4244)\r
-#endif\r
+* You should have received a copy of the GNU General Public License\r
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
+*\r
+*/\r
+ \r
+#include "..\..\StdAfx.h"\r
\r
-#include "frame_consumer_device.h"\r
+#ifndef DISABLE_BLUEFISH\r
\r
-#include "../format/video_format.h"\r
+#include "fwd.h"\r
+#include "bluefish_consumer.h"\r
+#include "util.h"\r
+#include "exception.h"\r
+#include "memory.h"\r
+\r
+#include "../../processor/read_frame.h"\r
\r
#include <common/concurrency/executor.h>\r
-#include <common/utility/timer.h>\r
\r
-#include <boost/range/algorithm_ext/erase.hpp>\r
-#include <boost/range/algorithm.hpp>\r
+#include <tbb/concurrent_queue.h>\r
+\r
+#include <BlueVelvet4.h>\r
+#include <BlueHancUtils.h>\r
\r
-namespace caspar { namespace core {\r
+namespace caspar { namespace core { namespace bluefish {\r
\r
-struct frame_consumer_device::implementation\r
+struct consumer::implementation : boost::noncopyable\r
{\r
-public:\r
- implementation(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers) : consumers_(consumers), fmt_(format_desc)\r
- { \r
- std::vector<size_t> depths;\r
- boost::range::transform(consumers_, std::back_inserter(depths), std::mem_fn(&frame_consumer::buffer_depth));\r
- max_depth_ = *boost::range::max_element(depths);\r
- executor_.set_capacity(3);\r
- executor_.start();\r
- }\r
+ boost::unique_future<void> active_;\r
+ executor executor_;\r
\r
- void consume(safe_ptr<const read_frame>&& frame)\r
- { \r
- executor_.begin_invoke([=]\r
+ BlueVelvetPtr sdk_;\r
+ \r
+ unsigned int device_index_;\r
+ video_format_desc format_desc_;\r
+ \r
+ unsigned long mem_fmt_;\r
+ unsigned long upd_fmt_;\r
+ EVideoMode vid_fmt_; \r
+ unsigned long res_fmt_; \r
+ unsigned long engine_mode_;\r
+\r
+ std::shared_ptr<const read_frame> transferring_frame_;\r
+\r
+ std::array<page_locked_buffer_ptr, 3> hanc_buffers_;\r
+ int current_id_;\r
+ bool embed_audio_;\r
+\r
+public:\r
+ implementation::implementation(const video_format_desc& format_desc, unsigned int device_index, bool embed_audio) \r
+ : sdk_(BlueVelvetFactory4())\r
+ , device_index_(device_index)\r
+ , format_desc_(format_desc)\r
+ , mem_fmt_(MEM_FMT_ARGB_PC)\r
+ , upd_fmt_(UPD_FMT_FRAME)\r
+ , vid_fmt_(VID_FMT_INVALID) \r
+ , res_fmt_(RES_FMT_NORMAL) \r
+ , engine_mode_(VIDEO_ENGINE_FRAMESTORE) \r
+ , current_id_(0)\r
+ , embed_audio_(embed_audio)\r
+ {\r
+ \r
+ if(BLUE_FAIL(sdk_->device_attach(device_index_, FALSE))) \r
+ BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to attach device."));\r
+ \r
+ int videoCardType = sdk_->has_video_cardtype();\r
+ CASPAR_LOG(info) << TEXT("BLUECARD INFO: Card type: ") << get_card_desc(videoCardType) << TEXT(". (device ") << device_index_ << TEXT(")");\r
+ \r
+ //void* pBlueDevice = blue_attach_to_device(1);\r
+ //EBlueConnectorPropertySetting video_routing[1];\r
+ //auto channel = BLUE_VIDEO_OUTPUT_CHANNEL_A;\r
+ //video_routing[0].channel = channel; \r
+ //video_routing[0].propType = BLUE_CONNECTOR_PROP_SINGLE_LINK;\r
+ //video_routing[0].connector = channel == BLUE_VIDEO_OUTPUT_CHANNEL_A ? BLUE_CONNECTOR_SDI_OUTPUT_A : BLUE_CONNECTOR_SDI_OUTPUT_B;\r
+ //blue_set_connector_property(pBlueDevice, 1, video_routing);\r
+ //blue_detach_from_device(&pBlueDevice);\r
+ \r
+ auto desiredVideoFormat = vid_fmt_from_video_format(format_desc_.format);\r
+ int videoModeCount = sdk_->count_video_mode();\r
+ for(int videoModeIndex = 1; videoModeIndex <= videoModeCount; ++videoModeIndex) \r
{\r
- buffer_.push_back(frame);\r
+ EVideoMode videoMode = sdk_->enum_video_mode(videoModeIndex);\r
+ if(videoMode == desiredVideoFormat) \r
+ vid_fmt_ = videoMode; \r
+ }\r
+ if(vid_fmt_ == VID_FMT_INVALID)\r
+ BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to set videomode."));\r
+ \r
+ // Set default video output channel\r
+ //if(BLUE_FAIL(set_card_property(sdk_, DEFAULT_VIDEO_OUTPUT_CHANNEL, channel)))\r
+ // CASPAR_LOG(error) << TEXT("BLUECARD ERROR: Failed to set default channel. (device ") << device_index_ << TEXT(")");\r
+\r
+ //Setting output Video mode\r
+ if(BLUE_FAIL(set_card_property(sdk_, VIDEO_MODE, vid_fmt_))) \r
+ BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to set videomode."));\r
+\r
+ //Select Update Mode for output\r
+ if(BLUE_FAIL(set_card_property(sdk_, VIDEO_UPDATE_TYPE, upd_fmt_))) \r
+ BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to set update type. "));\r
\r
- boost::range::for_each(consumers_, [&](const safe_ptr<frame_consumer>& consumer)\r
- {\r
- size_t offset = max_depth_ - consumer->buffer_depth();\r
- if(offset < buffer_.size())\r
- consumer->send(*(buffer_.begin() + offset));\r
- });\r
+ disable_video_output();\r
+\r
+ //Enable dual link output\r
+ if(BLUE_FAIL(set_card_property(sdk_, VIDEO_DUAL_LINK_OUTPUT, 1)))\r
+ BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to enable dual link."));\r
+\r
+ if(BLUE_FAIL(set_card_property(sdk_, VIDEO_DUAL_LINK_OUTPUT_SIGNAL_FORMAT_TYPE, Signal_FormatType_4224)))\r
+ BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to set dual link format type to 4:2:2:4. (device " + boost::lexical_cast<std::string>(device_index_) + ")"));\r
\r
- frame_consumer::sync_mode sync = frame_consumer::ready;\r
- boost::range::for_each(consumers_, [&](const safe_ptr<frame_consumer>& consumer)\r
+ //Select output memory format\r
+ if(BLUE_FAIL(set_card_property(sdk_, VIDEO_MEMORY_FORMAT, mem_fmt_))) \r
+ BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to set memory format."));\r
+ \r
+ //Select image orientation\r
+ if(BLUE_FAIL(set_card_property(sdk_, VIDEO_IMAGE_ORIENTATION, ImageOrientation_Normal)))\r
+ CASPAR_LOG(error) << TEXT("BLUECARD ERROR: Failed to set image orientation to normal. (device ") << device_index_ << TEXT(")"); \r
+\r
+ // Select data range\r
+ if(BLUE_FAIL(set_card_property(sdk_, VIDEO_RGB_DATA_RANGE, CGR_RANGE))) \r
+ CASPAR_LOG(error) << TEXT("BLUECARD ERROR: Failed to set RGB data range to CGR. (device ") << device_index_ << TEXT(")"); \r
+ \r
+ if(BLUE_FAIL(set_card_property(sdk_, VIDEO_PREDEFINED_COLOR_MATRIX, vid_fmt_ == VID_FMT_PAL ? MATRIX_601_CGR : MATRIX_709_CGR)))\r
+ CASPAR_LOG(error) << TEXT("BLUECARD ERROR: Failed to set colormatrix to ") << (vid_fmt_ == VID_FMT_PAL ? TEXT("601 CGR") : TEXT("709 CGR")) << TEXT(". (device ") << device_index_ << TEXT(")");\r
+ \r
+ //if(BLUE_FAIL(set_card_property(sdk_, EMBEDDED_AUDIO_OUTPUT, 0))) \r
+ // CASPAR_LOG(error) << TEXT("BLUECARD ERROR: Failed to enable embedded audio. (device ") << device_index_ << TEXT(")"); \r
+ //else \r
+ //{\r
+ // CASPAR_LOG(info) << TEXT("BLUECARD INFO: Enabled embedded audio. (device ") << device_index_ << TEXT(")");\r
+ // hasEmbeddedAudio_ = true;\r
+ //}\r
+\r
+ CASPAR_LOG(info) << TEXT("BLUECARD INFO: Successfully configured bluecard for ") << format_desc_ << TEXT(". (device ") << device_index_ << TEXT(")");\r
+\r
+ if (sdk_->has_output_key()) \r
+ {\r
+ int dummy = TRUE; int v4444 = FALSE; int invert = FALSE; int white = FALSE;\r
+ sdk_->set_output_key(dummy, v4444, invert, white);\r
+ }\r
+\r
+ if(sdk_->GetHDCardType(device_index_) != CRD_HD_INVALID) \r
+ sdk_->Set_DownConverterSignalType(vid_fmt_ == VID_FMT_PAL ? SD_SDI : HD_SDI); \r
+ \r
+ if(BLUE_FAIL(sdk_->set_video_engine(engine_mode_)))\r
+ BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to set vido engine."));\r
+\r
+ enable_video_output();\r
+ \r
+ page_locked_buffer::reserve_working_size(MAX_HANC_BUFFER_SIZE * hanc_buffers_.size()); \r
+ for(size_t n = 0; n < hanc_buffers_.size(); ++n)\r
+ hanc_buffers_[n] = std::make_shared<page_locked_buffer>(MAX_HANC_BUFFER_SIZE);\r
+ \r
+ executor_.start();\r
+\r
+ CASPAR_LOG(info) << TEXT("BLUECARD INFO: Successfully initialized device ") << device_index_;\r
+\r
+ active_ = executor_.begin_invoke([]{});\r
+ }\r
+\r
+ ~implementation()\r
+ {\r
+ page_locked_buffer::unreserve_working_size(MAX_HANC_BUFFER_SIZE * hanc_buffers_.size()); \r
+ disable_video_output();\r
+\r
+ if(sdk_)\r
+ sdk_->device_detach(); \r
+\r
+ CASPAR_LOG(info) << "BLUECARD INFO: Successfully released device " << device_index_;\r
+ }\r
+ \r
+ void enable_video_output()\r
+ {\r
+ if(!BLUE_PASS(set_card_property(sdk_, VIDEO_BLACKGENERATOR, 0)))\r
+ CASPAR_LOG(error) << "BLUECARD ERROR: Failed to disable video output. (device " << device_index_ << TEXT(")"); \r
+ }\r
+\r
+ void disable_video_output()\r
+ {\r
+ if(!BLUE_PASS(set_card_property(sdk_, VIDEO_BLACKGENERATOR, 1)))\r
+ CASPAR_LOG(error) << "BLUECARD ERROR: Failed to disable video output. (device " << device_index_ << TEXT(")"); \r
+ }\r
+\r
+ void send(const safe_ptr<const read_frame>& frame)\r
+ { \r
+ static size_t audio_samples = static_cast<size_t>(48000.0 / format_desc_.fps);\r
+ static size_t audio_nchannels = 2;\r
+ static std::vector<short> silence(audio_samples*audio_nchannels*2, 0);\r
+ \r
+ active_.get();\r
+ active_ = executor_.begin_invoke([=]\r
+ {\r
+ try\r
{\r
- try\r
- {\r
- size_t offset = max_depth_ - consumer->buffer_depth();\r
- if(offset < buffer_.size() && consumer->synchronize() == frame_consumer::clock)\r
- sync = frame_consumer::clock;\r
+ auto hanc = hanc_buffers_.front(); \r
+ std::rotate(hanc_buffers_.begin(), hanc_buffers_.begin() + 1, hanc_buffers_.end());\r
+\r
+ unsigned long fieldCount = 0;\r
+ sdk_->wait_output_video_synch(UPD_FMT_FRAME, fieldCount);\r
+ \r
+ if(embed_audio_)\r
+ { \r
+ auto frame_audio_data = frame->audio_data().empty() ? silence.data() : const_cast<short*>(frame->audio_data().begin());\r
+\r
+ encode_hanc(reinterpret_cast<BLUE_UINT32*>(hanc->data()), frame_audio_data, audio_samples, audio_nchannels);\r
+ \r
+ sdk_->system_buffer_write_async(const_cast<unsigned char*>(frame->image_data().begin()), \r
+ frame->image_data().size(), \r
+ nullptr, \r
+ BlueImage_HANC_DMABuffer(current_id_, BLUE_DATA_IMAGE));\r
+\r
+ sdk_->system_buffer_write_async(hanc->data(),\r
+ hanc->size(), \r
+ nullptr, \r
+ BlueImage_HANC_DMABuffer(current_id_, BLUE_DATA_HANC));\r
+\r
+ if(BLUE_FAIL(sdk_->render_buffer_update(BlueBuffer_Image_HANC(current_id_))))\r
+ CASPAR_LOG(trace) << TEXT("BLUEFISH: render_buffer_update failed");\r
}\r
- catch(...)\r
+ else\r
{\r
- CASPAR_LOG_CURRENT_EXCEPTION();\r
- boost::range::remove_erase(consumers_, consumer);\r
- CASPAR_LOG(warning) << "Removed consumer from frame_consumer_device.";\r
+ sdk_->system_buffer_write_async(const_cast<unsigned char*>(frame->image_data().begin()),\r
+ frame->image_data().size(), \r
+ nullptr, \r
+ BlueImage_DMABuffer(current_id_, BLUE_DATA_IMAGE));\r
+ \r
+ if(BLUE_FAIL(sdk_->render_buffer_update(BlueBuffer_Image(current_id_))))\r
+ CASPAR_LOG(trace) << TEXT("BLUEFISH: render_buffer_update failed");\r
}\r
- });\r
- \r
- if(sync != frame_consumer::clock)\r
- clock_.wait(fmt_.actual_fps);\r
\r
- if(buffer_.size() >= max_depth_)\r
- buffer_.pop_front();\r
+ transferring_frame_ = frame;\r
+ }\r
+ catch(...)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ }\r
});\r
}\r
\r
- timer clock_;\r
- executor executor_; \r
+ size_t buffer_depth() const\r
+ {\r
+ return 1;\r
+ }\r
\r
- size_t max_depth_;\r
- std::deque<safe_ptr<const read_frame>> buffer_; \r
+ void encode_hanc(BLUE_UINT32* hanc_data, void* audio_data, size_t audio_samples, size_t audio_nchannels)\r
+ { \r
+ auto card_type = sdk_->has_video_cardtype();\r
+ auto sample_type = (AUDIO_CHANNEL_16BIT | AUDIO_CHANNEL_LITTLEENDIAN);\r
+ \r
+ hanc_stream_info_struct hanc_stream_info;\r
+ memset(&hanc_stream_info, 0, sizeof(hanc_stream_info));\r
\r
- std::vector<safe_ptr<frame_consumer>> consumers_;\r
- \r
- const video_format_desc fmt_;\r
+ std::fill_n(hanc_stream_info.AudioDBNArray, sizeof(hanc_stream_info.AudioDBNArray)/sizeof(hanc_stream_info.AudioDBNArray[0]), -1);\r
+ hanc_stream_info.hanc_data_ptr = hanc_data;\r
+ hanc_stream_info.video_mode = vid_fmt_;\r
+ \r
+ auto emb_audio_flag = (blue_emb_audio_enable | blue_emb_audio_group1_enable);\r
+\r
+ if (!is_epoch_card(card_type))\r
+ {\r
+ encode_hanc_frame(&hanc_stream_info, audio_data, audio_nchannels, \r
+ audio_samples, sample_type, emb_audio_flag); \r
+ }\r
+ else\r
+ {\r
+ encode_hanc_frame_ex(card_type, &hanc_stream_info, audio_data, audio_nchannels,\r
+ audio_samples, sample_type, emb_audio_flag);\r
+ } \r
+ }\r
};\r
\r
-frame_consumer_device::frame_consumer_device(frame_consumer_device&& other) : impl_(std::move(other.impl_)){}\r
-frame_consumer_device::frame_consumer_device(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers) : impl_(new implementation(format_desc, consumers)){}\r
-void frame_consumer_device::consume(safe_ptr<const read_frame>&& future_frame) { impl_->consume(std::move(future_frame)); }\r
-}}
\ No newline at end of file
+consumer::consumer(consumer&& other) : impl_(std::move(other.impl_)){}\r
+consumer::consumer(const video_format_desc& format_desc, unsigned int device_index, bool embed_audio) : impl_(new implementation(format_desc, device_index, embed_audio)){} \r
+void consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
+size_t consumer::buffer_depth() const{return impl_->buffer_depth();}\r
+}}}\r
+\r
+#endif
\ No newline at end of file
class frame_consumer_device : boost::noncopyable\r
{\r
public:\r
+ explicit frame_consumer_device(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers);\r
frame_consumer_device(frame_consumer_device&& other);\r
- frame_consumer_device(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers);\r
void consume(safe_ptr<const read_frame>&& future_frame); // nothrow\r
private:\r
struct implementation;\r
\r
struct consumer::implementation : public sf::SoundStream, boost::noncopyable\r
{\r
- implementation() : container_(5)\r
+ tbb::concurrent_bounded_queue<std::vector<short>> input_;\r
+ boost::circular_buffer<std::vector<short>> container_;\r
+\r
+public:\r
+ implementation() \r
+ : container_(5)\r
{\r
sf::SoundStream::Initialize(2, 48000);\r
Play(); \r
input_.push(std::vector<short>(frame->audio_data().begin(), frame->audio_data().end())); \r
}\r
\r
- frame_consumer::sync_mode synchronize()\r
- {\r
- return frame_consumer::ready;\r
- }\r
-\r
size_t buffer_depth() const\r
{\r
return 3;\r
\r
return true;\r
}\r
-\r
- tbb::concurrent_bounded_queue<std::vector<short>> input_;\r
- boost::circular_buffer<std::vector<short>> container_;\r
};\r
\r
consumer::consumer(consumer&& other) : impl_(std::move(other.impl_)){}\r
consumer::consumer(const video_format_desc&) : impl_(new implementation()){}\r
void consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
-frame_consumer::sync_mode consumer::synchronize(){return impl_->synchronize();}\r
size_t consumer::buffer_depth() const{return impl_->buffer_depth();}\r
}}}\r
class consumer : public frame_consumer\r
{\r
public: \r
- consumer(consumer&& other);\r
explicit consumer(const video_format_desc& format_desc);\r
+ consumer(consumer&& other);\r
\r
virtual void send(const safe_ptr<const read_frame>&);\r
- virtual sync_mode synchronize();\r
virtual size_t buffer_depth() const;\r
private:\r
struct implementation;\r
#include "../../format/video_format.h"\r
#include "../../processor/read_frame.h"\r
\r
-#include <common/gl/utility.h>\r
+#include <common/gl/gl_check.h>\r
#include <common/concurrency/executor.h>\r
#include <common/utility/safe_ptr.h>\r
\r
namespace caspar { namespace core { namespace ogl{ \r
\r
struct consumer::implementation : boost::noncopyable\r
-{ \r
+{ \r
+ boost::unique_future<void> active_;\r
+ executor executor_;\r
+ \r
+ float wratio_;\r
+ float hratio_;\r
+ \r
+ float wSize_;\r
+ float hSize_;\r
+\r
+ GLuint texture_;\r
+ std::array<GLuint, 2> pbos_;\r
+\r
+ bool windowed_;\r
+ unsigned int screen_width_;\r
+ unsigned int screen_height_;\r
+ unsigned int screen_x_;\r
+ unsigned int screen_y_;\r
+ \r
+ stretch stretch_;\r
+ const video_format_desc format_desc_;\r
+ \r
+ sf::Window window_;\r
+\r
+public:\r
implementation(const video_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed) \r
- : format_desc_(format_desc), stretch_(stretch), screen_width_(0), screen_height_(0), windowed_(windowed), texture_(0)\r
+ : format_desc_(format_desc)\r
+ , stretch_(stretch)\r
+ , windowed_(windowed)\r
+ , texture_(0)\r
+ , screen_width_(format_desc.width)\r
+ , screen_height_(format_desc.height)\r
+ , screen_x_(0)\r
+ , screen_y_(0)\r
{ \r
#ifdef _WIN32\r
DISPLAY_DEVICE d_device; \r
\r
if(screen_index != 0)\r
CASPAR_LOG(warning) << "OGLConsumer only supports screen_index=0 for non-Win32";\r
- \r
- screen_width_ = format_desc_.width;\r
- screen_height_ = format_desc_.height;\r
- screen_x_ = 0;\r
- screen_y_ = 0;\r
#endif\r
\r
executor_.start();\r
glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, format_desc_.size, 0, GL_STREAM_DRAW_ARB);\r
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);\r
});\r
+ active_ = executor_.begin_invoke([]{});\r
}\r
\r
std::pair<float, float> None()\r
\r
void send(const safe_ptr<const read_frame>& frame)\r
{\r
+ active_.get();\r
active_ = executor_.begin_invoke([=]\r
{\r
sf::Event e;\r
});\r
}\r
\r
- frame_consumer::sync_mode synchronize()\r
- {\r
- active_.get();\r
- return frame_consumer::ready;\r
- }\r
\r
size_t buffer_depth() const\r
{\r
return 2;\r
}\r
- \r
- boost::unique_future<void> active_;\r
- executor executor_;\r
- \r
- float wratio_;\r
- float hratio_;\r
- \r
- float wSize_;\r
- float hSize_;\r
-\r
- GLuint texture_;\r
- std::array<GLuint, 2> pbos_;\r
-\r
- bool windowed_;\r
- unsigned int screen_width_;\r
- unsigned int screen_height_;\r
- unsigned int screen_x_;\r
- unsigned int screen_y_;\r
- \r
- stretch stretch_;\r
- const video_format_desc format_desc_;\r
- \r
- sf::Window window_;\r
};\r
\r
consumer::consumer(consumer&& other) : impl_(std::move(other.impl_)){}\r
-consumer::consumer(const video_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed)\r
-: impl_(new implementation(format_desc, screen_index, stretch, windowed)){}\r
+consumer::consumer(const video_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed) : impl_(new implementation(format_desc, screen_index, stretch, windowed)){}\r
void consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
-frame_consumer::sync_mode consumer::synchronize(){return impl_->synchronize();}\r
size_t consumer::buffer_depth() const{return impl_->buffer_depth();}\r
}}}\r
class consumer : public frame_consumer\r
{\r
public: \r
- consumer(consumer&& other);\r
explicit consumer(const video_format_desc& format_desc, unsigned int screen_index = 0, stretch stretch = stretch::fill, bool windowed = false);\r
+ consumer(consumer&& other);\r
\r
virtual void send(const safe_ptr<const read_frame>&);\r
- virtual sync_mode synchronize();\r
virtual size_t buffer_depth() const;\r
private:\r
struct implementation;\r
\r
#include <array>\r
\r
-#define DEFINE_VIDEOFORMATDESC(w, h, m, f, s, fmt) { (fmt), (w), (h), (m), (f), (m == video_mode::progressive ? f : f/2.0), (1.0/(m == video_mode::progressive ? f : f/2.0)), ((w)*(h)*4), (s) }\r
+#define DEFINE_VIDEOFORMATDESC(w, h, m, f, s, fmt) { (fmt), (w), (h), (m), (m == video_mode::progressive ? f : f/2.0), (1.0/(m == video_mode::progressive ? f : f/2.0)), ((w)*(h)*4), (s) }\r
\r
namespace caspar { namespace core {\r
\r
\r
struct video_format_desc\r
{\r
- video_format::type format;\r
+ video_format::type format; // video output format\r
\r
- size_t width;\r
- size_t height;\r
- video_mode::type mode;\r
- double fps;\r
- double actual_fps;\r
- double actual_interval;\r
- size_t size;\r
- std::wstring name;\r
+ size_t width; // output frame width\r
+ size_t height; // output frame height\r
+ video_mode::type mode; // progressive, interlaced upper field first, interlaced lower field first\r
+ double fps; // actual framerate, e.g. i50 = 25 fps, p50 = 50 fps\r
+ double interval; // time between frames\r
+ size_t size; // output frame size in bytes \r
+ std::wstring name; // name of output format\r
\r
static const video_format_desc& get(video_format::type format);\r
static const video_format_desc& get(const std::wstring& name);\r
\r
struct audio_processor::implementation\r
{\r
+ std::vector<short> audio_data_;\r
+ std::stack<audio_transform> transform_stack_;\r
+\r
+public:\r
implementation()\r
{\r
transform_stack_.push(audio_transform());\r
{\r
return std::move(audio_data_);\r
}\r
-\r
- std::vector<short> audio_data_;\r
- std::stack<audio_transform> transform_stack_;\r
};\r
\r
audio_processor::audio_processor() : impl_(new implementation()){}\r
\r
#include "device_buffer.h"\r
\r
-#include <common/gl/utility.h>\r
+#include <common/gl/gl_check.h>\r
\r
namespace caspar { namespace core {\r
\r
\r
struct device_buffer::implementation : boost::noncopyable\r
{\r
- implementation(size_t width, size_t height, size_t stride) : width_(width), height_(height), stride_(stride)\r
+ GLuint id_;\r
+\r
+ const size_t width_;\r
+ const size_t height_;\r
+ const size_t stride_;\r
+\r
+public:\r
+ implementation(size_t width, size_t height, size_t stride) \r
+ : width_(width)\r
+ , height_(height)\r
+ , stride_(stride)\r
{ \r
GL(glGenTextures(1, &id_));\r
GL(glBindTexture(GL_TEXTURE_2D, id_));\r
{\r
GL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + index, GL_TEXTURE_2D, id_, 0));\r
}\r
-\r
- GLuint id_;\r
-\r
- const size_t width_;\r
- const size_t height_;\r
- const size_t stride_;\r
};\r
\r
device_buffer::device_buffer(size_t width, size_t height, size_t stride) : impl_(new implementation(width, height, stride)){}\r
#include "audio_processor.h"\r
#include "pixel_format.h"\r
\r
-#include <common/utility/singleton_pool.h>\r
-\r
#include <boost/range/algorithm.hpp>\r
\r
namespace caspar { namespace core {\r
\r
struct draw_frame::implementation\r
-{\r
- implementation(const std::vector<safe_ptr<draw_frame>>& frames) : frames_(frames){}\r
- implementation(std::vector<safe_ptr<draw_frame>>&& frames) : frames_(std::move(frames)){}\r
+{ \r
+ std::vector<safe_ptr<draw_frame>> frames_;\r
+\r
+ image_transform image_transform_; \r
+ audio_transform audio_transform_;\r
+\r
+public:\r
+ implementation(const std::vector<safe_ptr<draw_frame>>& frames) \r
+ : frames_(frames){}\r
+ implementation(std::vector<safe_ptr<draw_frame>>&& frames) \r
+ : frames_(std::move(frames)){}\r
\r
void process_image(image_processor& processor)\r
{\r
processor.begin(audio_transform_);\r
boost::range::for_each(frames_, std::bind(&draw_frame::process_audio, std::placeholders::_1, std::ref(processor)));\r
processor.end();\r
- }\r
- \r
- std::vector<safe_ptr<draw_frame>> frames_;\r
-\r
- image_transform image_transform_; \r
- audio_transform audio_transform_; \r
+ } \r
};\r
\r
-draw_frame::draw_frame() : impl_(singleton_pool<implementation>::make_shared(std::vector<safe_ptr<draw_frame>>())){}\r
-draw_frame::draw_frame(const std::vector<safe_ptr<draw_frame>>& frames) : impl_(singleton_pool<implementation>::make_shared(frames)){}\r
-draw_frame::draw_frame(std::vector<safe_ptr<draw_frame>>&& frames) : impl_(singleton_pool<implementation>::make_shared(std::move(frames))){}\r
-draw_frame::draw_frame(const draw_frame& other) : impl_(singleton_pool<implementation>::make_shared(*other.impl_)){}\r
+draw_frame::draw_frame() : impl_(new implementation(std::vector<safe_ptr<draw_frame>>())){}\r
+draw_frame::draw_frame(const std::vector<safe_ptr<draw_frame>>& frames) : impl_(new implementation(frames)){}\r
+draw_frame::draw_frame(std::vector<safe_ptr<draw_frame>>&& frames) : impl_(new implementation(std::move(frames))){}\r
+draw_frame::draw_frame(const draw_frame& other) : impl_(new implementation(*other.impl_)){}\r
draw_frame::draw_frame(const safe_ptr<draw_frame>& frame)\r
{\r
std::vector<safe_ptr<draw_frame>> frames;\r
frames.push_back(frame);\r
- impl_ = singleton_pool<implementation>::make_shared(std::move(frames));\r
+ impl_.reset(new implementation(std::move(frames)));\r
}\r
draw_frame::draw_frame(safe_ptr<draw_frame>&& frame)\r
{\r
std::vector<safe_ptr<draw_frame>> frames;\r
frames.push_back(std::move(frame));\r
- impl_ = singleton_pool<implementation>::make_shared(std::move(frames));\r
+ impl_.reset(new implementation(std::move(frames)));\r
}\r
draw_frame::draw_frame(const safe_ptr<draw_frame>& frame1, const safe_ptr<draw_frame>& frame2)\r
{\r
std::vector<safe_ptr<draw_frame>> frames;\r
frames.push_back(frame1);\r
frames.push_back(frame2);\r
- impl_ = singleton_pool<implementation>::make_shared(std::move(frames));\r
+ impl_.reset(new implementation(std::move(frames)));\r
}\r
draw_frame::draw_frame(safe_ptr<draw_frame>&& frame1, safe_ptr<draw_frame>&& frame2)\r
{\r
std::vector<safe_ptr<draw_frame>> frames;\r
frames.push_back(std::move(frame1));\r
frames.push_back(std::move(frame2));\r
- impl_ = singleton_pool<implementation>::make_shared(std::move(frames));\r
+ impl_.reset(new implementation(std::move(frames)));\r
}\r
\r
void draw_frame::swap(draw_frame& other){impl_.swap(other.impl_);}\r
\r
#include <common/exception/exceptions.h>\r
#include <common/concurrency/executor.h>\r
-#include <common/gl/utility.h>\r
+#include <common/gl/gl_check.h>\r
\r
#include <tbb/concurrent_queue.h>\r
#include <tbb/concurrent_unordered_map.h>\r
namespace caspar { namespace core {\r
\r
struct frame_processor_device::implementation : boost::noncopyable\r
-{ \r
- implementation(const video_format_desc& format_desc) : fmt_(format_desc), image_processor_(format_desc){}\r
+{ \r
+ const video_format_desc format_desc_;\r
+\r
+ audio_processor audio_processor_;\r
+ image_processor image_processor_;\r
+\r
+public:\r
+ implementation(const video_format_desc& format_desc) \r
+ : format_desc_(format_desc)\r
+ , image_processor_(format_desc){}\r
\r
safe_ptr<const read_frame> process(safe_ptr<draw_frame>&& frame)\r
{ \r
{\r
return make_safe<write_frame>(desc, image_processor_.create_buffers(desc));\r
}\r
- \r
- const video_format_desc format_desc_;\r
- \r
- audio_processor audio_processor_;\r
- image_processor image_processor_;\r
- \r
- const video_format_desc fmt_;\r
};\r
\r
frame_processor_device::frame_processor_device(frame_processor_device&& other) : impl_(std::move(other.impl_)){}\r
frame_processor_device::frame_processor_device(const video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
safe_ptr<const read_frame> frame_processor_device::process(safe_ptr<draw_frame>&& frame){return impl_->process(std::move(frame));}\r
-const video_format_desc& frame_processor_device::get_video_format_desc() const { return impl_->fmt_; }\r
+const video_format_desc& frame_processor_device::get_video_format_desc() const { return impl_->format_desc_; }\r
safe_ptr<write_frame> frame_processor_device::create_frame(const pixel_format_desc& desc){ return impl_->create_frame(desc); } \r
safe_ptr<write_frame> frame_processor_device::create_frame(size_t width, size_t height, pixel_format::type pix_fmt)\r
{\r
\r
#include "host_buffer.h"\r
\r
-#include <common/gl/utility.h>\r
+#include <common/gl/gl_check.h>\r
\r
namespace caspar { namespace core {\r
\r
struct host_buffer::implementation : boost::noncopyable\r
-{\r
- implementation(size_t size, usage_t usage) : size_(size), data_(nullptr), pbo_(0),\r
- target_(usage == write_only ? GL_PIXEL_UNPACK_BUFFER : GL_PIXEL_PACK_BUFFER), usage_(usage == write_only ? GL_STREAM_DRAW : GL_STREAM_READ)\r
+{ \r
+ GLuint pbo_;\r
+\r
+ const size_t size_;\r
+\r
+ void* data_;\r
+ GLenum usage_;\r
+ GLenum target_;\r
+\r
+public:\r
+ implementation(size_t size, usage_t usage) \r
+ : size_(size)\r
+ , data_(nullptr)\r
+ , pbo_(0)\r
+ , target_(usage == write_only ? GL_PIXEL_UNPACK_BUFFER : GL_PIXEL_PACK_BUFFER)\r
+ , usage_(usage == write_only ? GL_STREAM_DRAW : GL_STREAM_READ)\r
{\r
GL(glGenBuffers(1, &pbo_));\r
GL(glBindBuffer(target_, pbo_));\r
{\r
GL(glBindBuffer(target_, 0));\r
}\r
- \r
- GLuint pbo_;\r
-\r
- const size_t size_;\r
-\r
- void* data_;\r
- GLenum usage_;\r
- GLenum target_;\r
};\r
\r
host_buffer::host_buffer(size_t size, usage_t usage) : impl_(new implementation(size, usage)){}\r
#include "image_kernel.h"\r
\r
#include <common/exception/exceptions.h>\r
-#include <common/gl/utility.h>\r
+#include <common/gl/gl_check.h>\r
\r
#include <Glee.h>\r
\r
\r
class shader_program\r
{\r
+ GLuint program_;\r
public:\r
\r
shader_program() : program_(0) {}\r
{ \r
GL(glUseProgramObjectARB(program_)); \r
}\r
-\r
-private:\r
- GLuint program_;\r
};\r
\r
GLubyte progressive_pattern[] = {\r
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff};\r
\r
struct image_kernel::implementation\r
-{\r
+{ \r
+ std::unordered_map<pixel_format::type, shader_program> shaders_;\r
+\r
+public:\r
std::unordered_map<pixel_format::type, shader_program>& shaders()\r
{\r
GL(glEnable(GL_POLYGON_STIPPLE));\r
}\r
return shaders_;\r
}\r
- \r
- std::unordered_map<pixel_format::type, shader_program> shaders_;\r
};\r
\r
image_kernel::image_kernel() : impl_(new implementation()){}\r
#include "device_buffer.h"\r
\r
#include <common/exception/exceptions.h>\r
-#include <common/gl/utility.h>\r
+#include <common/gl/gl_check.h>\r
#include <common/concurrency/executor.h>\r
\r
#include <Glee.h>\r
}\r
\r
struct image_processor::implementation : boost::noncopyable\r
-{ \r
+{ \r
+ ogl_device context_;\r
+\r
+ const video_format_desc format_desc_;\r
+ \r
+ std::stack<image_transform> transform_stack_;\r
+\r
+ GLuint fbo_;\r
+ std::array<std::shared_ptr<device_buffer>, 2> render_targets_;\r
+\r
+ std::shared_ptr<host_buffer> reading_;\r
+\r
+ image_kernel kernel_;\r
+\r
+public:\r
implementation(const video_format_desc& format_desc) : format_desc_(format_desc)\r
{\r
context_.begin_invoke([=]\r
});\r
return buffers;\r
}\r
- \r
- ogl_device context_;\r
-\r
- const video_format_desc format_desc_;\r
- \r
- std::stack<image_transform> transform_stack_;\r
-\r
- GLuint fbo_;\r
- std::array<std::shared_ptr<device_buffer>, 2> render_targets_;\r
-\r
- std::shared_ptr<host_buffer> reading_;\r
-\r
- image_kernel kernel_;\r
};\r
\r
image_processor::image_processor(const video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
\r
safe_ptr<device_buffer> create_device_buffer(size_t width, size_t height, size_t stride);\r
safe_ptr<host_buffer> create_host_buffer(size_t size, host_buffer::usage_t usage);\r
+\r
private:\r
executor executor_;\r
std::unique_ptr<sf::Context> context_;\r
\r
#include "host_buffer.h"\r
\r
-#include <common/gl/utility.h>\r
-#include <common/utility/singleton_pool.h>\r
+#include <common/gl/gl_check.h>\r
\r
namespace caspar { namespace core {\r
\r
struct read_frame::implementation : boost::noncopyable\r
{\r
- implementation(safe_ptr<const host_buffer>&& image_data, std::vector<short>&& audio_data) : image_data_(std::move(image_data)), audio_data_(std::move(audio_data)){} \r
-\r
safe_ptr<const host_buffer> image_data_;\r
std::vector<short> audio_data_;\r
+\r
+public:\r
+ implementation(safe_ptr<const host_buffer>&& image_data, std::vector<short>&& audio_data) \r
+ : image_data_(std::move(image_data))\r
+ , audio_data_(std::move(audio_data)){} \r
};\r
\r
read_frame::read_frame(){}\r
-read_frame::read_frame(safe_ptr<const host_buffer>&& image_data, std::vector<short>&& audio_data) : impl_(singleton_pool<implementation>::make_shared(image_data, audio_data)){}\r
+read_frame::read_frame(safe_ptr<const host_buffer>&& image_data, std::vector<short>&& audio_data) : impl_(new implementation(std::move(image_data), std::move(audio_data))){}\r
\r
const boost::iterator_range<const unsigned char*> read_frame::image_data() const\r
{\r
#include "audio_processor.h"\r
#include "pixel_format.h"\r
\r
-#include "../../common/gl/utility.h"\r
-#include "../../common/utility/singleton_pool.h"\r
+#include <common/gl/gl_check.h>\r
\r
#include <boost/range/algorithm.hpp>\r
\r
namespace caspar { namespace core {\r
\r
struct write_frame::implementation : boost::noncopyable\r
-{\r
- implementation(const pixel_format_desc& desc, std::vector<safe_ptr<host_buffer>> buffers) : desc_(desc), buffers_(buffers){}\r
+{ \r
+ std::vector<safe_ptr<host_buffer>> buffers_;\r
+ std::vector<short> audio_data_;\r
+ const pixel_format_desc desc_;\r
+\r
+public:\r
+ implementation(const pixel_format_desc& desc, std::vector<safe_ptr<host_buffer>> buffers) \r
+ : desc_(desc)\r
+ , buffers_(buffers){}\r
\r
void process_image(image_processor& processor)\r
{\r
auto ptr = static_cast<const unsigned char*>(buffers_[index]->data());\r
return boost::iterator_range<const unsigned char*>(ptr, ptr+buffers_[index]->size());\r
}\r
- \r
- std::vector<safe_ptr<host_buffer>> buffers_;\r
- std::vector<short> audio_data_;\r
- const pixel_format_desc desc_;\r
};\r
\r
-write_frame::write_frame(const pixel_format_desc& desc, std::vector<safe_ptr<host_buffer>> buffers) : impl_(singleton_pool<implementation>::make_shared(desc, buffers)){}\r
+write_frame::write_frame(const pixel_format_desc& desc, std::vector<safe_ptr<host_buffer>> buffers) : impl_(new implementation(desc, buffers)){}\r
write_frame::write_frame(write_frame&& other) : impl_(std::move(other.impl_)){}\r
void write_frame::swap(write_frame& other){impl_.swap(other.impl_);}\r
write_frame& write_frame::operator=(write_frame&& other)\r
\r
class color_producer : public frame_producer\r
{\r
+ safe_ptr<draw_frame> frame_;\r
+ std::wstring color_str_;\r
+\r
public:\r
- color_producer(color_producer&& other) : frame_(std::move(other.frame_)), color_str_(std::move(other.color_str_)){}\r
+ explicit color_producer(color_producer&& other) \r
+ : frame_(std::move(other.frame_))\r
+ , color_str_(std::move(other.color_str_)){}\r
\r
explicit color_producer(const std::wstring& color) : color_str_(color), frame_(draw_frame::empty())\r
{\r
}\r
\r
virtual std::wstring print() const { return + L"color[" + color_str_ + L"]"; }\r
-\r
- safe_ptr<draw_frame> frame_;\r
- std::wstring color_str_;\r
};\r
\r
safe_ptr<frame_producer> create_color_producer(const std::vector<std::wstring>& params)\r
\r
struct audio_decoder::implementation : boost::noncopyable\r
{\r
+ typedef std::vector<short, tbb::cache_aligned_allocator<short>> buffer;\r
+ \r
+ AVCodecContext* codec_context_;\r
+\r
+ buffer audio_buffer_; \r
+ buffer current_chunk_;\r
+\r
+ size_t audio_frame_size_;\r
+\r
static const size_t SAMPLE_RATE = 48000;\r
static const size_t N_CHANNELS = 2;\r
\r
- implementation(AVCodecContext* codec_context, double fps) : current_chunk_(), codec_context_(codec_context), audio_buffer_(4*SAMPLE_RATE*2+FF_INPUT_BUFFER_PADDING_SIZE/2)\r
+public:\r
+ explicit implementation(AVCodecContext* codec_context, double fps) \r
+ : codec_context_(codec_context)\r
+ , audio_buffer_(4*SAMPLE_RATE*2+FF_INPUT_BUFFER_PADDING_SIZE/2)\r
+ , audio_frame_size_(static_cast<size_t>(static_cast<double>(SAMPLE_RATE) / fps) * N_CHANNELS)\r
{\r
if(codec_context_->sample_rate != SAMPLE_RATE)\r
BOOST_THROW_EXCEPTION(file_read_error() << msg_info("Invalid sample rate. Expected 48000."));\r
\r
if(codec_context_->channels != 2)\r
BOOST_THROW_EXCEPTION(file_read_error() << msg_info("Invalid channel count. Expected 2."));\r
- audio_frame_size_ = static_cast<size_t>(static_cast<double>(SAMPLE_RATE) / fps) * N_CHANNELS;\r
}\r
\r
std::vector<std::vector<short>> execute(const aligned_buffer& audio_packet)\r
\r
return chunks_;\r
}\r
-\r
- size_t audio_frame_size_;\r
-\r
- typedef std::vector<short, tbb::cache_aligned_allocator<short>> buffer;\r
-\r
- buffer audio_buffer_; \r
-\r
- std::vector<short, tbb::cache_aligned_allocator<short>> current_chunk_;\r
-\r
- AVCodecContext* codec_context_;\r
};\r
\r
audio_decoder::audio_decoder(AVCodecContext* codec_context, double fps) : impl_(new implementation(codec_context, fps)){}\r
class audio_decoder : boost::noncopyable\r
{\r
public:\r
- audio_decoder(AVCodecContext* codec_context, double fps);\r
+ explicit audio_decoder(AVCodecContext* codec_context, double fps);\r
std::vector<std::vector<short>> execute(const aligned_buffer& audio_packet);\r
private:\r
struct implementation;\r
\r
struct ffmpeg_producer : public frame_producer\r
{\r
+ input input_; \r
+ audio_decoder audio_decoder_;\r
+ video_decoder video_decoder_;\r
+\r
+ std::deque<safe_ptr<write_frame>> video_frame_channel_; \r
+ std::deque<std::vector<short>> audio_chunk_channel_;\r
+\r
+ std::queue<safe_ptr<draw_frame>> ouput_channel_;\r
+ \r
+ const std::wstring filename_;\r
+ \r
+ safe_ptr<draw_frame> last_frame_;\r
+\r
+ video_format_desc format_desc_;\r
+\r
public:\r
- ffmpeg_producer(const std::wstring& filename, const std::vector<std::wstring>& params) : filename_(filename), last_frame_(draw_frame(draw_frame::empty())),\r
- input_(filename), video_decoder_(input_.get_video_codec_context().get()), audio_decoder_(input_.get_audio_codec_context().get(), input_.fps())\r
+ explicit ffmpeg_producer(const std::wstring& filename, const std::vector<std::wstring>& params) \r
+ : filename_(filename)\r
+ , last_frame_(draw_frame(draw_frame::empty()))\r
+ , input_(filename)\r
+ , video_decoder_(input_.get_video_codec_context().get())\r
+ , audio_decoder_(input_.get_audio_codec_context().get(), input_.fps())\r
{ \r
input_.set_loop(std::find(params.begin(), params.end(), L"LOOP") != params.end());\r
\r
{\r
return L"ffmpeg[" + boost::filesystem::wpath(filename_).filename() + L"]";\r
}\r
-\r
- input input_; \r
- audio_decoder audio_decoder_;\r
- video_decoder video_decoder_;\r
-\r
- std::deque<safe_ptr<write_frame>> video_frame_channel_; \r
- std::deque<std::vector<short>> audio_chunk_channel_;\r
-\r
- std::queue<safe_ptr<draw_frame>> ouput_channel_;\r
- \r
- const std::wstring filename_;\r
- \r
- safe_ptr<draw_frame> last_frame_;\r
-\r
- video_format_desc format_desc_;\r
};\r
\r
safe_ptr<frame_producer> create_ffmpeg_producer(const std::vector<std::wstring>& params)\r
namespace caspar { namespace core { namespace ffmpeg{\r
\r
struct input::implementation : boost::noncopyable\r
-{\r
+{ \r
+ std::shared_ptr<AVFormatContext> format_context_; // Destroy this last\r
+\r
+ std::shared_ptr<AVCodecContext> video_codec_context_;\r
+ std::shared_ptr<AVCodecContext> audio_codex_context_;\r
+\r
+ tbb::queuing_mutex seek_mutex_;\r
+\r
+ const std::wstring filename_;\r
+\r
+ tbb::atomic<bool> loop_;\r
+ int video_s_index_;\r
+ int audio_s_index_;\r
+\r
+ tbb::atomic<size_t> buffer_size_;\r
+ \r
+ tbb::concurrent_bounded_queue<std::shared_ptr<aligned_buffer>> video_packet_buffer_;\r
+ tbb::concurrent_bounded_queue<std::shared_ptr<aligned_buffer>> audio_packet_buffer_;\r
+ \r
+ executor executor_;\r
+\r
static const size_t BUFFER_SIZE = 2 << 25;\r
\r
- implementation(const std::wstring& filename) : video_s_index_(-1), audio_s_index_(-1), filename_(filename)\r
+public:\r
+ explicit implementation(const std::wstring& filename) \r
+ : video_s_index_(-1)\r
+ , audio_s_index_(-1)\r
+ , filename_(filename)\r
{ \r
static boost::once_flag av_register_all_flag = BOOST_ONCE_INIT;\r
boost::call_once(av_register_all, av_register_all_flag); \r
{\r
return L"ffmpeg[" + boost::filesystem::wpath(filename_).filename() + L"] Buffer thread";\r
}\r
- \r
- std::shared_ptr<AVFormatContext> format_context_; // Destroy this last\r
-\r
- tbb::queuing_mutex seek_mutex_;\r
-\r
- const std::wstring filename_;\r
-\r
- std::shared_ptr<AVCodecContext> video_codec_context_;\r
-\r
- std::shared_ptr<AVCodecContext> audio_codex_context_;\r
-\r
- tbb::atomic<bool> loop_;\r
- int video_s_index_;\r
- int audio_s_index_;\r
- \r
- tbb::concurrent_bounded_queue<std::shared_ptr<aligned_buffer>> video_packet_buffer_;\r
- tbb::concurrent_bounded_queue<std::shared_ptr<aligned_buffer>> audio_packet_buffer_;\r
- \r
- tbb::atomic<size_t> buffer_size_;\r
-\r
- executor executor_;\r
};\r
\r
input::input(const std::wstring& filename) : impl_(new implementation(filename)){}\r
class input : boost::noncopyable\r
{\r
public:\r
- input(const std::wstring& filename);\r
+ explicit input(const std::wstring& filename);\r
const std::shared_ptr<AVCodecContext>& get_video_codec_context() const;\r
const std::shared_ptr<AVCodecContext>& get_audio_codec_context() const;\r
\r
}\r
\r
struct video_decoder::implementation : boost::noncopyable\r
-{\r
- implementation(AVCodecContext* codec_context) : codec_context_(codec_context), width_(codec_context_->width), height_(codec_context_->height), \r
- pix_fmt_(codec_context_->pix_fmt), desc_(get_pixel_format_desc(pix_fmt_, width_, height_))\r
+{ \r
+ std::shared_ptr<frame_processor_device> frame_processor_;\r
+ std::shared_ptr<SwsContext> sws_context_;\r
+\r
+ AVCodecContext* codec_context_;\r
+\r
+ int width_;\r
+ int height_;\r
+ PixelFormat pix_fmt_;\r
+ pixel_format_desc desc_;\r
+\r
+public:\r
+ explicit implementation(AVCodecContext* codec_context) \r
+ : codec_context_(codec_context)\r
+ , width_(codec_context_->width)\r
+ , height_(codec_context_->height)\r
+ , pix_fmt_(codec_context_->pix_fmt)\r
+ , desc_(get_pixel_format_desc(pix_fmt_, width_, height_))\r
{\r
if(desc_.pix_fmt == pixel_format::invalid)\r
{\r
{\r
frame_processor_ = frame_processor; \r
double frame_rate = static_cast<double>(codec_context_->time_base.den) / static_cast<double>(codec_context_->time_base.num);\r
- if(abs(frame_rate - frame_processor->get_video_format_desc().actual_fps) > std::numeric_limits<double>::min())\r
+ if(abs(frame_rate - frame_processor->get_video_format_desc().fps) > std::numeric_limits<double>::min())\r
BOOST_THROW_EXCEPTION(file_read_error() << msg_info("Invalid video framerate."));\r
}\r
- \r
- std::shared_ptr<frame_processor_device> frame_processor_;\r
- std::shared_ptr<SwsContext> sws_context_;\r
-\r
- AVCodecContext* codec_context_;\r
-\r
- int width_;\r
- int height_;\r
- PixelFormat pix_fmt_;\r
- pixel_format_desc desc_;\r
};\r
\r
video_decoder::video_decoder(AVCodecContext* codec_context) : impl_(new implementation(codec_context)){}\r
class video_decoder : boost::noncopyable\r
{\r
public:\r
- video_decoder(AVCodecContext* codec_context);\r
+ explicit video_decoder(AVCodecContext* codec_context);\r
safe_ptr<write_frame> execute(const aligned_buffer& video_packet); \r
void initialize(const safe_ptr<frame_processor_device>& frame_processor);\r
private:\r
struct cg_producer::implementation : boost::noncopyable\r
{\r
public:\r
- implementation() : flash_producer_(flash_producer(configuration::template_folder()+TEXT("cg.fth.18"))){}\r
+ implementation() \r
+ : flash_producer_(flash_producer(configuration::template_folder()+TEXT("cg.fth.18"))){}\r
\r
void clear()\r
{\r
public:\r
static const unsigned int DEFAULT_LAYER = 5000;\r
\r
- cg_producer();\r
+ explicit cg_producer();\r
cg_producer(cg_producer&& other);\r
\r
virtual safe_ptr<draw_frame> receive();\r
\r
class flash_renderer\r
{\r
+ std::wstring filename_;\r
+ std::shared_ptr<frame_processor_device> frame_processor_;\r
+ video_format_desc format_desc_;\r
+ \r
+ BYTE* bmp_data_; \r
+ std::shared_ptr<void> hdc_;\r
+ std::shared_ptr<void> bmp_;\r
+\r
+ CComObject<caspar::flash::FlashAxContainer>* ax_;\r
+ safe_ptr<draw_frame> head_;\r
+\r
public:\r
flash_renderer(const std::shared_ptr<frame_processor_device>& frame_processor, const std::wstring& filename) \r
- : head_(draw_frame::empty()), bmp_data_(nullptr), ax_(nullptr), filename_(filename), hdc_(CreateCompatibleDC(0), DeleteDC), frame_processor_(frame_processor), \r
- format_desc_(frame_processor->get_video_format_desc())\r
+ : head_(draw_frame::empty())\r
+ , bmp_data_(nullptr)\r
+ , ax_(nullptr)\r
+ , filename_(filename)\r
+ , hdc_(CreateCompatibleDC(0), DeleteDC)\r
+ , frame_processor_(frame_processor)\r
+ , format_desc_(frame_processor->get_video_format_desc())\r
{\r
CASPAR_LOG(info) << print() << L" Started";\r
\r
return draw_frame::empty();\r
\r
auto frame = render_simple_frame();\r
- if(ax_->GetFPS()/2.0 - format_desc_.actual_fps >= 0.0)\r
+ if(format_desc_.mode != video_mode::progressive && ax_->GetFPS()/2.0 - format_desc_.fps >= 0.0)\r
frame = draw_frame::interlace(frame, render_simple_frame(), format_desc_.mode);\r
return frame;\r
}\r
\r
return head_;\r
}\r
-\r
- std::wstring filename_;\r
- std::shared_ptr<frame_processor_device> frame_processor_;\r
- video_format_desc format_desc_;\r
- \r
- BYTE* bmp_data_;\r
- \r
- std::shared_ptr<void> hdc_;\r
- std::shared_ptr<void> bmp_;\r
-\r
- CComObject<caspar::flash::FlashAxContainer>* ax_;\r
- safe_ptr<draw_frame> head_;\r
};\r
\r
struct flash_producer::implementation\r
{ \r
- implementation(const std::wstring& filename) : filename_(filename), tail_(draw_frame::empty())\r
+ safe_ptr<draw_frame> tail_;\r
+ tbb::concurrent_bounded_queue<safe_ptr<draw_frame>> frame_buffer_;\r
+ executor executor_;\r
+\r
+ std::shared_ptr<flash_renderer> renderer_;\r
+ std::shared_ptr<frame_processor_device> frame_processor_;\r
+ \r
+ std::wstring print() const{ return L"flash[" + boost::filesystem::wpath(filename_).filename() + L"]"; } \r
+ std::wstring filename_;\r
+\r
+ implementation(const std::wstring& filename) \r
+ : filename_(filename)\r
+ , tail_(draw_frame::empty())\r
{ \r
if(!boost::filesystem::exists(filename))\r
BOOST_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(narrow(filename)));\r
virtual void initialize(const safe_ptr<frame_processor_device>& frame_processor)\r
{\r
frame_processor_ = frame_processor;\r
- frame_buffer_.set_capacity(static_cast<size_t>(frame_processor->get_video_format_desc().actual_fps/2.0));\r
+ frame_buffer_.set_capacity(static_cast<size_t>(frame_processor->get_video_format_desc().fps/2.0));\r
while(frame_buffer_.try_push(draw_frame::empty())){}\r
executor_.start();\r
}\r
}\r
});\r
}\r
-\r
- safe_ptr<draw_frame> tail_;\r
- tbb::concurrent_bounded_queue<safe_ptr<draw_frame>> frame_buffer_;\r
- executor executor_;\r
-\r
- std::shared_ptr<flash_renderer> renderer_;\r
- std::shared_ptr<frame_processor_device> frame_processor_;\r
- \r
- std::wstring print() const{ return L"flash[" + boost::filesystem::wpath(filename_).filename() + L"]"; } \r
- std::wstring filename_;\r
};\r
\r
flash_producer::flash_producer(flash_producer&& other) : impl_(std::move(other.impl_)){}\r
class flash_producer : public frame_producer\r
{\r
public:\r
+ explicit flash_producer(const std::wstring& filename);\r
flash_producer(flash_producer&& other);\r
\r
- flash_producer(const std::wstring& filename);\r
-\r
virtual safe_ptr<draw_frame> receive();\r
virtual void initialize(const safe_ptr<frame_processor_device>& frame_processor);\r
virtual std::wstring print() const;\r
namespace caspar { namespace core { namespace image{\r
\r
struct image_producer : public frame_producer\r
-{\r
- image_producer(image_producer&& other) : frame_processor_(std::move(other.frame_processor_)), filename_(std::move(other.filename_)), frame_(draw_frame::empty()){}\r
- image_producer(const std::wstring& filename) : filename_(filename), frame_(draw_frame::empty()) {}\r
+{ \r
+ std::shared_ptr<frame_processor_device> frame_processor_;\r
+ std::wstring filename_;\r
+ safe_ptr<draw_frame> frame_;\r
+\r
+ image_producer(image_producer&& other) \r
+ : frame_processor_(std::move(other.frame_processor_))\r
+ , filename_(std::move(other.filename_))\r
+ , frame_(draw_frame::empty()){}\r
+\r
+ image_producer(const std::wstring& filename) \r
+ : filename_(filename), frame_(draw_frame::empty()) {}\r
\r
virtual safe_ptr<draw_frame> receive(){return frame_;}\r
\r
{\r
return L"image_producer. filename: " + filename_;\r
}\r
- \r
- std::shared_ptr<frame_processor_device> frame_processor_;\r
- std::wstring filename_;\r
- safe_ptr<draw_frame> frame_;\r
};\r
\r
safe_ptr<frame_producer> create_image_producer(const std::vector<std::wstring>& params)\r
namespace caspar { namespace core {\r
\r
struct layer::implementation : boost::noncopyable\r
-{ \r
- implementation(size_t index) : foreground_(frame_producer::empty()), background_(frame_producer::empty()), last_frame_(draw_frame::empty()), index_(index) {}\r
+{ \r
+ std::wstring print() const { return L"layer[" + boost::lexical_cast<std::wstring>(index_) + L"]"; }\r
+ \r
+ tbb::atomic<bool> is_paused_;\r
+ safe_ptr<draw_frame> last_frame_;\r
+ safe_ptr<frame_producer> foreground_;\r
+ safe_ptr<frame_producer> background_;\r
+ const size_t index_;\r
+\r
+public:\r
+ implementation(size_t index) \r
+ : foreground_(frame_producer::empty())\r
+ , background_(frame_producer::empty())\r
+ , last_frame_(draw_frame::empty())\r
+ , index_(index) {}\r
\r
void load(const safe_ptr<frame_producer>& frame_producer, bool autoplay)\r
{ \r
\r
return last_frame_;\r
}\r
-\r
- std::wstring print() const { return L"layer[" + boost::lexical_cast<std::wstring>(index_) + L"]"; }\r
- \r
- tbb::atomic<bool> is_paused_;\r
- safe_ptr<draw_frame> last_frame_;\r
- safe_ptr<frame_producer> foreground_;\r
- safe_ptr<frame_producer> background_;\r
- const size_t index_;\r
};\r
\r
layer::layer(size_t index) : impl_(new implementation(index)){}\r
namespace caspar { namespace core { \r
\r
struct transition_producer::implementation : boost::noncopyable\r
-{\r
- implementation(const safe_ptr<frame_producer>& dest, const transition_info& info) : current_frame_(0), info_(info), \r
- dest_producer_(dest), source_producer_(frame_producer::empty())\r
+{ \r
+ unsigned short current_frame_;\r
+ \r
+ const transition_info info_;\r
+ \r
+ safe_ptr<frame_producer> dest_producer_;\r
+ safe_ptr<frame_producer> source_producer_;\r
+\r
+ std::shared_ptr<frame_processor_device> frame_processor_;\r
+\r
+ implementation(const safe_ptr<frame_producer>& dest, const transition_info& info) \r
+ : current_frame_(0)\r
+ , info_(info)\r
+ , dest_producer_(dest)\r
+ , source_producer_(frame_producer::empty())\r
{}\r
\r
safe_ptr<frame_producer> get_following_producer() const\r
}\r
\r
safe_ptr<draw_frame> receive()\r
- {\r
- return render_frame();\r
- }\r
-\r
- safe_ptr<draw_frame> render_frame()\r
{\r
if(current_frame_++ >= info_.duration)\r
return draw_frame::eof();\r
\r
return compose(dest, source);\r
}\r
-\r
+ \r
safe_ptr<draw_frame> render_sub_frame(safe_ptr<frame_producer>& producer)\r
{\r
if(producer == frame_producer::empty())\r
{\r
return L"transition[" + (source_producer_->print()) + L" -> " + (dest_producer_->print()) + L"]";\r
}\r
- \r
- safe_ptr<frame_producer> source_producer_;\r
- safe_ptr<frame_producer> dest_producer_;\r
- \r
- unsigned short current_frame_;\r
- \r
- const transition_info info_;\r
- std::shared_ptr<frame_processor_device> frame_processor_;\r
};\r
\r
transition_producer::transition_producer(transition_producer&& other) : impl_(std::move(other.impl_)){}\r
class transition_producer : public frame_producer\r
{\r
public:\r
+ explicit transition_producer(const safe_ptr<frame_producer>& destination, const transition_info& info);\r
transition_producer(transition_producer&& other);\r
\r
- transition_producer(const safe_ptr<frame_producer>& destination, const transition_info& info);\r
-\r
virtual safe_ptr<draw_frame> receive();\r
\r
virtual safe_ptr<frame_producer> get_following_producer() const;\r
</paths>\r
<channels>\r
<channel>\r
- <videomode>720p2500</videomode>\r
+ <videomode>PAL</videomode>\r
<consumers>\r
- <ogl>\r
+ <!--ogl>\r
<device>0</device>\r
<stretch>uniform</stretch>\r
<windowed>true</windowed>\r
</ogl>\r
- <audio/>\r
- <!--decklink> \r
- </decklink>\r
+ <audio/-->\r
+ <!--decklink>\r
+ <device>1</device>\r
+ </decklink-->\r
<bluefish>\r
<device>1</device> \r
<embedded-audio>true</embedded-audio>\r
- </bluefish-->\r
+ </bluefish>\r
</consumers>\r
</channel>\r
</channels>\r