]> git.sesse.net Git - casparcg/blob - core/producer/image/image_scroll_producer.cpp
2.0.0.2:
[casparcg] / core / producer / image / image_scroll_producer.cpp
1 #include "../../StdAfx.h"\r
2 \r
3 #include "image_scroll_producer.h"\r
4 \r
5 #include "image_loader.h"\r
6 \r
7 #include "../../frame/gpu_frame.h"\r
8 #include "../../frame/gpu_composite_frame.h"\r
9 #include "../../frame/frame_format.h"\r
10 #include "../../frame/frame_factory.h"\r
11 #include "../../server.h"\r
12 #include "../../../common/utility/find_file.h"\r
13 #include "../../../common/utility/memory.h"\r
14 \r
15 #include <tbb/parallel_for.h>\r
16 #include <tbb/parallel_invoke.h>\r
17 #include <tbb/scalable_allocator.h>\r
18 \r
19 #include <boost/assign.hpp>\r
20 #include <boost/algorithm/string/case_conv.hpp>\r
21 \r
22 using namespace boost::assign;\r
23 \r
24 namespace caspar { namespace core { namespace image{\r
25 \r
26 enum direction\r
27 {\r
28         Up, Down, Left, Right\r
29 };\r
30 \r
31 struct image_scroll_producer : public frame_producer\r
32 {\r
33         static const int DEFAULT_SCROLL_SPEED = 50;\r
34 \r
35         image_scroll_producer(const std::wstring& filename, const std::vector<std::wstring>& params, const frame_format_desc& format_desc) \r
36                 : format_desc_(format_desc), speed_(image_scroll_producer::DEFAULT_SCROLL_SPEED), direction_(direction::Up), offset_(0)\r
37         {\r
38                 load_and_pad_image(filename);\r
39 \r
40                 auto pos = filename.find_last_of(L'_');\r
41                 if(pos != std::wstring::npos && pos + 1 < filename.size())\r
42                 {\r
43                         std::wstring speedStr = filename.substr(pos + 1);\r
44                         pos = speedStr.find_first_of(L'.');\r
45                         if(pos != std::wstring::npos)\r
46                         {\r
47                                 speedStr = speedStr.substr(0, pos);             \r
48                                 speed_ = common::lexical_cast_or_default<int>(speedStr, image_scroll_producer::DEFAULT_SCROLL_SPEED);\r
49                         }\r
50                 }\r
51 \r
52                 loop_ = std::find(params.begin(), params.end(), L"LOOP") != params.end();\r
53                                 \r
54                 if(image_width_ - format_desc.width > image_height_ - format_desc_.height)\r
55                         direction_ = speed_ < 0 ? direction::Right : direction::Left;\r
56                 else\r
57                         direction_ = speed_ < 0 ? direction::Down : direction::Up;\r
58 \r
59                 if (direction_ == direction::Down)\r
60                         offset_ = image_height_ - format_desc_.height;\r
61                 else if (direction_ == direction::Right)\r
62                         offset_ = image_width_ - format_desc_.width;\r
63 \r
64                 speed_ = static_cast<int>(abs(static_cast<double>(speed_) / format_desc.fps));\r
65         }\r
66 \r
67         void load_and_pad_image(const std::wstring& filename)\r
68         {\r
69                 auto pBitmap = load_image(filename);\r
70 \r
71                 size_t width = FreeImage_GetWidth(pBitmap.get());\r
72                 size_t height = FreeImage_GetHeight(pBitmap.get());\r
73 \r
74                 image_width_ = std::max(width, format_desc_.width);\r
75                 image_height_ = std::max(height, format_desc_.height);\r
76 \r
77                 image_ = std::shared_ptr<unsigned char>(static_cast<unsigned char*>(scalable_aligned_malloc(image_width_*image_height_*4, 16)));\r
78                 common::clear(image_.get(), image_width_*image_height_*4);\r
79 \r
80                 unsigned char* pBits = FreeImage_GetBits(pBitmap.get());\r
81                 \r
82                 for (size_t i = 0; i < height; ++i)\r
83                         common::aligned_memcpy(&image_.get()[i * image_width_ * 4], &pBits[i* width * 4], width * 4);\r
84         }\r
85 \r
86         gpu_frame_ptr render_frame()\r
87         {\r
88                 gpu_frame_ptr frame = factory_->create_frame(format_desc_);\r
89                 common::clear(frame->data(), frame->size());\r
90 \r
91                 const int delta_x = direction_ == direction::Left ? speed_ : -speed_;\r
92                 const int delta_y = direction_ == direction::Up ? speed_ : -speed_;\r
93 \r
94                 unsigned char* frame_data = frame->data();\r
95                 unsigned char* image_data = image_.get();\r
96         \r
97                 if (direction_ == direction::Up || direction_ == direction::Down)\r
98                 {\r
99                         tbb::parallel_for(static_cast<size_t>(0), format_desc_.height, static_cast<size_t>(1), [&](size_t i)\r
100                         {\r
101                                 int srcRow = i + offset_;\r
102                                 int dstInxex = i * format_desc_.width * 4;\r
103                                 int srcIndex = srcRow * format_desc_.width * 4;\r
104                                 int size = format_desc_.width * 4;\r
105 \r
106                                 memcpy(&frame_data[dstInxex], &image_data[srcIndex], size);     \r
107                         });                             \r
108                         \r
109                         offset_ += delta_y;\r
110                 }\r
111                 else\r
112                 {\r
113                         tbb::parallel_for(static_cast<size_t>(0), format_desc_.height, static_cast<size_t>(1), [&](size_t i)\r
114                         {\r
115                                 int correctOffset = offset_;\r
116                                 int dstIndex = i * format_desc_.width * 4;\r
117                                 int srcIndex = (i * image_width_ + correctOffset) * 4;\r
118                         \r
119                                 int stopOffset = std::min<int>(correctOffset + format_desc_ .width, image_width_);\r
120                                 int size = (stopOffset - correctOffset) * 4;\r
121 \r
122                                 memcpy(&frame_data[dstIndex], &image_data[srcIndex], size);\r
123                         });\r
124 \r
125                         offset_ += delta_x;\r
126                 }\r
127 \r
128                 return frame;\r
129         }\r
130                 \r
131         gpu_frame_ptr get_frame()\r
132         {               \r
133                 if(format_desc_.mode != video_mode::progressive)                                \r
134                 {\r
135                         gpu_frame_ptr frame1;\r
136                         gpu_frame_ptr frame2;\r
137                         tbb::parallel_invoke([&]{ frame1 = render_frame(); }, [&]{ frame2 = render_frame(); });\r
138                         return gpu_composite_frame::interlace(frame1, frame2, format_desc_.mode);\r
139                 }                       \r
140 \r
141                 return render_frame();  \r
142         }\r
143         \r
144         void initialize(const frame_factory_ptr& factory)\r
145         {\r
146                 factory_ = factory;\r
147         }\r
148 \r
149         const frame_format_desc& get_frame_format_desc() const { return format_desc_; } \r
150         \r
151         int image_width_;\r
152         int image_height_;\r
153         int speed_;\r
154         int offset_;\r
155         direction direction_;\r
156 \r
157         tbb::atomic<bool> loop_;\r
158         std::shared_ptr<unsigned char> image_;\r
159         frame_format_desc format_desc_;\r
160 \r
161         frame_factory_ptr factory_;\r
162 };\r
163 \r
164 frame_producer_ptr create_image_scroll_producer(const std::vector<std::wstring>& params, const frame_format_desc& format_desc)\r
165 {\r
166         std::wstring filename = params[0];\r
167         auto result_filename = common::find_file(server::media_folder() + filename, list_of(L"spng")(L"stga")(L"sbmp")(L"sjpg")(L"sjpeg"));\r
168         if(!result_filename.empty())\r
169                 return std::make_shared<image_scroll_producer>(result_filename, params, format_desc);\r
170 \r
171         return nullptr;\r
172 }\r
173 \r
174 }}}