]> git.sesse.net Git - casparcg/blob - core/frame/frame.h
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches...
[casparcg] / core / frame / frame.h
1 /*\r
2 * copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
3 *\r
4 *  This file is part of CasparCG.\r
5 *\r
6 *    CasparCG is free software: you can redistribute it and/or modify\r
7 *    it under the terms of the GNU General Public License as published by\r
8 *    the Free Software Foundation, either version 3 of the License, or\r
9 *    (at your option) any later version.\r
10 *\r
11 *    CasparCG is distributed in the hope that it will be useful,\r
12 *    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14 *    GNU General Public License for more details.\r
15 \r
16 *    You should have received a copy of the GNU General Public License\r
17 *    along with CasparCG.  If not, see <http://www.gnu.org/licenses/>.\r
18 *\r
19 */\r
20 #pragma once\r
21 \r
22 #include <memory>\r
23 #include <vector>\r
24 \r
25 #include "audio_chunk.h"\r
26 #include "frame_format.h"\r
27 \r
28 #include "../../common/image/image.h"\r
29 \r
30 #include <tbb/parallel_invoke.h>\r
31 \r
32 #include <boost/range/algorithm.hpp>\r
33 \r
34 namespace caspar {\r
35 \r
36 // NOTE: audio data is ALWAYS shallow copy\r
37 class frame : boost::noncopyable\r
38 {\r
39 public:\r
40         virtual ~frame(){}\r
41         \r
42         virtual const unsigned char* data() const { return const_cast<frame&>(*this).data(); }\r
43         virtual unsigned char* data() = 0;\r
44         virtual size_t size() const = 0;\r
45         virtual void* tag() const { return nullptr; }\r
46         virtual const std::vector<audio_chunk_ptr>& audio_data() const { return audioData_; }   \r
47         virtual std::vector<audio_chunk_ptr>& audio_data() { return audioData_; }                       \r
48 \r
49         static std::shared_ptr<frame> null()\r
50         {\r
51                 class null_frame : public frame\r
52                 {\r
53                         unsigned char* data() { return nullptr; };\r
54                         size_t size() const { return 0; };\r
55                 };\r
56                 static auto my_null_frame = std::make_shared<null_frame>();\r
57                 return my_null_frame;\r
58         }\r
59 private:        \r
60         std::vector<audio_chunk_ptr> audioData_;\r
61 };\r
62 typedef std::shared_ptr<frame> frame_ptr;\r
63 typedef std::shared_ptr<const frame> frame_const_ptr;\r
64 typedef std::unique_ptr<frame> frame_uptr;\r
65 typedef std::unique_ptr<const frame> frame_const_uptr;\r
66 \r
67 inline bool operator==(const frame& lhs, const frame& rhs)\r
68 {\r
69         return lhs.data() == rhs.data() && (lhs.data() == nullptr || lhs.size() == rhs.size());\r
70 }\r
71 \r
72 template<typename frame_ptr_type>\r
73 frame_ptr_type& set_frame_volume(frame_ptr_type& result_frame, float volume)\r
74 {\r
75         assert(result_frame != nullptr);\r
76         assert(boost::range::find(result_frame->audio_data(), nullptr) == result_frame->audio_data().end());\r
77         boost::range::for_each(result_frame->audio_data(), std::bind(&audio_chunk::set_volume, std::placeholders::_1, volume));\r
78         return result_frame;\r
79 }\r
80 \r
81 template<typename frame_ptr_type>\r
82 frame_ptr_type& clear_frame(frame_ptr_type& result_frame)\r
83 {\r
84         assert(result_frame != nullptr);\r
85         common::image::clear(result_frame->data(), result_frame->size());\r
86         result_frame->audio_data().clear();\r
87         return result_frame;\r
88 }\r
89 \r
90 template<typename frame_ptr_type>\r
91 frame_ptr_type& pre_over_frame(frame_ptr_type& result_frame, const frame_const_ptr& frame1, const frame_const_ptr& frame2)\r
92 {\r
93         assert(result_frame != nullptr && frame1 != nullptr && frame2 != nullptr);\r
94         assert(result_frame->size() == frame1->size());\r
95         assert(result_frame->size() == frame2->size());\r
96         assert(boost::range::find(frame1->audio_data(), nullptr) == frame1->audio_data().end());\r
97         assert(boost::range::find(frame2->audio_data(), nullptr) == frame2->audio_data().end());\r
98         tbb::parallel_invoke(\r
99         [&]{common::image::pre_over(result_frame->data(), frame1->data(), frame2->data(), result_frame->size());},\r
100         [&]\r
101         {\r
102                 if(result_frame != frame1)\r
103                         boost::range::copy(frame1->audio_data(), std::back_inserter(result_frame->audio_data()));\r
104                 if(result_frame != frame2)\r
105                         boost::range::copy(frame2->audio_data(), std::back_inserter(result_frame->audio_data()));\r
106         });\r
107         return result_frame;\r
108 }\r
109 \r
110 template<typename frame_ptr_type>\r
111 frame_ptr_type& copy_frame(frame_ptr_type& result_frame, const frame_const_ptr& frame)\r
112 {       \r
113         assert(result_frame != nullptr && frame != nullptr);\r
114         assert(result_frame->size() == frame->size());\r
115         if(result_frame == frame)\r
116                 return result_frame;\r
117         tbb::parallel_invoke(\r
118         [&]{common::image::copy(result_frame->data(), frame->data(), result_frame->size());},\r
119         [&]{boost::range::copy(frame->audio_data(), std::back_inserter(result_frame->audio_data()));});\r
120         return result_frame;\r
121\r
122 \r
123 template<typename frame_ptr_type>\r
124 frame_ptr_type& copy_frame(frame_ptr_type& result_frame, const frame_const_ptr& frame, const frame_format_desc& format_desc)\r
125 {       \r
126         assert(result_frame != nullptr && frame != nullptr);\r
127         assert(result_frame->size() == format_desc.size);\r
128         assert(frame->size() == format_desc.size);\r
129         if(result_frame == frame)\r
130                 return result_frame;\r
131         tbb::parallel_invoke(\r
132         [&]\r
133         {\r
134                 if(format_desc.mode == video_mode::progressive)\r
135                         common::image::copy(result_frame->data(), frame->data(), result_frame->size());\r
136                 else\r
137                         common::image::copy_field(result_frame->data(), frame->data(), format_desc.mode == video_mode::upper ? 1 : 0, format_desc.width, format_desc.height);\r
138         },\r
139         [&]{boost::range::copy(frame->audio_data(), std::back_inserter(result_frame->audio_data()));});\r
140         return result_frame;\r
141\r
142 \r
143 template<typename frame_ptr_type, typename frame_container>\r
144 frame_ptr_type& compose_frames(frame_ptr_type& result_frame, const frame_container& frames)\r
145 {\r
146         assert(boost::range::find(frames, nullptr) == frames.end());\r
147         assert(boost::range::find_if(frames, [&](const frame_ptr& frame) { return frame->size() != result_frame->size();}) == frames.end());\r
148         if(frames.empty())      \r
149                 clear_frame(result_frame);      \r
150         else if(frames.size() == 1)     \r
151                 copy_frame(result_frame, frames[0]);    \r
152         else if(frames.size() == 2)     \r
153                 pre_over_frame(result_frame, frames[0], frames[1]);     \r
154         else\r
155         {\r
156                 for(size_t n = 0; n < frames.size() - 2; ++n)\r
157                         pre_over_frame(frames[0], frames[n], frames[n+1]);\r
158                 pre_over_frame(result_frame, frames[0], frames[frames.size()-1]);\r
159         }\r
160         return result_frame;\r
161 }\r
162 \r
163 }