</Lib>\r
</ItemDefinitionGroup>\r
<ItemGroup>\r
+ <ClInclude Include="cpu\image\deinterlacer.h" />\r
<ClInclude Include="cpu\image\image_mixer.h" />\r
<ClInclude Include="cpu\util\xmm.h" />\r
<ClInclude Include="accelerator.h" />\r
</ItemGroup>\r
<ItemGroup>\r
<ClCompile Include="accelerator.cpp" />\r
+ <ClCompile Include="cpu\image\deinterlacer.cpp">\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
+ </ClCompile>\r
<ClCompile Include="cpu\image\image_mixer.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
<ClInclude Include="ogl\util\buffer.h">\r
<Filter>source\ogl\util</Filter>\r
</ClInclude>\r
+ <ClInclude Include="cpu\image\deinterlacer.h">\r
+ <Filter>source\cpu\image</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<ClCompile Include="StdAfx.cpp" />\r
<ClCompile Include="ogl\util\buffer.cpp">\r
<Filter>source\ogl\util</Filter>\r
</ClCompile>\r
+ <ClCompile Include="cpu\image\deinterlacer.cpp">\r
+ <Filter>source\cpu\image</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
--- /dev/null
+#include "../../StdAfx.h"\r
+\r
+#include "deinterlacer.h"\r
+/*\r
+#include <core/frame/frame_factory.h>\r
+\r
+#include <modules/ffmpeg/producer/filter/filter.h>\r
+#include <modules/ffmpeg/producer/util/util.h>\r
+\r
+#include <tbb/concurrent_hash_map.h>\r
+\r
+#include <tuple>\r
+\r
+namespace caspar { namespace accelerator { namespace cpu {\r
+\r
+struct deinterlacer::impl : public std::enable_shared_from_this<impl> \r
+{\r
+ ffmpeg::filter filter_;\r
+\r
+ typedef tbb::concurrent_hash_map<const void*, std::tuple<boost::signals2::scoped_connection, std::vector<core::const_frame>>> cache_t; \r
+\r
+ cache_t frame_cache_;\r
+\r
+public:\r
+\r
+ impl() \r
+ : filter_(L"YADIF=1:-1")\r
+ {\r
+ }\r
+\r
+ std::vector<core::const_frame> operator()(const core::const_frame& frame, core::frame_factory& frame_factory)\r
+ {\r
+ auto tag = frame.data_tag();\r
+\r
+ cache_t::const_accessor a;\r
+ \r
+ if(frame_cache_.find(a, tag))\r
+ return std::get<1>(a->second);\r
+ \r
+ std::array<uint8_t*, 4> data = {};\r
+ for(int n = 0; n < frame.pixel_format_desc().planes.size(); ++n)\r
+ data[n] = const_cast<uint8_t*>(frame.image_data(n).begin());\r
+\r
+ auto av_frame = ffmpeg::make_av_frame(data, frame.pixel_format_desc());\r
+\r
+ filter_.push(av_frame);\r
+\r
+ auto av_frames = filter_.poll_all();\r
+\r
+ std::vector<core::const_frame> frames;\r
+\r
+ BOOST_FOREACH(auto av_frame, av_frames)\r
+ frames.push_back(ffmpeg::make_frame(tag, av_frame, frame.frame_rate(), frame_factory, 0));\r
+\r
+ std::weak_ptr<impl> self = shared_from_this();\r
+ auto connection = frame.on_released.connect(std::function<void()>([self, tag]() mutable\r
+ {\r
+ auto self2 = self.lock();\r
+ if(self2)\r
+ self2->frame_cache_.erase(tag);\r
+ }));\r
+\r
+ frame_cache_.insert(std::make_pair(&frame, std::make_tuple(connection, frames)));\r
+\r
+ return frames;\r
+ } \r
+};\r
+\r
+deinterlacer::deinterlacer() : impl_(new impl()){}\r
+deinterlacer::~deinterlacer(){}\r
+std::vector<core::const_frame> deinterlacer::operator()(const core::const_frame& frame, core::frame_factory& frame_factory){return (*impl_)(frame, frame_factory);}\r
+\r
+}}}*/
\ No newline at end of file
--- /dev/null
+#pragma once\r
+/*\r
+#include <common/forward.h>\r
+\r
+#include <core/frame/frame.h>\r
+\r
+FORWARD2(caspar, core, class frame_factory);\r
+\r
+namespace caspar { namespace accelerator { namespace cpu {\r
+ \r
+class deinterlacer sealed \r
+{\r
+public:\r
+\r
+ // Static Members\r
+\r
+ // Constructors\r
+\r
+ deinterlacer();\r
+ ~deinterlacer();\r
+\r
+ // Methods \r
+ \r
+ std::vector<core::const_frame> operator()(const core::const_frame& frame, core::frame_factory& frame_factory);\r
+ \r
+ // Properties\r
+\r
+private:\r
+ struct impl;\r
+ spl::unique_ptr<impl> impl_;\r
+};\r
+\r
+}}}*/
\ No newline at end of file
}\r
};\r
\r
-struct image_mixer::impl : boost::noncopyable\r
+struct image_mixer::impl : public core::frame_factory\r
{ \r
spl::shared_ptr<device> ogl_;\r
image_renderer renderer_;\r
item.pix_desc = frame.pixel_format_desc();\r
item.field_mode = frame.field_mode();\r
item.transform = transform_stack_.back();\r
-\r
+ \r
// NOTE: Once we have copied the arrays they are no longer valid for reading!!! Check for alternative solution e.g. transfer with AMD_pinned_memory.\r
for(int n = 0; n < static_cast<int>(item.pix_desc.planes.size()); ++n)\r
item.textures.push_back(ogl_->copy_async(frame.image_data(n), item.pix_desc.planes[n].width, item.pix_desc.planes[n].height, item.pix_desc.planes[n].stride));\r
return renderer_(std::move(layers_), format_desc);\r
}\r
\r
- virtual core::mutable_frame create_frame(const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode)\r
+ virtual core::mutable_frame create_frame(const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode) override\r
{\r
std::vector<array<std::uint8_t>> buffers;\r
BOOST_FOREACH(auto& plane, desc.planes) \r
core::field_mode mutable_frame::field_mode() const{return impl_->field_mode_;}\r
std::size_t mutable_frame::width() const{return impl_->desc_.planes.at(0).width;}\r
std::size_t mutable_frame::height() const{return impl_->desc_.planes.at(0).height;} \r
-const void* mutable_frame::tag() const{return impl_->tag_;} \r
-\r
+const void* mutable_frame::stream_tag()const{return impl_->tag_;} \r
+const void* mutable_frame::data_tag()const{return impl_.get();} \r
\r
const const_frame& const_frame::empty()\r
{\r
impl(mutable_frame&& other)\r
: audio_data_(other.audio_data())\r
, desc_(other.pixel_format_desc())\r
- , tag_(other.tag())\r
+ , tag_(other.stream_tag())\r
, id_(reinterpret_cast<int>(this))\r
, frame_rate_(other.frame_rate())\r
, field_mode_(other.field_mode())\r
\r
array<const std::uint8_t> image_data(int index) const\r
{\r
- return tag_ != empty().tag() ? future_buffers_.at(index).get() : array<const std::uint8_t>(nullptr, 0, true, 0);\r
+ return tag_ != empty().stream_tag() ? future_buffers_.at(index).get() : array<const std::uint8_t>(nullptr, 0, true, 0);\r
}\r
\r
std::size_t width() const\r
{\r
- return tag_ != empty().tag() ? desc_.planes.at(0).width : 0;\r
+ return tag_ != empty().stream_tag() ? desc_.planes.at(0).width : 0;\r
}\r
\r
std::size_t height() const\r
{\r
- return tag_ != empty().tag() ? desc_.planes.at(0).height : 0;\r
+ return tag_ != empty().stream_tag() ? desc_.planes.at(0).height : 0;\r
}\r
\r
std::size_t size() const\r
{\r
- return tag_ != empty().tag() ? desc_.planes.at(0).size : 0;\r
- }\r
-\r
- bool operator==(const impl& other)\r
- {\r
- return tag_ == other.tag_ && id_ == other.id_;\r
+ return tag_ != empty().stream_tag() ? desc_.planes.at(0).size : 0;\r
}\r
};\r
\r
const_frame::const_frame(boost::shared_future<array<const std::uint8_t>> image, audio_buffer audio_buffer, const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode) \r
: impl_(new impl(std::move(image), std::move(audio_buffer), tag, desc, frame_rate, field_mode)){}\r
const_frame::const_frame(mutable_frame&& other) : impl_(new impl(std::move(other))){}\r
-const_frame::~const_frame(){}\r
+const_frame::~const_frame()\r
+{\r
+ on_released();\r
+}\r
const_frame::const_frame(const_frame&& other) : impl_(std::move(other.impl_)){}\r
const_frame& const_frame::operator=(const_frame&& other)\r
{\r
impl_ = other.impl_;\r
return *this;\r
}\r
-bool const_frame::operator==(const const_frame& other){return *impl_ == *other.impl_;}\r
+bool const_frame::operator==(const const_frame& other){return impl_ == other.impl_;}\r
bool const_frame::operator!=(const const_frame& other){return !(*this == other);}\r
+bool const_frame::operator<(const const_frame& other){return impl_< other.impl_;}\r
+bool const_frame::operator>(const const_frame& other){return impl_> other.impl_;}\r
const core::pixel_format_desc& const_frame::pixel_format_desc()const{return impl_->desc_;}\r
array<const std::uint8_t> const_frame::image_data(int index)const{return impl_->image_data(index);}\r
const core::audio_buffer& const_frame::audio_data()const{return impl_->audio_data_;}\r
std::size_t const_frame::width()const{return impl_->width();}\r
std::size_t const_frame::height()const{return impl_->height();} \r
std::size_t const_frame::size()const{return impl_->size();} \r
-const void* const_frame::tag()const{return impl_->tag_;} \r
+const void* const_frame::stream_tag()const{return impl_->tag_;} \r
+const void* const_frame::data_tag()const{return impl_.get();} \r
\r
}}
\ No newline at end of file
#pragma once\r
\r
+#undef BOOST_PARAMETER_MAX_ARITY\r
+#define BOOST_PARAMETER_MAX_ARITY 7\r
+\r
#include "../video_format.h"\r
\r
#include <common/memory.h>\r
\r
#include <boost/range.hpp>\r
#include <boost/any.hpp>\r
+#include <boost/signals2.hpp>\r
\r
#include <tbb/cache_aligned_allocator.h>\r
\r
std::size_t width() const;\r
std::size_t height() const;\r
\r
- const void* tag() const;\r
+ const void* stream_tag() const;\r
+ const void* data_tag() const;\r
\r
private:\r
struct impl;\r
const_frame& operator=(const const_frame& other);\r
\r
// Properties\r
+\r
+ boost::signals2::signal<void()> on_released;\r
\r
const struct pixel_format_desc& pixel_format_desc() const;\r
\r
std::size_t height() const;\r
std::size_t size() const;\r
\r
- const void* tag() const;\r
+ const void* stream_tag() const;\r
+ const void* data_tag() const;\r
\r
bool operator==(const const_frame& other);\r
bool operator!=(const const_frame& other);\r
+ bool operator<(const const_frame& other);\r
+ bool operator>(const const_frame& other);\r
\r
private:\r
struct impl;\r
void visit(const const_frame& frame)\r
{\r
audio_item item;\r
- item.tag = frame.tag();\r
+ item.tag = frame.stream_tag();\r
item.transform = transform_stack_.top();\r
item.audio_data = frame.audio_data();\r
\r
if(video_frame->format == PIX_FMT_GRAY8 && format == CASPAR_PIX_FMT_LUMA)\r
av_frame->format = format;\r
\r
- video_streams_.back().push(make_frame(this, av_frame, format_desc_.fps, frame_factory_, flags));\r
+ video_streams_.back().push(make_frame(this, av_frame, format_desc_.fps, *frame_factory_, flags));\r
}\r
}\r
\r
filter_.push(frame);\r
auto av_frame = filter_.poll();\r
if(av_frame) \r
- video_streams_.back().push(make_frame(this, spl::make_shared_ptr(av_frame), format_desc_.fps, frame_factory_, 0));\r
+ video_streams_.back().push(make_frame(this, spl::make_shared_ptr(av_frame), format_desc_.fps, *frame_factory_, 0));\r
}\r
filter_ = filter(filter_str);\r
CASPAR_LOG(info) << L"[frame_muxer] " << display_mode_ << L" " << print_mode(frame->width, frame->height, in_fps_, frame->interlaced_frame > 0);\r
}\r
}\r
\r
-core::mutable_frame make_frame(const void* tag, const spl::shared_ptr<AVFrame>& decoded_frame, double fps, const spl::shared_ptr<core::frame_factory>& frame_factory, int flags)\r
+core::mutable_frame make_frame(const void* tag, const spl::shared_ptr<AVFrame>& decoded_frame, double fps, core::frame_factory& frame_factory, int flags)\r
{ \r
static tbb::concurrent_unordered_map<int, tbb::concurrent_queue<std::shared_ptr<SwsContext>>> sws_contexts_;\r
\r
if(decoded_frame->width < 1 || decoded_frame->height < 1)\r
- return frame_factory->create_frame(tag, core::pixel_format_desc(core::pixel_format::invalid));\r
+ return frame_factory.create_frame(tag, core::pixel_format_desc(core::pixel_format::invalid));\r
\r
const auto width = decoded_frame->width;\r
const auto height = decoded_frame->height;\r
\r
auto target_desc = pixel_format_desc(target_pix_fmt, width, height);\r
\r
- auto write = frame_factory->create_frame(tag, target_desc, fps, get_mode(*decoded_frame));\r
+ auto write = frame_factory.create_frame(tag, target_desc, fps, get_mode(*decoded_frame));\r
\r
std::shared_ptr<SwsContext> sws_context;\r
\r
}\r
else\r
{\r
- auto write = frame_factory->create_frame(tag, desc, fps, get_mode(*decoded_frame));\r
+ auto write = frame_factory.create_frame(tag, desc, fps, get_mode(*decoded_frame));\r
\r
for(int n = 0; n < static_cast<int>(desc.planes.size()); ++n)\r
{\r
\r
core::field_mode get_mode(const AVFrame& frame);\r
int make_alpha_format(int format); // NOTE: Be careful about CASPAR_PIX_FMT_LUMA, change it to PIX_FMT_GRAY8 if you want to use the frame inside some ffmpeg function.\r
-core::mutable_frame make_frame(const void* tag, const spl::shared_ptr<AVFrame>& decoded_frame, double fps, const spl::shared_ptr<core::frame_factory>& frame_factory, int flags);\r
+core::mutable_frame make_frame(const void* tag, const spl::shared_ptr<AVFrame>& decoded_frame, double fps, core::frame_factory& frame_factory, int flags);\r
spl::shared_ptr<AVFrame> make_av_frame(core::mutable_frame& frame);\r
+spl::shared_ptr<AVFrame> make_av_frame(core::const_frame& frame);\r
spl::shared_ptr<AVFrame> make_av_frame(std::array<uint8_t*, 4> data, const core::pixel_format_desc& pix_desc);\r
\r
core::pixel_format_desc pixel_format_desc(PixelFormat pix_fmt, int width, int height);\r