X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fimage%2Fconsumer%2Fimage_consumer.cpp;h=ab466f046ce6e804d9ba718db0f795da577a0a2e;hb=e87a1b1a9301f029fe8dbb8c0b3d523cfb7e0f54;hp=b90def5a6086f0c5f14c682c8c3e16b242f8cf99;hpb=e059c077f56667d7e8d31b1873a0a813ee55ee25;p=casparcg diff --git a/modules/image/consumer/image_consumer.cpp b/modules/image/consumer/image_consumer.cpp index b90def5a6..ab466f046 100644 --- a/modules/image/consumer/image_consumer.cpp +++ b/modules/image/consumer/image_consumer.cpp @@ -1,110 +1,192 @@ -/* -* 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 - -namespace caspar { namespace image { - -struct image_consumer : public core::frame_consumer -{ -public: - - // frame_consumer - - virtual void initialize(const core::video_format_desc&, int) override - { - } - - virtual bool send(const safe_ptr& frame) override - { - boost::thread async([frame] - { - try - { - auto filename = u8(env::data_folder()) + boost::posix_time::to_iso_string(boost::posix_time::second_clock::local_time()) + ".png"; - - auto bitmap = std::shared_ptr(FreeImage_Allocate(frame->width(), frame->height(), 32), FreeImage_Unload); - A_memcpy(FreeImage_GetBits(bitmap.get()), frame->image_data().begin(), frame->image_data().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 boost::property_tree::wptree info() const override - { - boost::property_tree::wptree info; - info.add(L"type", L"image-consumer"); - return info; - } - - virtual int buffer_depth() const override - { - return 0; - } - - virtual int index() const override - { - return 100; - } -}; - -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*) +{ + 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); +} + +}}