class const_producer : public frame_producer_base
{
- draw_frame frame_;
+ std::vector<draw_frame> frames_;
+ std::vector<draw_frame>::const_iterator seek_position_;
constraints constraints_;
public:
const_producer(const draw_frame& frame, int width, int height)
- : frame_(frame)
+ : constraints_(width, height)
+ {
+ frames_.push_back(frame);
+ seek_position_ = frames_.begin();
+ CASPAR_LOG(info) << print() << L" Initialized";
+ }
+
+ const_producer(std::vector<draw_frame>&& frames, int width, int height)
+ : frames_(std::move(frames))
+ , seek_position_(frames_.begin())
, constraints_(width, height)
{
CASPAR_LOG(info) << print() << L" Initialized";
draw_frame receive_impl() override
{
- return frame_;
+ auto result = *seek_position_;
+
+ if (seek_position_ + 1 != frames_.end())
+ ++seek_position_;
+
+ return result;
}
constraints& pixel_constraints() override
return spl::make_shared<const_producer>(frame, width, height);
}
+spl::shared_ptr<class frame_producer> create_const_producer(
+ std::vector<class draw_frame>&& frames, int width, int height)
+{
+ return spl::make_shared<const_producer>(std::move(frames), width, height);
+}
+
}}
spl::shared_ptr<class frame_producer> create_const_producer(
const class draw_frame& frame, int width, int height);
+spl::shared_ptr<class frame_producer> create_const_producer(
+ std::vector<class draw_frame>&& frames, int width, int height);
}}
scene->create_variable<std::wstring>(variable_prefix + L"parameter." + var_name, false, expr) = var.as<std::wstring>();
else if (var.is<bool>())
scene->create_variable<bool>(variable_prefix + L"parameter." + var_name, false, expr) = var.as<bool>();
- else if (var.is<int>())
- scene->create_variable<double>(variable_prefix + L"parameter." + var_name, false, expr) = var.as<int>().as<double>();
}
}
struct text_producer::impl
{
- spl::shared_ptr<core::frame_factory> frame_factory_;
+ spl::shared_ptr<core::frame_factory> frame_factory_;
constraints constraints_;
int x_, y_, parent_width_, parent_height_;
bool standalone_;
variable_impl<std::wstring> text_;
std::shared_ptr<void> text_subscription_;
- variable_impl<int> current_bearing_y_;
- variable_impl<int> current_protrude_under_y_;
+ variable_impl<double> tracking_;
+ std::shared_ptr<void> tracking_subscription_;
+ variable_impl<double> current_bearing_y_;
+ variable_impl<double> current_protrude_under_y_;
draw_frame frame_;
text::texture_atlas atlas_;
text::texture_font font_;
+ bool dirty_;
public:
explicit impl(const spl::shared_ptr<frame_factory>& frame_factory, int x, int y, const std::wstring& str, text::text_info& text_info, long parent_width, long parent_height, bool standalone)
, standalone_(standalone)
, atlas_(512,512,4)
, font_(atlas_, text::find_font_file(text_info), !standalone)
+ , dirty_(false)
{
//TODO: examine str to determine which unicode_blocks to load
font_.load_glyphs(text::Basic_Latin, text_info.color);
font_.load_glyphs(text::Latin_1_Supplement, text_info.color);
font_.load_glyphs(text::Latin_Extended_A, text_info.color);
+ tracking_.value().set(text_info.tracking);
text_subscription_ = text_.value().on_change([this]()
{
- generate_frame(text_.value().get());
+ dirty_ = true;
+ });
+ tracking_subscription_ = tracking_.value().on_change([this]()
+ {
+ dirty_ = true;
});
constraints_.height.depend_on(text());
constraints_.width.depend_on(text());
- current_bearing_y_.as<int>().depend_on(text());
- current_protrude_under_y_.as<int>().depend_on(text());
+ current_bearing_y_.as<double>().depend_on(text());
+ current_protrude_under_y_.as<double>().depend_on(text());
//generate frame
text_.value().set(str);
CASPAR_LOG(info) << print() << L" Initialized";
}
- void generate_frame(const std::wstring& str)
+ void generate_frame()
{
core::pixel_format_desc pfd(core::pixel_format::bgra);
pfd.planes.push_back(core::pixel_format_desc::plane(static_cast<int>(atlas_.width()), static_cast<int>(atlas_.height()), static_cast<int>(atlas_.depth())));
text::string_metrics metrics;
- std::vector<float> vertex_stream(std::move(font_.create_vertex_stream(str, x_, y_, parent_width_, parent_height_, &metrics)));
+ font_.set_tracking(static_cast<int>(tracking_.value().get()));
+ std::vector<float> vertex_stream(std::move(font_.create_vertex_stream(text_.value().get(), x_, y_, parent_width_, parent_height_, &metrics)));
auto frame = frame_factory_->create_frame(vertex_stream.data(), pfd);
memcpy(frame.image_data().data(), atlas_.data(), frame.image_data().size());
frame.set_geometry(frame_geometry(frame_geometry::quad_list, std::move(vertex_stream)));
draw_frame receive_impl()
{
+ if (dirty_)
+ generate_frame();
+
return frame_;
}
return current_bearing_y_;
else if (name == L"current_protrude_under_y")
return current_protrude_under_y_;
+ else if (name == L"tracking")
+ return tracking_;
CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(L"text_producer does not have a variable called " + name));
}
static std::vector<std::wstring> vars =
boost::assign::list_of<std::wstring>
(L"text")
+ (L"tracking")
(L"current_bearing_y")
(L"current_protrude_under_y");
return text_.value();
}
- const binding<int>& current_bearing_y() const
+ binding<double>& tracking()
+ {
+ return tracking_.value();
+ }
+
+ const binding<double>& current_bearing_y() const
{
return current_bearing_y_.value();
}
- const binding<int>& current_protrude_under_y() const
+ const binding<double>& current_protrude_under_y() const
{
return current_protrude_under_y_.value();
}
void text_producer::subscribe(const monitor::observable::observer_ptr& o) {}
void text_producer::unsubscribe(const monitor::observable::observer_ptr& o) {}
binding<std::wstring>& text_producer::text() { return impl_->text(); }
-const binding<int>& text_producer::current_bearing_y() const { return impl_->current_bearing_y(); }
-const binding<int>& text_producer::current_protrude_under_y() const { return impl_->current_protrude_under_y(); }
+binding<double>& text_producer::tracking() { return impl_->tracking(); }
+const binding<double>& text_producer::current_bearing_y() const { return impl_->current_bearing_y(); }
+const binding<double>& text_producer::current_protrude_under_y() const { return impl_->current_protrude_under_y(); }
spl::shared_ptr<text_producer> text_producer::create(const spl::shared_ptr<frame_factory>& frame_factory, int x, int y, const std::wstring& str, text::text_info& text_info, long parent_width, long parent_height, bool standalone)
{
void unsubscribe(const monitor::observable::observer_ptr& o) override;
binding<std::wstring>& text();
- const binding<int>& current_bearing_y() const;
- const binding<int>& current_protrude_under_y() const;
+ binding<double>& tracking();
+ const binding<double>& current_bearing_y() const;
+ const binding<double>& current_protrude_under_y() const;
private:
struct impl;
spl::unique_ptr<impl> impl_;
color<float> color;
int baseline_shift;
int tracking;
+
+ text_info()
+ : size(0.0f)
+ , baseline_shift(0)
+ , tracking(0)
+ {
+ }
};
}}}
\ No newline at end of file
FT_Done_FreeType(lib_);
}
+ void set_tracking(int tracking)
+ {
+ tracking_ = size_ * tracking / 1000.0f;
+ }
+
int count_glyphs_in_range(unicode_block block)
{
unicode_range range = get_range(block);
texture_font::texture_font(texture_atlas& atlas, const text_info& info, bool normalize_coordinates) : impl_(new impl(atlas, info, normalize_coordinates)) {}
void texture_font::load_glyphs(unicode_block range, const color<float>& col) { impl_->load_glyphs(range, col); }
+void texture_font::set_tracking(int tracking) { impl_->set_tracking(tracking); }
std::vector<float> texture_font::create_vertex_stream(const std::wstring& str, int x, int y, int parent_width, int parent_height, string_metrics* metrics) { return impl_->create_vertex_stream(str, x, y, parent_width, parent_height, metrics); }
string_metrics texture_font::measure_string(const std::wstring& str) { return impl_->measure_string(str); }
public:
texture_font(texture_atlas&, const text_info&, bool normalize_coordinates);
void load_glyphs(unicode_block block, const color<float>& col);
+ void set_tracking(int tracking);
std::vector<float> create_vertex_stream(const std::wstring& str, int x, int y, int parent_width, int parent_height, string_metrics* metrics);
string_metrics measure_string(const std::wstring& str);
{
executor_.invoke([=]
{
+ consumer_.reset();
::CoUninitialize();
});
}
#include <core/video_format.h>
#include <core/producer/frame_producer.h>
+#include <core/producer/scene/const_producer.h>
#include <core/frame/frame.h>
#include <core/frame/draw_frame.h>
#include <core/frame/frame_factory.h>
#include <boost/assign.hpp>
#include <boost/filesystem.hpp>
#include <boost/property_tree/ptree.hpp>
+#include <boost/algorithm/string.hpp>
#include <algorithm>
namespace caspar { namespace image {
+std::pair<core::draw_frame, core::constraints> load_image(
+ const spl::shared_ptr<core::frame_factory>& frame_factory,
+ const std::wstring& filename)
+{
+ auto bitmap = load_image(filename);
+ FreeImage_FlipVertical(bitmap.get());
+
+ core::pixel_format_desc desc = core::pixel_format::bgra;
+ auto width = FreeImage_GetWidth(bitmap.get());
+ auto height = FreeImage_GetHeight(bitmap.get());
+ desc.planes.push_back(core::pixel_format_desc::plane(width, height, 4));
+ auto frame = frame_factory->create_frame(bitmap.get(), desc);
+
+ std::copy_n(
+ FreeImage_GetBits(bitmap.get()),
+ frame.image_data(0).size(),
+ frame.image_data(0).begin());
+
+ return std::make_pair(
+ core::draw_frame(std::move(frame)),
+ core::constraints(width, height));
+}
+
struct image_producer : public core::frame_producer_base
{
monitor::basic_subject event_subject_;
: filename_(filename)
, frame_(core::draw_frame::empty())
{
- auto bitmap = load_image(filename_);
- FreeImage_FlipVertical(bitmap.get());
-
- core::pixel_format_desc desc = core::pixel_format::bgra;
- auto width = FreeImage_GetWidth(bitmap.get());
- auto height = FreeImage_GetHeight(bitmap.get());
- desc.planes.push_back(core::pixel_format_desc::plane(width, height, 4));
- auto frame = frame_factory->create_frame(this, desc);
+ auto frame = load_image(frame_factory, filename);
- std::copy_n(FreeImage_GetBits(bitmap.get()), frame.image_data(0).size(), frame.image_data(0).begin());
- frame_ = core::draw_frame(std::move(frame));
- constraints_.width.set(width);
- constraints_.height.set(height);
+ frame_ = frame.first;
+ constraints_ = frame.second;
CASPAR_LOG(info) << print() << L" Initialized";
}
}
};
+class ieq
+{
+ std::wstring test_;
+public:
+ ieq(const std::wstring& test)
+ : test_(test)
+ {
+ }
+
+ bool operator()(const std::wstring& elem) const
+ {
+ return boost::iequals(elem, test_);
+ }
+};
+
spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params)
{
static const std::vector<std::wstring> extensions = list_of(L".png")(L".tga")(L".bmp")(L".jpg")(L".jpeg")(L".gif")(L".tiff")(L".tif")(L".jp2")(L".jpx")(L".j2k")(L".j2c");
+
+ if (boost::iequals(params[0], L"[IMG_SEQUENCE]"))
+ {
+ if (params.size() != 2)
+ return core::frame_producer::empty();
+
+ auto dir = boost::filesystem::path(env::media_folder() + L"\\" + params[1]).parent_path();
+ auto basename = boost::filesystem3::basename(params[1]);
+ std::set<std::wstring> files;
+ boost::filesystem::directory_iterator end;
+
+ for (boost::filesystem::directory_iterator it(dir); it != end; ++it)
+ {
+ auto name = it->path().filename().wstring();
+
+ if (!boost::algorithm::istarts_with(name, basename))
+ continue;
+
+ auto extension = it->path().extension().wstring();
+
+ if (std::find_if(extensions.begin(), extensions.end(), ieq(extension)) == extensions.end())
+ continue;
+
+ files.insert(it->path().wstring());
+ }
+
+ if (files.empty())
+ return core::frame_producer::empty();
+
+ int width = -1;
+ int height = -1;
+ std::vector<core::draw_frame> frames;
+ frames.reserve(files.size());
+
+ BOOST_FOREACH(auto& file, files)
+ {
+ auto frame = load_image(frame_factory, file);
+
+ if (width == -1)
+ {
+ width = static_cast<int>(frame.second.width.get());
+ height = static_cast<int>(frame.second.height.get());
+ }
+
+ frames.push_back(std::move(frame.first));
+ }
+
+ return core::create_const_producer(std::move(frames), width, height);
+ }
+
std::wstring filename = env::media_folder() + L"\\" + params[0];
-
+
auto ext = std::find_if(extensions.begin(), extensions.end(), [&](const std::wstring& ex) -> bool
{
return boost::filesystem::is_regular_file(boost::filesystem::path(filename).replace_extension(ex));