]> 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         ~image_scroll_producer()\r
68         {\r
69                 if(factory_)\r
70                         factory_->release_frames(this);\r
71         }\r
72 \r
73         void load_and_pad_image(const std::wstring& filename)\r
74         {\r
75                 auto pBitmap = load_image(filename);\r
76 \r
77                 size_t width = FreeImage_GetWidth(pBitmap.get());\r
78                 size_t height = FreeImage_GetHeight(pBitmap.get());\r
79 \r
80                 image_width_ = std::max(width, format_desc_.width);\r
81                 image_height_ = std::max(height, format_desc_.height);\r
82 \r
83                 image_ = std::shared_ptr<unsigned char>(static_cast<unsigned char*>(scalable_aligned_malloc(image_width_*image_height_*4, 16)));\r
84                 common::clear(image_.get(), image_width_*image_height_*4);\r
85 \r
86                 unsigned char* pBits = FreeImage_GetBits(pBitmap.get());\r
87                 \r
88                 for (size_t i = 0; i < height; ++i)\r
89                         common::aligned_parallel_memcpy(&image_.get()[i * image_width_ * 4], &pBits[i* width * 4], width * 4);\r
90         }\r
91 \r
92         gpu_frame_ptr render_frame()\r
93         {\r
94                 gpu_frame_ptr frame = factory_->create_frame(format_desc_, this);\r
95                 common::clear(frame->data(), frame->size());\r
96 \r
97                 const int delta_x = direction_ == direction::Left ? speed_ : -speed_;\r
98                 const int delta_y = direction_ == direction::Up ? speed_ : -speed_;\r
99 \r
100                 unsigned char* frame_data = frame->data();\r
101                 unsigned char* image_data = image_.get();\r
102         \r
103                 if (direction_ == direction::Up || direction_ == direction::Down)\r
104                 {\r
105                         tbb::parallel_for(static_cast<size_t>(0), format_desc_.height, static_cast<size_t>(1), [&](size_t i)\r
106                         {\r
107                                 int srcRow = i + offset_;\r
108                                 int dstInxex = i * format_desc_.width * 4;\r
109                                 int srcIndex = srcRow * format_desc_.width * 4;\r
110                                 int size = format_desc_.width * 4;\r
111 \r
112                                 memcpy(&frame_data[dstInxex], &image_data[srcIndex], size);     \r
113                         });                             \r
114                         \r
115                         offset_ += delta_y;\r
116                 }\r
117                 else\r
118                 {\r
119                         tbb::parallel_for(static_cast<size_t>(0), format_desc_.height, static_cast<size_t>(1), [&](size_t i)\r
120                         {\r
121                                 int correctOffset = offset_;\r
122                                 int dstIndex = i * format_desc_.width * 4;\r
123                                 int srcIndex = (i * image_width_ + correctOffset) * 4;\r
124                         \r
125                                 int stopOffset = std::min<int>(correctOffset + format_desc_ .width, image_width_);\r
126                                 int size = (stopOffset - correctOffset) * 4;\r
127 \r
128                                 memcpy(&frame_data[dstIndex], &image_data[srcIndex], size);\r
129                         });\r
130 \r
131                         offset_ += delta_x;\r
132                 }\r
133 \r
134                 return frame;\r
135         }\r
136                 \r
137         gpu_frame_ptr get_frame()\r
138         {               \r
139                 if(format_desc_.mode != video_mode::progressive)                                \r
140                 {\r
141                         gpu_frame_ptr frame1;\r
142                         gpu_frame_ptr frame2;\r
143                         tbb::parallel_invoke([&]{ frame1 = render_frame(); }, [&]{ frame2 = render_frame(); });\r
144                         return gpu_composite_frame::interlace(frame1, frame2, format_desc_.mode);\r
145                 }                       \r
146 \r
147                 return render_frame();  \r
148         }\r
149         \r
150         void initialize(const frame_factory_ptr& factory)\r
151         {\r
152                 factory_ = factory;\r
153         }\r
154 \r
155         const frame_format_desc& get_frame_format_desc() const { return format_desc_; } \r
156         \r
157         int image_width_;\r
158         int image_height_;\r
159         int speed_;\r
160         int offset_;\r
161         direction direction_;\r
162 \r
163         tbb::atomic<bool> loop_;\r
164         std::shared_ptr<unsigned char> image_;\r
165         frame_format_desc format_desc_;\r
166 \r
167         frame_factory_ptr factory_;\r
168 };\r
169 \r
170 frame_producer_ptr create_image_scroll_producer(const std::vector<std::wstring>& params, const frame_format_desc& format_desc)\r
171 {\r
172         std::wstring filename = params[0];\r
173         auto result_filename = common::find_file(server::media_folder() + filename, list_of(L"spng")(L"stga")(L"sbmp")(L"sjpg")(L"sjpeg"));\r
174         if(!result_filename.empty())\r
175                 return std::make_shared<image_scroll_producer>(result_filename, params, format_desc);\r
176 \r
177         return nullptr;\r
178 }\r
179 \r
180 }}}