1 #include "../../StdAfx.h"
\r
3 #include "image_scroll_producer.h"
\r
5 #include "image_loader.h"
\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
15 #include <tbb/parallel_for.h>
\r
16 #include <tbb/parallel_invoke.h>
\r
17 #include <tbb/scalable_allocator.h>
\r
19 #include <boost/assign.hpp>
\r
20 #include <boost/algorithm/string/case_conv.hpp>
\r
22 using namespace boost::assign;
\r
24 namespace caspar { namespace core { namespace image{
\r
28 Up, Down, Left, Right
\r
31 struct image_scroll_producer : public frame_producer
\r
33 static const int DEFAULT_SCROLL_SPEED = 50;
\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
38 load_and_pad_image(filename);
\r
40 auto pos = filename.find_last_of(L'_');
\r
41 if(pos != std::wstring::npos && pos + 1 < filename.size())
\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
47 speedStr = speedStr.substr(0, pos);
\r
48 speed_ = common::lexical_cast_or_default<int>(speedStr, image_scroll_producer::DEFAULT_SCROLL_SPEED);
\r
52 loop_ = std::find(params.begin(), params.end(), L"LOOP") != params.end();
\r
54 if(image_width_ - format_desc.width > image_height_ - format_desc_.height)
\r
55 direction_ = speed_ < 0 ? direction::Right : direction::Left;
\r
57 direction_ = speed_ < 0 ? direction::Down : direction::Up;
\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
64 speed_ = static_cast<int>(abs(static_cast<double>(speed_) / format_desc.fps));
\r
67 void load_and_pad_image(const std::wstring& filename)
\r
69 auto pBitmap = load_image(filename);
\r
71 size_t width = FreeImage_GetWidth(pBitmap.get());
\r
72 size_t height = FreeImage_GetHeight(pBitmap.get());
\r
74 image_width_ = std::max(width, format_desc_.width);
\r
75 image_height_ = std::max(height, format_desc_.height);
\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
80 unsigned char* pBits = FreeImage_GetBits(pBitmap.get());
\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
86 gpu_frame_ptr render_frame()
\r
88 gpu_frame_ptr frame = factory_->create_frame(format_desc_);
\r
89 common::clear(frame->data(), frame->size());
\r
91 const int delta_x = direction_ == direction::Left ? speed_ : -speed_;
\r
92 const int delta_y = direction_ == direction::Up ? speed_ : -speed_;
\r
94 unsigned char* frame_data = frame->data();
\r
95 unsigned char* image_data = image_.get();
\r
97 if (direction_ == direction::Up || direction_ == direction::Down)
\r
99 tbb::parallel_for(static_cast<size_t>(0), format_desc_.height, static_cast<size_t>(1), [&](size_t i)
\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
106 memcpy(&frame_data[dstInxex], &image_data[srcIndex], size);
\r
109 offset_ += delta_y;
\r
113 tbb::parallel_for(static_cast<size_t>(0), format_desc_.height, static_cast<size_t>(1), [&](size_t i)
\r
115 int correctOffset = offset_;
\r
116 int dstIndex = i * format_desc_.width * 4;
\r
117 int srcIndex = (i * image_width_ + correctOffset) * 4;
\r
119 int stopOffset = std::min<int>(correctOffset + format_desc_ .width, image_width_);
\r
120 int size = (stopOffset - correctOffset) * 4;
\r
122 memcpy(&frame_data[dstIndex], &image_data[srcIndex], size);
\r
125 offset_ += delta_x;
\r
131 gpu_frame_ptr get_frame()
\r
133 if(format_desc_.mode != video_mode::progressive)
\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
141 return render_frame();
\r
144 void initialize(const frame_factory_ptr& factory)
\r
146 factory_ = factory;
\r
149 const frame_format_desc& get_frame_format_desc() const { return format_desc_; }
\r
155 direction direction_;
\r
157 tbb::atomic<bool> loop_;
\r
158 std::shared_ptr<unsigned char> image_;
\r
159 frame_format_desc format_desc_;
\r
161 frame_factory_ptr factory_;
\r
164 frame_producer_ptr create_image_scroll_producer(const std::vector<std::wstring>& params, const frame_format_desc& format_desc)
\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