2 * copyright (c) 2010 Sveriges Television AB <info@casparcg.com>
\r
4 * This file is part of CasparCG.
\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
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
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
25 #include "audio_chunk.h"
\r
26 #include "frame_format.h"
\r
28 #include "../../common/image/image.h"
\r
30 #include <tbb/parallel_invoke.h>
\r
32 #include <boost/range/algorithm.hpp>
\r
36 // NOTE: audio data is ALWAYS shallow copy
\r
37 class frame : boost::noncopyable
\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
49 static std::shared_ptr<frame> null()
\r
51 class null_frame : public frame
\r
53 unsigned char* data() { return nullptr; };
\r
54 size_t size() const { return 0; };
\r
56 static auto my_null_frame = std::make_shared<null_frame>();
\r
57 return my_null_frame;
\r
60 std::vector<audio_chunk_ptr> audioData_;
\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
67 inline bool operator==(const frame& lhs, const frame& rhs)
\r
69 return lhs.data() == rhs.data() && (lhs.data() == nullptr || lhs.size() == rhs.size());
\r
72 template<typename frame_ptr_type>
\r
73 frame_ptr_type& set_frame_volume(frame_ptr_type& result_frame, float volume)
\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
81 template<typename frame_ptr_type>
\r
82 frame_ptr_type& clear_frame(frame_ptr_type& result_frame)
\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
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
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
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
107 return result_frame;
\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
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
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
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
134 if(format_desc.mode == video_mode::progressive)
\r
135 common::image::copy(result_frame->data(), frame->data(), result_frame->size());
\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
139 [&]{boost::range::copy(frame->audio_data(), std::back_inserter(result_frame->audio_data()));});
\r
140 return result_frame;
\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
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
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
160 return result_frame;
\r