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