return renderer_(std::move(items_), format_desc);\r
}\r
\r
- virtual spl::shared_ptr<cpu::write_frame> create_frame(const void* tag, const core::pixel_format_desc& desc)\r
+ virtual spl::shared_ptr<cpu::write_frame> create_frame(const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode)\r
{\r
- return spl::make_shared<cpu::write_frame>(tag, desc);\r
+ return spl::make_shared<cpu::write_frame>(tag, desc, frame_rate, field_mode);\r
}\r
};\r
\r
boost::shared_future<boost::iterator_range<const uint8_t*>> image_mixer::operator()(const core::video_format_desc& format_desc){return impl_->render(format_desc);}\r
void image_mixer::begin_layer(core::blend_mode blend_mode){impl_->begin_layer(blend_mode);}\r
void image_mixer::end_layer(){impl_->end_layer();}\r
-spl::shared_ptr<core::write_frame> image_mixer::create_frame(const void* tag, const core::pixel_format_desc& desc) {return impl_->create_frame(tag, desc);}\r
+spl::shared_ptr<core::write_frame> image_mixer::create_frame(const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode) {return impl_->create_frame(tag, desc, frame_rate, field_mode);}\r
\r
}}}
\ No newline at end of file
#include <core/mixer/image/image_mixer.h>\r
\r
#include <core/frame/frame_visitor.h>\r
+#include <core/video_format.h>\r
\r
FORWARD1(boost, template<typename> class shared_future);\r
FORWARD1(boost, template<typename> class iterator_range);\r
// NOTE: Content of return future is only valid while future is valid.\r
virtual ::boost::shared_future<::boost::iterator_range<const uint8_t*>> operator()(const core::video_format_desc& format_desc) override;\r
\r
- virtual spl::shared_ptr<core::write_frame> create_frame(const void* tag, const core::pixel_format_desc& desc) override;\r
+ virtual spl::shared_ptr<core::write_frame> create_frame(const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode) override;\r
private:\r
struct impl;\r
spl::shared_ptr<impl> impl_;\r
core::audio_buffer audio_data_;\r
const core::pixel_format_desc desc_;\r
const void* tag_;\r
+ double frame_rate_;\r
+ core::field_mode field_mode_;\r
\r
impl(const void* tag)\r
: desc_(core::pixel_format::invalid)\r
, tag_(tag) \r
+ , field_mode_(core::field_mode::empty)\r
{\r
}\r
\r
- impl(const void* tag, const core::pixel_format_desc& desc) \r
+ impl(const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode) \r
: desc_(desc)\r
, tag_(tag)\r
+ , frame_rate_(frame_rate)\r
+ , field_mode_(field_mode)\r
{\r
std::transform(desc.planes.begin(), desc.planes.end(), std::back_inserter(buffers_), [&](const core::pixel_format_desc::plane& plane)\r
{\r
};\r
\r
write_frame::write_frame(const void* tag) : impl_(new impl(tag)){}\r
-write_frame::write_frame(const void* tag, const core::pixel_format_desc& desc) \r
- : impl_(new impl(tag, desc)){}\r
+write_frame::write_frame(const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode) \r
+ : impl_(new impl(tag, desc, frame_rate, field_mode)){}\r
write_frame::write_frame(write_frame&& other) : impl_(std::move(other.impl_)){}\r
write_frame& write_frame::operator=(write_frame&& other)\r
{\r
const core::audio_buffer& write_frame::audio_data() const{return impl_->audio_data_;}\r
const boost::iterator_range<uint8_t*> write_frame::image_data(int index){return impl_->image_data(index);}\r
core::audio_buffer& write_frame::audio_data(){return impl_->audio_data_;}\r
-double write_frame::get_frame_rate() const{return 0.0;} // TODO: what's this?\r
+double write_frame::frame_rate() const{return impl_->frame_rate_;}\r
+core::field_mode write_frame::field_mode()const{return impl_->field_mode_;}\r
int write_frame::width() const{return impl_->desc_.planes.at(0).width;}\r
int write_frame::height() const{return impl_->desc_.planes.at(0).height;} \r
const void* write_frame::tag() const{return impl_->tag_;} \r
write_frame& operator=(const write_frame);\r
public: \r
explicit write_frame(const void* tag);\r
- explicit write_frame(const void* tag, const core::pixel_format_desc& desc);\r
+ explicit write_frame(const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode);\r
\r
write_frame(write_frame&& other);\r
write_frame& operator=(write_frame&& other);\r
virtual const boost::iterator_range<uint8_t*> image_data(int index) override;\r
virtual core::audio_buffer& audio_data() override;\r
\r
- virtual double get_frame_rate() const override;\r
+ virtual double frame_rate() const override;\r
+ virtual core::field_mode field_mode() const override;\r
\r
virtual int width() const override;\r
virtual int height() const override;\r
#include <core/frame/pixel_format.h>\r
#include <core/video_format.h>\r
\r
+#include <modules/ffmpeg/producer/filter/filter.h>\r
+\r
#include <asmlib.h>\r
\r
#include <gl/glew.h>\r
{\r
spl::shared_ptr<context> ogl_;\r
image_kernel kernel_;\r
- std::pair<std::vector<layer>, boost::shared_future<boost::iterator_range<const uint8_t*>>> last_image_;\r
+ std::pair<std::vector<layer>, boost::shared_future<boost::iterator_range<const uint8_t*>>> last_image_; \r
+ ffmpeg::filter deinterlacer_;\r
public:\r
image_renderer(const spl::shared_ptr<context>& ogl)\r
: ogl_(ogl)\r
, kernel_(ogl_)\r
+ , deinterlacer_(L"YADIF=0:-1")\r
{\r
}\r
\r
return renderer_(std::move(layers_), format_desc);\r
}\r
\r
- virtual spl::shared_ptr<ogl::write_frame> create_frame(const void* tag, const core::pixel_format_desc& desc)\r
+ virtual spl::shared_ptr<ogl::write_frame> create_frame(const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode)\r
{\r
- return spl::make_shared<ogl::write_frame>(ogl_, tag, desc);\r
+ return spl::make_shared<ogl::write_frame>(ogl_, tag, desc, frame_rate, field_mode);\r
}\r
};\r
\r
boost::shared_future<boost::iterator_range<const uint8_t*>> image_mixer::operator()(const core::video_format_desc& format_desc){return impl_->render(format_desc);}\r
void image_mixer::begin_layer(core::blend_mode blend_mode){impl_->begin_layer(blend_mode);}\r
void image_mixer::end_layer(){impl_->end_layer();}\r
-spl::shared_ptr<core::write_frame> image_mixer::create_frame(const void* tag, const core::pixel_format_desc& desc) {return impl_->create_frame(tag, desc);}\r
+spl::shared_ptr<core::write_frame> image_mixer::create_frame(const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode) {return impl_->create_frame(tag, desc, frame_rate, field_mode);}\r
\r
}}}
\ No newline at end of file
#include <core/mixer/image/image_mixer.h>\r
\r
#include <core/frame/frame_visitor.h>\r
+#include <core/video_format.h>\r
\r
FORWARD1(boost, template<typename> class unique_future);\r
FORWARD2(caspar, core, class write_frame);\r
// NOTE: Content of return future is only valid while future is valid.\r
virtual boost::shared_future<boost::iterator_range<const uint8_t*>> operator()(const core::video_format_desc& format_desc) override;\r
\r
- virtual spl::shared_ptr<core::write_frame> create_frame(const void* tag, const core::pixel_format_desc& desc) override;\r
+ virtual spl::shared_ptr<core::write_frame> create_frame(const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode) override;\r
private:\r
struct impl;\r
spl::shared_ptr<impl> impl_;\r
core::audio_buffer audio_data_;\r
const core::pixel_format_desc desc_;\r
const void* tag_;\r
+ double frame_rate_;\r
+ core::field_mode field_mode_;\r
\r
impl(const void* tag)\r
: desc_(core::pixel_format::invalid)\r
, tag_(tag) \r
+ , field_mode_(core::field_mode::empty)\r
{\r
}\r
\r
- impl(const spl::shared_ptr<ogl::context>& ogl, const void* tag, const core::pixel_format_desc& desc) \r
+ impl(const spl::shared_ptr<ogl::context>& ogl, const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode) \r
: ogl_(ogl)\r
, desc_(desc)\r
, tag_(tag)\r
+ , frame_rate_(frame_rate)\r
+ , field_mode_(field_mode)\r
{\r
std::transform(desc.planes.begin(), desc.planes.end(), std::back_inserter(buffers_), [&](const core::pixel_format_desc::plane& plane)\r
{\r
};\r
\r
write_frame::write_frame(const void* tag) : impl_(new impl(tag)){}\r
-write_frame::write_frame(const spl::shared_ptr<ogl::context>& ogl, const void* tag, const core::pixel_format_desc& desc) \r
- : impl_(new impl(ogl, tag, desc)){}\r
+write_frame::write_frame(const spl::shared_ptr<ogl::context>& ogl, const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode) \r
+ : impl_(new impl(ogl, tag, desc, frame_rate, field_mode)){}\r
write_frame::write_frame(write_frame&& other) : impl_(std::move(other.impl_)){}\r
write_frame& write_frame::operator=(write_frame&& other)\r
{\r
const core::audio_buffer& write_frame::audio_data() const{return impl_->audio_data_;}\r
const boost::iterator_range<uint8_t*> write_frame::image_data(int index){return impl_->image_data(index);}\r
core::audio_buffer& write_frame::audio_data(){return impl_->audio_data_;}\r
-double write_frame::get_frame_rate() const{return 0.0;} // TODO: what's this?\r
+double write_frame::frame_rate() const{return impl_->frame_rate_;}\r
+core::field_mode write_frame::field_mode() const{return impl_->field_mode_;}\r
int write_frame::width() const{return impl_->desc_.planes.at(0).width;}\r
int write_frame::height() const{return impl_->desc_.planes.at(0).height;} \r
const void* write_frame::tag() const{return impl_->tag_;} \r
write_frame& operator=(const write_frame);\r
public: \r
explicit write_frame(const void* tag);\r
- explicit write_frame(const spl::shared_ptr<class context>& ogl, const void* tag, const core::pixel_format_desc& desc);\r
+ explicit write_frame(const spl::shared_ptr<class context>& ogl, const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode);\r
\r
write_frame(write_frame&& other);\r
write_frame& operator=(write_frame&& other);\r
virtual const boost::iterator_range<uint8_t*> image_data(int index) override;\r
virtual core::audio_buffer& audio_data() override;\r
\r
- virtual double get_frame_rate() const override;\r
+ virtual double frame_rate() const override;\r
+ virtual core::field_mode field_mode() const override;\r
\r
virtual int width() const override;\r
virtual int height() const override;\r
static audio_buffer buffer;\r
return buffer;\r
}\r
- virtual double get_frame_rate() const override\r
+ virtual double frame_rate() const override\r
{\r
return 0.0;\r
}\r
+ virtual core::field_mode field_mode() const override\r
+ {\r
+ return core::field_mode::empty;\r
+ }\r
virtual int width() const override\r
{\r
return 0;\r
virtual const boost::iterator_range<uint8_t*> image_data(int index) = 0;\r
virtual audio_buffer& audio_data() = 0;\r
\r
- virtual double get_frame_rate() const = 0;\r
+ virtual double frame_rate() const = 0;\r
+ virtual field_mode field_mode() const = 0;\r
\r
virtual int width() const = 0;\r
virtual int height() const = 0;\r
public:\r
virtual ~frame_factory(){}\r
\r
- virtual spl::shared_ptr<class write_frame> create_frame(const void* video_stream_tag, const struct pixel_format_desc& desc) = 0; \r
+ virtual spl::shared_ptr<class write_frame> create_frame(const void* video_stream_tag, const struct pixel_format_desc& desc, double frame_rate, core::field_mode field_mode) = 0; \r
+ spl::shared_ptr<class write_frame> create_frame(const void* video_stream_tag, const struct pixel_format_desc& desc)\r
+ {\r
+ auto format_desc = video_format_desc();\r
+ return create_frame(video_stream_tag, desc, format_desc.fps, format_desc.field_mode);\r
+ }\r
virtual struct video_format_desc video_format_desc() const = 0; // nothrow\r
};\r
\r
#include <common/forward.h>\r
#include <common/spl/memory.h>\r
\r
+#include <core/video_format.h>\r
#include <core/frame/frame_visitor.h>\r
\r
#include <boost/range.hpp>\r
virtual void end_layer() = 0;\r
\r
virtual boost::shared_future<boost::iterator_range<const uint8_t*>> operator()(const struct video_format_desc& format_desc) = 0;\r
- virtual spl::shared_ptr<core::write_frame> create_frame(const void* tag, const struct pixel_format_desc& desc) = 0;\r
+ virtual spl::shared_ptr<core::write_frame> create_frame(const void* tag, const struct pixel_format_desc& desc, double frame_rate, core::field_mode field_mode) = 0;\r
};\r
\r
}}
\ No newline at end of file
{\r
BOOST_THROW_EXCEPTION(invalid_operation());\r
}\r
-\r
- virtual double get_frame_rate() const override\r
+ \r
+ virtual double frame_rate() const override\r
{\r
return video_desc_.fps;\r
}\r
\r
+ virtual core::field_mode field_mode() const\r
+ {\r
+ return video_desc_.field_mode;\r
+ }\r
+ \r
virtual int width() const override\r
{\r
return video_desc_.width;\r
void mixer::set_blend_mode(int index, blend_mode value){impl_->set_blend_mode(index, value);}\r
boost::unique_future<boost::property_tree::wptree> mixer::info() const{return impl_->info();}\r
spl::shared_ptr<const data_frame> mixer::operator()(std::map<int, spl::shared_ptr<draw_frame>> frames, const struct video_format_desc& format_desc){return (*impl_)(std::move(frames), format_desc);}\r
-spl::shared_ptr<write_frame> mixer::create_frame(const void* tag, const core::pixel_format_desc& desc) {return impl_->image_mixer_->create_frame(tag, desc);}\r
+spl::shared_ptr<write_frame> mixer::create_frame(const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode) {return impl_->image_mixer_->create_frame(tag, desc, frame_rate, field_mode);}\r
}}
\ No newline at end of file
#include <common/spl/memory.h>\r
#include <common/reactive.h>\r
\r
+#include <core/video_format.h>\r
+\r
#include <boost/noncopyable.hpp>\r
#include <boost/property_tree/ptree_fwd.hpp>\r
\r
\r
boost::unique_future<boost::property_tree::wptree> info() const;\r
\r
- spl::shared_ptr<class write_frame> create_frame(const void* tag, const struct pixel_format_desc& desc);\r
+ spl::shared_ptr<class write_frame> create_frame(const void* tag, const struct pixel_format_desc& desc, double frame_rate, core::field_mode field_mode);\r
private:\r
struct impl;\r
spl::shared_ptr<impl> impl_;\r
\r
// frame_factory\r
\r
- virtual spl::shared_ptr<write_frame> create_frame(const void* tag, const core::pixel_format_desc& desc) override\r
+ virtual spl::shared_ptr<write_frame> create_frame(const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode) override\r
{ \r
- return mixer_.create_frame(tag, desc);\r
+ return mixer_.create_frame(tag, desc, frame_rate, field_mode);\r
}\r
\r
virtual core::video_format_desc video_format_desc() const\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_write_frame(this, av_frame, frame_factory_, flags));\r
+ video_streams_.back().push(make_write_frame(this, av_frame, frame_factory_->video_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_write_frame(this, spl::make_shared_ptr(av_frame), frame_factory_, 0));\r
+ video_streams_.back().push(make_write_frame(this, spl::make_shared_ptr(av_frame), frame_factory_->video_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
-spl::shared_ptr<core::write_frame> make_write_frame(const void* tag, const spl::shared_ptr<AVFrame>& decoded_frame, const spl::shared_ptr<core::frame_factory>& frame_factory, int flags)\r
+spl::shared_ptr<core::write_frame> make_write_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
{ \r
static tbb::concurrent_unordered_map<int, tbb::concurrent_queue<std::shared_ptr<SwsContext>>> sws_contexts_;\r
\r
\r
auto target_desc = get_pixel_format_desc(target_pix_fmt, width, height);\r
\r
- write = frame_factory->create_frame(tag, target_desc);\r
+ 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
- write = frame_factory->create_frame(tag, desc);\r
-\r
+ 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
auto plane = desc.planes[n];\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
-spl::shared_ptr<core::write_frame> make_write_frame(const void* tag, const spl::shared_ptr<AVFrame>& decoded_frame, const spl::shared_ptr<core::frame_factory>& frame_factory, int flags);\r
+spl::shared_ptr<core::write_frame> make_write_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
spl::shared_ptr<AVFrame> make_av_frame(caspar::core::data_frame& frame);\r
spl::shared_ptr<AVFrame> make_av_frame(std::array<void*, 4> data, const core::pixel_format_desc& pix_desc);\r
\r
\r
spl::shared_ptr<core::draw_frame> render()\r
{ \r
- const float frame_time = 1.0f/ax_->GetFPS();\r
+ const float frame_time = 1.0f/fps();\r
\r
frame_timer_.restart();\r
\r
\r
core::pixel_format_desc desc = core::pixel_format::bgra;\r
desc.planes.push_back(core::pixel_format_desc::plane(width_, height_, 4));\r
- auto frame = frame_factory_->create_frame(this, desc);\r
+ auto frame = frame_factory_->create_frame(this, desc, fps(), core::field_mode::progressive);\r
\r
A_memcpy(frame->image_data(0).begin(), bmp_.data(), width_*height_*4);\r
head_ = frame; \r
\r
frame_number_++;\r
\r
- bool double_speed = std::abs(frame_factory_->video_format_desc().fps / 2.0 - read_frame->get_frame_rate()) < 0.01; \r
- bool half_speed = std::abs(read_frame->get_frame_rate() / 2.0 - frame_factory_->video_format_desc().fps) < 0.01;\r
+ bool double_speed = std::abs(frame_factory_->video_format_desc().fps / 2.0 - read_frame->frame_rate()) < 0.01; \r
+ bool half_speed = std::abs(read_frame->frame_rate() / 2.0 - frame_factory_->video_format_desc().fps) < 0.01;\r
\r
if(half_speed && frame_number_ % 2 == 0) // Skip frame\r
return receive(0);\r