X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fimage%2Fproducer%2Fimage_producer.cpp;h=112922ac5f68fe450de2feec264398800f94066f;hb=c30ace6f19e057aff4d84a54f37596857df93750;hp=d55da62f4248c77545e06e8162e9f9213f5a947c;hpb=dfbde5d6d0fcff021c60c0240d94fece52481cf5;p=casparcg diff --git a/modules/image/producer/image_producer.cpp b/modules/image/producer/image_producer.cpp index d55da62f4..112922ac5 100644 --- a/modules/image/producer/image_producer.cpp +++ b/modules/image/producer/image_producer.cpp @@ -1,84 +1,302 @@ -/* -* copyright (c) 2010 Sveriges Television AB -* -* This file is part of CasparCG. -* -* CasparCG is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* CasparCG is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. - -* You should have received a copy of the GNU General Public License -* along with CasparCG. If not, see . -* -*/ -#include "image_producer.h" - -#include "../util/image_loader.h" - -#include - -#include -#include - -#include - -#include -#include - -#include - -using namespace boost::assign; - -namespace caspar { - -struct image_producer : public core::frame_producer -{ - const std::wstring filename_; - safe_ptr frame_; - - explicit image_producer(const safe_ptr& frame_factory, const std::wstring& filename) - : filename_(filename) - , frame_(core::basic_frame::empty()) - { - auto bitmap = load_image(filename_); - FreeImage_FlipVertical(bitmap.get()); - auto frame = frame_factory->create_frame(this, FreeImage_GetWidth(bitmap.get()), FreeImage_GetHeight(bitmap.get())); - std::copy_n(FreeImage_GetBits(bitmap.get()), frame->image_data().size(), frame->image_data().begin()); - frame->commit(); - frame_ = std::move(frame); - } - - // frame_producer - - virtual safe_ptr receive(){return frame_;} - - virtual std::wstring print() const - { - return L"image_producer[" + filename_ + L"]"; - } -}; - -safe_ptr create_image_producer(const safe_ptr& frame_factory, const std::vector& params) -{ - static const std::vector extensions = list_of(L"png")(L"tga")(L"bmp")(L"jpg")(L"jpeg"); - 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::wpath(filename).replace_extension(ex)); - }); - - if(ext == extensions.end()) - return core::frame_producer::empty(); - - return make_safe(frame_factory, filename + L"." + *ext); -} - - -} \ No newline at end of file +/* +* Copyright (c) 2011 Sveriges Television AB +* +* This file is part of CasparCG (www.casparcg.com). +* +* CasparCG is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* CasparCG is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with CasparCG. If not, see . +* +* Author: Robert Nagy, ronag89@gmail.com +*/ + +#include "image_producer.h" + +#include "../util/image_loader.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace caspar { namespace image { + +std::pair load_image( + const spl::shared_ptr& 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, core::audio_channel_layout::invalid()); + + 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 +{ + core::monitor::subject monitor_subject_; + const std::wstring description_; + const spl::shared_ptr frame_factory_; + core::draw_frame frame_ = core::draw_frame::empty(); + core::constraints constraints_; + + image_producer(const spl::shared_ptr& frame_factory, const std::wstring& description, bool thumbnail_mode) + : description_(description) + , frame_factory_(frame_factory) + { + load(load_image(description_)); + + if (thumbnail_mode) + CASPAR_LOG(debug) << print() << L" Initialized"; + else + CASPAR_LOG(info) << print() << L" Initialized"; + } + + image_producer(const spl::shared_ptr& frame_factory, const void* png_data, size_t size) + : description_(L"png from memory") + , frame_factory_(frame_factory) + { + load(load_png_from_memory(png_data, size)); + + CASPAR_LOG(info) << print() << L" Initialized"; + } + + void load(const std::shared_ptr& bitmap) + { + FreeImage_FlipVertical(bitmap.get()); + auto longest_side = static_cast(std::max(FreeImage_GetWidth(bitmap.get()), FreeImage_GetHeight(bitmap.get()))); + + if (longest_side > frame_factory_->get_max_frame_size()) + CASPAR_THROW_EXCEPTION(user_error() << msg_info("Image too large for texture")); + + core::pixel_format_desc desc; + desc.format = core::pixel_format::bgra; + desc.planes.push_back(core::pixel_format_desc::plane(FreeImage_GetWidth(bitmap.get()), FreeImage_GetHeight(bitmap.get()), 4)); + auto frame = frame_factory_->create_frame(this, desc, core::audio_channel_layout::invalid()); + + std::copy_n(FreeImage_GetBits(bitmap.get()), frame.image_data().size(), frame.image_data().begin()); + frame_ = core::draw_frame(std::move(frame)); + constraints_.width.set(FreeImage_GetWidth(bitmap.get())); + constraints_.height.set(FreeImage_GetHeight(bitmap.get())); + } + + // frame_producer + + core::draw_frame receive_impl() override + { + monitor_subject_ << core::monitor::message("/file/path") % description_; + + return frame_; + } + + core::constraints& pixel_constraints() override + { + return constraints_; + } + + std::wstring print() const override + { + return L"image_producer[" + description_ + L"]"; + } + + std::wstring name() const override + { + return L"image"; + } + + boost::property_tree::wptree info() const override + { + boost::property_tree::wptree info; + info.add(L"type", L"image"); + info.add(L"location", description_); + return info; + } + + core::monitor::subject& monitor_output() + { + return monitor_subject_; + } +}; + +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_); + } +}; + +void describe_producer(core::help_sink& sink, const core::help_repository& repo) +{ + sink.short_description(L"Loads a still image."); + sink.syntax(L"{[image_file:string]},{[PNG_BASE64] [encoded:string]}"); + sink.para()->text(L"Loads a still image, either from disk or via a base64 encoded image submitted via AMCP."); + sink.para()->text(L"Examples:"); + sink.example(L">> PLAY 1-10 image_file", L"Plays an image from the media folder."); + sink.example(L">> PLAY 1-10 [PNG_BASE64] data...", L"Plays a PNG image transferred as a base64 encoded string."); +} + +static const auto g_extensions = { + L".png", + L".tga", + L".bmp", + L".jpg", + L".jpeg", + L".gif", + L".tiff", + L".tif", + L".jp2", + L".jpx", + L".j2k", + L".j2c" +}; + +spl::shared_ptr create_producer(const core::frame_producer_dependencies& dependencies, const std::vector& params) +{ + + if (boost::iequals(params.at(0), L"[IMG_SEQUENCE]")) + { + if (params.size() != 2) + return core::frame_producer::empty(); + + auto dir = boost::filesystem::path(env::media_folder() + params.at(1)).parent_path(); + auto basename = boost::filesystem::basename(params.at(1)); + std::set 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(g_extensions.begin(), g_extensions.end(), ieq(extension)) == g_extensions.end()) + continue; + + files.insert(it->path().wstring()); + } + + if (files.empty()) + return core::frame_producer::empty(); + + int width = -1; + int height = -1; + std::vector frames; + frames.reserve(files.size()); + + for (auto& file : files) + { + auto frame = load_image(dependencies.frame_factory, file); + + if (width == -1) + { + width = static_cast(frame.second.width.get()); + height = static_cast(frame.second.height.get()); + } + + frames.push_back(std::move(frame.first)); + } + + return core::create_const_producer(std::move(frames), width, height); + } + else if(boost::iequals(params.at(0), L"[PNG_BASE64]")) + { + if (params.size() < 2) + return core::frame_producer::empty(); + + auto png_data = from_base64(std::string(params.at(1).begin(), params.at(1).end())); + + return spl::make_shared(dependencies.frame_factory, png_data.data(), png_data.size()); + } + + std::wstring filename = env::media_folder() + params.at(0); + + auto ext = std::find_if(g_extensions.begin(), g_extensions.end(), [&](const std::wstring& ex) -> bool + { + auto file = caspar::find_case_insensitive(boost::filesystem::path(filename).wstring() + ex); + + return static_cast(file); + }); + + if(ext == g_extensions.end()) + return core::frame_producer::empty(); + + return spl::make_shared(dependencies.frame_factory, *caspar::find_case_insensitive(filename + *ext), false); +} + + +core::draw_frame create_thumbnail(const core::frame_producer_dependencies& dependencies, const std::wstring& media_file) +{ + std::wstring filename = env::media_folder() + media_file; + + auto ext = std::find_if(g_extensions.begin(), g_extensions.end(), [&](const std::wstring& ex) -> bool + { + auto file = caspar::find_case_insensitive(boost::filesystem::path(filename).wstring() + ex); + + return static_cast(file); + }); + + if (ext == g_extensions.end()) + return core::draw_frame::empty(); + + spl::shared_ptr producer = spl::make_shared( + dependencies.frame_factory, + *caspar::find_case_insensitive(filename + *ext), + true); + + return producer->receive(); +} + +}}