X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fimage%2Fconsumer%2Fimage_consumer.cpp;h=4730402d7566fae1dba51a455bcf176811e4ff5a;hb=9e4b08cde6c6de9e83a3fff42d90affc3cd8e5bc;hp=417e1f1c15734ad9be44fe315f29b7e0af07bc58;hpb=f6a130bfe0eb0dd0c7c2d26908d358db3e2e8927;p=casparcg diff --git a/modules/image/consumer/image_consumer.cpp b/modules/image/consumer/image_consumer.cpp index 417e1f1c1..4730402d7 100644 --- a/modules/image/consumer/image_consumer.cpp +++ b/modules/image/consumer/image_consumer.cpp @@ -1,98 +1,193 @@ -/* -* 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_consumer.h" - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include - -#include - -#include - -namespace caspar { namespace image { - -struct image_consumer : public core::frame_consumer -{ - core::video_format_desc format_desc_; -public: - - // frame_consumer - - virtual void initialize(const core::video_format_desc& format_desc, int, int) override - { - format_desc_ = format_desc; - } - - virtual bool send(const safe_ptr& frame) override - { - auto format_desc = format_desc_; - boost::thread async([format_desc, frame] - { - try - { - auto filename = narrow(env::data_folder()) + boost::posix_time::to_iso_string(boost::posix_time::second_clock::local_time()) + ".png"; - - auto bitmap = std::shared_ptr(FreeImage_Allocate(format_desc.width, format_desc.height, 32), FreeImage_Unload); - memcpy(FreeImage_GetBits(bitmap.get()), frame->image_data().begin(), frame->image_size()); - FreeImage_FlipVertical(bitmap.get()); - FreeImage_Save(FIF_PNG, bitmap.get(), filename.c_str(), 0); - } - catch(...) - { - CASPAR_LOG_CURRENT_EXCEPTION(); - } - }); - async.detach(); - - return false; - } - - virtual std::wstring print() const override - { - return L"image[]"; - } - - virtual size_t buffer_depth() const override - { - return 0; - } -}; - -safe_ptr create_consumer(const std::vector& params) -{ - if(params.size() < 1 || params[0] != L"IMAGE") - return core::frame_consumer::empty(); - - return make_safe(); -} - -}} +/* +* 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_consumer.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include + +#include +#include + +#include "../util/image_view.h" + +namespace caspar { namespace image { + +void write_cropped_png( + const core::const_frame& frame, + const core::video_format_desc& format_desc, + const boost::filesystem::path& output_file, + int width, + int height) +{ + auto bitmap = std::shared_ptr(FreeImage_Allocate(width, height, 32), FreeImage_Unload); + image_view destination_view(FreeImage_GetBits(bitmap.get()), width, height); + image_view complete_frame(const_cast(frame.image_data().begin()), format_desc.width, format_desc.height); + auto thumbnail_view = complete_frame.subview(0, 0, width, height); + + std::copy(thumbnail_view.begin(), thumbnail_view.end(), destination_view.begin()); + FreeImage_FlipVertical(bitmap.get()); +#ifdef WIN32 + FreeImage_SaveU(FIF_PNG, bitmap.get(), output_file.wstring().c_str(), 0); +#else + FreeImage_Save(FIF_PNG, bitmap.get(), u8(output_file.wstring()).c_str(), 0); +#endif +} + +struct image_consumer : public core::frame_consumer +{ + core::monitor::subject monitor_subject_; + std::wstring filename_; +public: + + // frame_consumer + + image_consumer(const std::wstring& filename) + : filename_(filename) + { + } + + void initialize(const core::video_format_desc&, const core::audio_channel_layout&, int) override + { + } + + int64_t presentation_frame_age_millis() const override + { + return 0; + } + + std::future send(core::const_frame frame) override + { + auto filename = filename_; + + boost::thread async([frame, filename] + { + ensure_gpf_handler_installed_for_thread("image-consumer"); + + try + { + auto filename2 = filename; + + if (filename2.empty()) + filename2 = env::media_folder() + boost::posix_time::to_iso_wstring(boost::posix_time::second_clock::local_time()) + L".png"; + else + filename2 = env::media_folder() + filename2 + L".png"; + + auto bitmap = std::shared_ptr(FreeImage_Allocate(static_cast(frame.width()), static_cast(frame.height()), 32), FreeImage_Unload); + A_memcpy(FreeImage_GetBits(bitmap.get()), frame.image_data().begin(), frame.image_data().size()); + FreeImage_FlipVertical(bitmap.get()); +#ifdef WIN32 + FreeImage_SaveU(FIF_PNG, bitmap.get(), filename2.c_str(), 0); +#else + FreeImage_Save(FIF_PNG, bitmap.get(), u8(filename2).c_str(), 0); +#endif + } + catch(...) + { + CASPAR_LOG_CURRENT_EXCEPTION(); + } + }); + async.detach(); + + return make_ready_future(false); + } + + std::wstring print() const override + { + return L"image[]"; + } + + 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"); + return info; + } + + int buffer_depth() const override + { + return -1; + } + + int index() const override + { + return 100; + } + + core::monitor::subject& monitor_output() + { + return monitor_subject_; + } +}; + +void describe_consumer(core::help_sink& sink, const core::help_repository& repo) +{ + sink.short_description(L"Writes a single PNG snapshot of a video channel."); + sink.syntax(L"IMAGE {[filename:string]|yyyyMMddTHHmmss}"); + sink.para() + ->text(L"Writes a single PNG snapshot of a video channel. ")->code(L".png")->text(L" will be appended to ") + ->code(L"filename")->text(L". The PNG image will be stored under the ")->code(L"media")->text(L" folder."); + sink.para()->text(L"Examples:"); + sink.example(L">> ADD 1 IMAGE screenshot", L"creating media/screenshot.png"); + sink.example(L">> ADD 1 IMAGE", L"creating media/20130228T210946.png if the current time is 2013-02-28 21:09:46."); +} + +spl::shared_ptr create_consumer( + const std::vector& params, core::interaction_sink*, std::vector> channels) +{ + if (params.size() < 1 || !boost::iequals(params.at(0), L"IMAGE")) + return core::frame_consumer::empty(); + + std::wstring filename; + + if (params.size() > 1) + filename = params.at(1); + + return spl::make_shared(filename); +} + +}}