]> git.sesse.net Git - casparcg/blobdiff - modules/image/producer/image_scroll_producer.cpp
2.0. Updated namespaces.
[casparcg] / modules / image / producer / image_scroll_producer.cpp
index 43fccb9a033f5c0a519abe289c73b6174540e7cf..4a7b8d195a0b38ebf3c729d1bfdc89820e7eb58b 100644 (file)
 *    along with CasparCG.  If not, see <http://www.gnu.org/licenses/>.\r
 *\r
 */\r
-//#include "image_scroll_producer.h"\r
-//\r
-//#include "image_loader.h"\r
-//\r
-//#include "../../mixer/basic_frame.h"\r
-//#include "../../mixer/basic_frame.h"\r
-//#include "../../video_format.h"\r
-//#include "../../mixer/frame_mixer_device.h"\r
-//#include "../../configuration.h"\r
-//\r
-//#include <tbb/parallel_for.h>\r
-//#include <tbb/parallel_invoke.h>\r
-//#include <tbb/scalable_allocator.h>\r
-//\r
-//#include <boost/assign.hpp>\r
-//#include <boost/algorithm/string/case_conv.hpp>\r
-//\r
-//using namespace boost::assign;\r
-//\r
-//namespace caspar { namespace core { namespace image{\r
-//\r
-//enum direction\r
-//{\r
-//     Up, Down, Left, Right\r
-//};\r
-//\r
-//struct image_scroll_producer : public frame_producer\r
-//{\r
-//     static const int DEFAULT_SCROLL_SPEED = 50;\r
-//\r
-//     image_scroll_producer(const std::wstring& filename, const std::vector<std::wstring>& params) \r
-//             : speed_(image_scroll_producer::DEFAULT_SCROLL_SPEED), direction_(direction::Up), offset_(0), filename_(filename)\r
-//     {\r
-//             auto pos = filename.find_last_of(L'_');\r
-//             if(pos != std::wstring::npos && pos + 1 < filename.size())\r
-//             {\r
-//                     std::wstring speedStr = filename.substr(pos + 1);\r
-//                     pos = speedStr.find_first_of(L'.');\r
-//                     if(pos != std::wstring::npos)\r
-//                     {\r
-//                             speedStr = speedStr.substr(0, pos);             \r
-//                             speed_ = lexical_cast_or_default<int>(speedStr, image_scroll_producer::DEFAULT_SCROLL_SPEED);\r
-//                     }\r
-//             }\r
-//\r
-//             loop_ = std::find(params.begin(), params.end(), L"LOOP") != params.end();\r
-//     }\r
-//\r
-//     void load_and_pad_image(const std::wstring& filename)\r
-//     {\r
-//             auto pBitmap = load_image(filename);\r
-//\r
-//             size_t width = FreeImage_GetWidth(pBitmap.get());\r
-//             size_t height = FreeImage_GetHeight(pBitmap.get());\r
-//\r
-//             image_width_ = std::max(width, format_desc_.width);\r
-//             image_height_ = std::max(height, format_desc_.height);\r
-//\r
-//             image_ = std::shared_ptr<unsigned char>(static_cast<unsigned char*>(scalable_aligned_malloc(image_width_*image_height_*4, 16)));\r
-//             std::fill_n(image_.get(), image_width_*image_height_*4, 0);\r
-//\r
-//             unsigned char* pBits = FreeImage_GetBits(pBitmap.get());\r
-//             \r
-//             for (size_t i = 0; i < height; ++i)\r
-//                     std::copy_n(&pBits[i* width * 4], width * 4, &image_.get()[i * image_width_ * 4]);\r
-//     }\r
-//\r
-//     basic_frame do_receive()\r
-//     {\r
-//             auto frame = frame_factory_->create_frame(format_desc_.width, format_desc_.height);\r
-//             std::fill(frame.image_data().begin(), frame.image_data().end(), 0);\r
-//\r
-//             const int delta_x = direction_ == direction::Left ? speed_ : -speed_;\r
-//             const int delta_y = direction_ == direction::Up ? speed_ : -speed_;\r
-//\r
-//             unsigned char* frame_data = frame.image_data().begin();\r
-//             unsigned char* image_data = image_.get();\r
-//     \r
-//             if (direction_ == direction::Up || direction_ == direction::Down)\r
-//             {\r
-//                     tbb::parallel_for(static_cast<size_t>(0), format_desc_.height, static_cast<size_t>(1), [&](size_t i)\r
-//                     {\r
-//                             int srcRow = i + offset_;\r
-//                             int dstInxex = i * format_desc_.width * 4;\r
-//                             int srcIndex = srcRow * format_desc_.width * 4;\r
-//                             int size = format_desc_.width * 4;\r
-//\r
-//                             std::copy_n(&image_data[srcIndex], size, &frame_data[dstInxex]);\r
-//                     });                             \r
-//                     \r
-//                     offset_ += delta_y;\r
-//             }\r
-//             else\r
-//             {\r
-//                     tbb::parallel_for(static_cast<size_t>(0), format_desc_.height, static_cast<size_t>(1), [&](size_t i)\r
-//                     {\r
-//                             int correctOffset = offset_;\r
-//                             int dstIndex = i * format_desc_.width * 4;\r
-//                             int srcIndex = (i * image_width_ + correctOffset) * 4;\r
-//                     \r
-//                             int stopOffset = std::min<int>(correctOffset + format_desc_ .width, image_width_);\r
-//                             int size = (stopOffset - correctOffset) * 4;\r
-//\r
-//                             std::copy_n(&image_data[srcIndex], size, &frame_data[dstIndex]);\r
-//                     });\r
-//\r
-//                     offset_ += delta_x;\r
-//             }\r
-//\r
-//             return std::move(frame);\r
-//     }\r
-//             \r
-//     safe_ptr<basic_frame> receive()\r
-//     {               \r
-//             if(format_desc_.mode != video_mode::progressive)                                \r
-//             {\r
-//                     basic_frame frame1;\r
-//                     basic_frame frame2;\r
-//                     tbb::parallel_invoke([&]{ frame1 = std::move(do_receive()); }, [&]{ frame2 = std::move(do_receive()); });\r
-//                     return basic_frame::interlace(std::move(frame1), std::move(frame2), format_desc_.mode);\r
-//             }                       \r
-//\r
-//             return receive();       \r
-//     }\r
-//     \r
-//     void initialize(const safe_ptr<frame_factory>& frame_factory)\r
-//     {\r
-//             frame_factory_ = frame_factory;\r
-//             format_desc_ = frame_factory_->get_video_format_desc();\r
-//                             \r
-//             if(image_width_ - format_desc_.width > image_height_ - format_desc_.height)\r
-//                     direction_ = speed_ < 0 ? direction::Right : direction::Left;\r
-//             else\r
-//                     direction_ = speed_ < 0 ? direction::Down : direction::Up;\r
-//\r
-//             if (direction_ == direction::Down)\r
-//                     offset_ = image_height_ - format_desc_.height;\r
-//             else if (direction_ == direction::Right)\r
-//                     offset_ = image_width_ - format_desc_.width;\r
-//\r
-//             speed_ = static_cast<int>(abs(static_cast<double>(speed_) / format_desc_.fps));\r
-//             \r
-//             load_and_pad_image(filename_);\r
-//     }\r
-//     \r
-//\r
-//     std::wstring print() const\r
-//     {\r
-//             return L"image_scroll_producer. filename: " + filename_;\r
-//     }\r
-//\r
-//     const video_format_desc& get_video_format_desc() const { return format_desc_; } \r
-//     \r
-//     int image_width_;\r
-//     int image_height_;\r
-//     int speed_;\r
-//     int offset_;\r
-//     direction direction_;\r
-//\r
-//     tbb::atomic<bool> loop_;\r
-//     std::shared_ptr<unsigned char> image_;\r
-//     video_format_desc format_desc_;\r
-//\r
-//     std::wstring filename_;\r
-//\r
-//     safe_ptr<frame_mixer_device> frame_factory_;\r
-//};\r
-//\r
-//safe_ptr<frame_producer> create_image_scroll_producer(const std::vector<std::wstring>& params)\r
-//{\r
-//     static const std::vector<std::wstring> extensions = list_of(L"spng")(L"stga")(L"sbmp")(L"sjpg")(L"sjpeg");\r
-//     std::wstring filename = configuration::media_folder() + L"\\" + params[0];\r
-//     \r
-//     auto ext = std::find_if(extensions.begin(), extensions.end(), [&](const std::wstring& ex) -> bool\r
-//             {                                       \r
-//                     return boost::filesystem::is_regular_file(boost::filesystem::wpath(filename).replace_extension(ex));\r
-//             });\r
-//\r
-//     if(ext == extensions.end())\r
-//             return nullptr;\r
-//\r
-//     return std::make_shared<image_scroll_producer>(filename + L"." + *ext, params);\r
-//}\r
-//\r
-//}}}
\ No newline at end of file
+// TODO: Refactor.\r
+// TODO: Looping.\r
+\r
+#include "image_scroll_producer.h"\r
+\r
+#include "../util/image_loader.h"\r
+\r
+#include <core/video_format.h>\r
+\r
+#include <core/producer/frame/basic_frame.h>\r
+#include <core/producer/frame/frame_factory.h>\r
+#include <core/producer/frame/frame_transform.h>\r
+#include <core/mixer/write_frame.h>\r
+\r
+#include <common/env.h>\r
+#include <common/memory/memclr.h>\r
+#include <common/exception/exceptions.h>\r
+\r
+#include <boost/assign.hpp>\r
+#include <boost/filesystem.hpp>\r
+#include <boost/foreach.hpp>\r
+#include <boost/lexical_cast.hpp>\r
+\r
+#include <algorithm>\r
+#include <array>\r
+\r
+using namespace boost::assign;\r
+\r
+namespace caspar { namespace image {\r
+               \r
+struct image_scroll_producer : public core::frame_producer\r
+{      \r
+       const std::wstring                                                      filename_;\r
+       std::vector<safe_ptr<core::basic_frame>>        frames_;\r
+       core::video_format_desc                                         format_desc_;\r
+       size_t                                                                          width_;\r
+       size_t                                                                          height_;\r
+\r
+       int                                                                                     delta_;\r
+       int                                                                                     speed_;\r
+\r
+       std::array<double, 2>                                           start_offset_;\r
+\r
+       safe_ptr<core::basic_frame>                                     last_frame_;\r
+       \r
+       explicit image_scroll_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& filename, int speed) \r
+               : filename_(filename)\r
+               , delta_(0)\r
+               , format_desc_(frame_factory->get_video_format_desc())\r
+               , speed_(speed)\r
+               , last_frame_(core::basic_frame::empty())\r
+       {\r
+               start_offset_.assign(0.0);\r
+\r
+               auto bitmap = load_image(filename_);\r
+               FreeImage_FlipVertical(bitmap.get());\r
+\r
+               width_  = FreeImage_GetWidth(bitmap.get());\r
+               height_ = FreeImage_GetHeight(bitmap.get());\r
+\r
+               auto bytes = FreeImage_GetBits(bitmap.get());\r
+               int count = width_*height_*4;\r
+\r
+               if(height_ > format_desc_.height)\r
+               {\r
+                       while(count > 0)\r
+                       {\r
+                               auto frame = frame_factory->create_frame(reinterpret_cast<void*>(rand()), width_, format_desc_.height);\r
+                               if(count >= frame->image_data().size())\r
+                               {       \r
+                                       std::copy_n(bytes + count - frame->image_data().size(), frame->image_data().size(), frame->image_data().begin());\r
+                                       count -= frame->image_data().size();\r
+                               }\r
+                               else\r
+                               {\r
+                                       fast_memclr(frame->image_data().begin(), frame->image_data().size());   \r
+                                       std::copy_n(bytes, count, frame->image_data().begin() + format_desc_.size - count);\r
+                                       count = 0;\r
+                               }\r
+                       \r
+                               frame->commit();\r
+                               frames_.push_back(frame);\r
+                       }\r
+                       \r
+                       if(speed_ < 0.0)\r
+                       {\r
+                               auto offset = format_desc_.height - (height_ % format_desc_.height);\r
+                               auto offset2 = offset * 0.5/static_cast<double>(format_desc_.height);\r
+                               start_offset_[1] = (std::ceil(static_cast<double>(height_) / static_cast<double>(format_desc_.height)) + 1.0) * 0.5 - offset2;// - 1.5;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       int i = 0;\r
+                       while(count > 0)\r
+                       {\r
+                               auto frame = frame_factory->create_frame(reinterpret_cast<void*>(rand()), format_desc_.width, height_);\r
+                               if(count >= frame->image_data().size())\r
+                               {       \r
+                                       for(size_t y = 0; y < height_; ++y)\r
+                                               std::copy_n(bytes + i * format_desc_.width*4 + y * width_*4, format_desc_.width*4, frame->image_data().begin() + y * format_desc_.width*4);\r
+                                       \r
+                                       ++i;\r
+                                       count -= frame->image_data().size();\r
+                               }\r
+                               else\r
+                               {\r
+                                       fast_memclr(frame->image_data().begin(), frame->image_data().size());   \r
+                                       int width2 = width_ % format_desc_.width;\r
+                                       for(size_t y = 0; y < height_; ++y)\r
+                                               std::copy_n(bytes + i * format_desc_.width*4 + y * width_*4, width2*4, frame->image_data().begin() + y * format_desc_.width*4);\r
+\r
+                                       count = 0;\r
+                               }\r
+                       \r
+                               frame->commit();\r
+                               frames_.push_back(frame);\r
+                       }\r
+\r
+                       std::reverse(frames_.begin(), frames_.end());\r
+\r
+                       if(speed_ > 0.0)\r
+                       {\r
+                               auto offset = format_desc_.width - (width_ % format_desc_.width);\r
+                               start_offset_[0] = offset * 0.5/static_cast<double>(format_desc_.width);\r
+                       }\r
+                       else\r
+                       {\r
+                               start_offset_[0] = (std::ceil(static_cast<double>(width_) / static_cast<double>(format_desc_.width)) + 1.0) * 0.5;// - 1.5;\r
+                       }\r
+               }\r
+       }\r
+       \r
+       // frame_producer\r
+\r
+       virtual safe_ptr<core::basic_frame> receive(int)\r
+       {               \r
+               delta_ += speed_;\r
+\r
+               if(frames_.empty())\r
+                       return core::basic_frame::eof();\r
+               \r
+               if(height_ > format_desc_.height)\r
+               {\r
+                       if(static_cast<size_t>(std::abs(delta_)) >= height_ - format_desc_.height)\r
+                               return core::basic_frame::eof();\r
+\r
+                       for(size_t n = 0; n < frames_.size(); ++n)\r
+                       {\r
+                               frames_[n]->get_frame_transform().fill_translation[0] = start_offset_[0];\r
+                               frames_[n]->get_frame_transform().fill_translation[1] = start_offset_[1] - (n+1) + delta_ * 0.5/static_cast<double>(format_desc_.height);\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       if(static_cast<size_t>(std::abs(delta_)) >= width_ - format_desc_.width)\r
+                               return core::basic_frame::eof();\r
+\r
+                       for(size_t n = 0; n < frames_.size(); ++n)\r
+                       {\r
+                               frames_[n]->get_frame_transform().fill_translation[0] = start_offset_[0] - (n+1) + delta_ * 0.5/static_cast<double>(format_desc_.width);                                \r
+                               frames_[n]->get_frame_transform().fill_translation[1] = start_offset_[1];\r
+                       }\r
+               }\r
+\r
+               return last_frame_ = core::basic_frame(frames_);\r
+       }\r
+\r
+       virtual safe_ptr<core::basic_frame> last_frame() const\r
+       {\r
+               return last_frame_;\r
+       }\r
+               \r
+       virtual std::wstring print() const\r
+       {\r
+               return L"image_scroll_producer[" + filename_ + L"]";\r
+       }\r
+\r
+       virtual int64_t nb_frames() const \r
+       {\r
+               if(height_ > format_desc_.height)\r
+               {\r
+                       auto length = (height_ - format_desc_.height);\r
+                       return length/std::abs(speed_);// + length % std::abs(delta_));\r
+               }\r
+               else\r
+               {\r
+                       auto length = (width_ - format_desc_.width);\r
+                       auto result = length/std::abs(speed_);// + length % std::abs(delta_));\r
+                       return result;\r
+               }\r
+       }\r
+};\r
+\r
+safe_ptr<core::frame_producer> create_scroll_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::vector<std::wstring>& params)\r
+{\r
+       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");\r
+       std::wstring filename = env::media_folder() + L"\\" + params[0];\r
+       \r
+       auto ext = std::find_if(extensions.begin(), extensions.end(), [&](const std::wstring& ex) -> bool\r
+               {                                       \r
+                       return boost::filesystem::is_regular_file(boost::filesystem::wpath(filename).replace_extension(ex));\r
+               });\r
+\r
+       if(ext == extensions.end())\r
+               return core::frame_producer::empty();\r
+       \r
+       size_t speed = 0;\r
+       auto speed_it = std::find(params.begin(), params.end(), L"SPEED");\r
+       if(speed_it != params.end())\r
+       {\r
+               if(++speed_it != params.end())\r
+                       speed = boost::lexical_cast<int>(*speed_it);\r
+       }\r
+\r
+       if(speed == 0)\r
+               return core::frame_producer::empty();\r
+\r
+       return make_safe<image_scroll_producer>(frame_factory, filename + L"." + *ext, speed);\r
+}\r
+\r
+}}
\ No newline at end of file