-/*\r
-* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG.\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-*/\r
-#pragma once\r
-\r
-#include <memory>\r
-#include <vector>\r
-\r
-#include "audio_chunk.h"\r
-#include "frame_format.h"\r
-\r
-#include "../../common/image/image.h"\r
-\r
-#include <tbb/parallel_invoke.h>\r
-\r
-#include <boost/range/algorithm.hpp>\r
-\r
-namespace caspar {\r
-\r
-// NOTE: audio data is ALWAYS shallow copy\r
-class frame : boost::noncopyable\r
-{\r
-public:\r
- virtual ~frame(){}\r
- \r
- virtual const unsigned char* data() const { return const_cast<frame&>(*this).data(); }\r
- virtual unsigned char* data() = 0;\r
- virtual size_t size() const = 0;\r
- virtual void* tag() const { return nullptr; }\r
- virtual const std::vector<audio_chunk_ptr>& audio_data() const { return audioData_; } \r
- virtual std::vector<audio_chunk_ptr>& audio_data() { return audioData_; } \r
-\r
- static std::shared_ptr<frame> null()\r
- {\r
- class null_frame : public frame\r
- {\r
- unsigned char* data() { return nullptr; };\r
- size_t size() const { return 0; };\r
- };\r
- static auto my_null_frame = std::make_shared<null_frame>();\r
- return my_null_frame;\r
- }\r
-private: \r
- std::vector<audio_chunk_ptr> audioData_;\r
-};\r
-typedef std::shared_ptr<frame> frame_ptr;\r
-typedef std::shared_ptr<const frame> frame_const_ptr;\r
-typedef std::unique_ptr<frame> frame_uptr;\r
-typedef std::unique_ptr<const frame> frame_const_uptr;\r
-\r
-inline bool operator==(const frame& lhs, const frame& rhs)\r
-{\r
- return lhs.data() == rhs.data() && (lhs.data() == nullptr || lhs.size() == rhs.size());\r
-}\r
-\r
-template<typename frame_ptr_type>\r
-frame_ptr_type& set_frame_volume(frame_ptr_type& result_frame, float volume)\r
-{\r
- assert(result_frame != nullptr);\r
- assert(boost::range::find(result_frame->audio_data(), nullptr) == result_frame->audio_data().end());\r
- boost::range::for_each(result_frame->audio_data(), std::bind(&audio_chunk::set_volume, std::placeholders::_1, volume));\r
- return result_frame;\r
-}\r
-\r
-template<typename frame_ptr_type>\r
-frame_ptr_type& clear_frame(frame_ptr_type& result_frame)\r
-{\r
- assert(result_frame != nullptr);\r
- common::image::clear(result_frame->data(), result_frame->size());\r
- result_frame->audio_data().clear();\r
- return result_frame;\r
-}\r
-\r
-template<typename frame_ptr_type>\r
-frame_ptr_type& pre_over_frame(frame_ptr_type& result_frame, const frame_const_ptr& frame1, const frame_const_ptr& frame2)\r
-{\r
- assert(result_frame != nullptr && frame1 != nullptr && frame2 != nullptr);\r
- assert(result_frame->size() == frame1->size());\r
- assert(result_frame->size() == frame2->size());\r
- assert(boost::range::find(frame1->audio_data(), nullptr) == frame1->audio_data().end());\r
- assert(boost::range::find(frame2->audio_data(), nullptr) == frame2->audio_data().end());\r
- tbb::parallel_invoke(\r
- [&]{common::image::pre_over(result_frame->data(), frame1->data(), frame2->data(), result_frame->size());},\r
- [&]\r
- {\r
- if(result_frame != frame1)\r
- boost::range::copy(frame1->audio_data(), std::back_inserter(result_frame->audio_data()));\r
- if(result_frame != frame2)\r
- boost::range::copy(frame2->audio_data(), std::back_inserter(result_frame->audio_data()));\r
- });\r
- return result_frame;\r
-}\r
-\r
-template<typename frame_ptr_type>\r
-frame_ptr_type& copy_frame(frame_ptr_type& result_frame, const frame_const_ptr& frame)\r
-{ \r
- assert(result_frame != nullptr && frame != nullptr);\r
- assert(result_frame->size() == frame->size());\r
- if(result_frame == frame)\r
- return result_frame;\r
- tbb::parallel_invoke(\r
- [&]{common::image::copy(result_frame->data(), frame->data(), result_frame->size());},\r
- [&]{boost::range::copy(frame->audio_data(), std::back_inserter(result_frame->audio_data()));});\r
- return result_frame;\r
-} \r
-\r
-template<typename frame_ptr_type>\r
-frame_ptr_type& copy_frame(frame_ptr_type& result_frame, const frame_const_ptr& frame, const frame_format_desc& format_desc)\r
-{ \r
- assert(result_frame != nullptr && frame != nullptr);\r
- assert(result_frame->size() == format_desc.size);\r
- assert(frame->size() == format_desc.size);\r
- if(result_frame == frame)\r
- return result_frame;\r
- tbb::parallel_invoke(\r
- [&]\r
- {\r
- if(format_desc.mode == video_mode::progressive)\r
- common::image::copy(result_frame->data(), frame->data(), result_frame->size());\r
- else\r
- common::image::copy_field(result_frame->data(), frame->data(), format_desc.mode == video_mode::upper ? 1 : 0, format_desc.width, format_desc.height);\r
- },\r
- [&]{boost::range::copy(frame->audio_data(), std::back_inserter(result_frame->audio_data()));});\r
- return result_frame;\r
-} \r
-\r
-template<typename frame_ptr_type, typename frame_container>\r
-frame_ptr_type& compose_frames(frame_ptr_type& result_frame, const frame_container& frames)\r
-{\r
- assert(boost::range::find(frames, nullptr) == frames.end());\r
- assert(boost::range::find_if(frames, [&](const frame_ptr& frame) { return frame->size() != result_frame->size();}) == frames.end());\r
- if(frames.empty()) \r
- clear_frame(result_frame); \r
- else if(frames.size() == 1) \r
- copy_frame(result_frame, frames[0]); \r
- else if(frames.size() == 2) \r
- pre_over_frame(result_frame, frames[0], frames[1]); \r
- else\r
- {\r
- for(size_t n = 0; n < frames.size() - 2; ++n)\r
- pre_over_frame(frames[0], frames[n], frames[n+1]);\r
- pre_over_frame(result_frame, frames[0], frames[frames.size()-1]);\r
- }\r
- return result_frame;\r
-}\r
-\r
-}
\ No newline at end of file
+#pragma once
+
+#undef BOOST_PARAMETER_MAX_ARITY
+#define BOOST_PARAMETER_MAX_ARITY 7
+
+#include "../fwd.h"
+
+#include <common/memory.h>
+#include <common/forward.h>
+#include <common/array.h>
+#include <common/future_fwd.h>
+#include <common/cache_aligned_vector.h>
+#include <common/timer.h>
+
+#include <cstddef>
+#include <cstdint>
+
+FORWARD1(boost, template<typename> class shared_future);
+
+namespace caspar { namespace core {
+
+typedef caspar::array<const int32_t> audio_buffer;
+typedef cache_aligned_vector<int32_t> mutable_audio_buffer;
+class frame_geometry;
+
+class mutable_frame final
+{
+ mutable_frame(const mutable_frame&);
+ mutable_frame& operator=(const mutable_frame&);
+public:
+
+ // Static Members
+
+ // Constructors
+
+ explicit mutable_frame(std::vector<array<std::uint8_t>> image_buffers,
+ mutable_audio_buffer audio_data,
+ const void* tag,
+ const pixel_format_desc& desc,
+ const audio_channel_layout& channel_layout);
+ ~mutable_frame();
+
+ // Methods
+
+ mutable_frame(mutable_frame&& other);
+ mutable_frame& operator=(mutable_frame&& other);
+
+ void swap(mutable_frame& other);
+
+ // Properties
+
+ const core::pixel_format_desc& pixel_format_desc() const;
+ const core::audio_channel_layout& audio_channel_layout() const;
+
+ const array<std::uint8_t>& image_data(std::size_t index = 0) const;
+ const core::mutable_audio_buffer& audio_data() const;
+
+ array<std::uint8_t>& image_data(std::size_t index = 0);
+ core::mutable_audio_buffer& audio_data();
+
+ std::size_t width() const;
+ std::size_t height() const;
+
+ const void* stream_tag() const;
+
+ const core::frame_geometry& geometry() const;
+ void set_geometry(const frame_geometry& g);
+
+ caspar::timer since_created() const;
+
+private:
+ struct impl;
+ spl::unique_ptr<impl> impl_;
+};
+
+class const_frame final
+{
+ struct impl;
+public:
+
+ // Static Members
+
+ static const const_frame& empty();
+
+ // Constructors
+
+ explicit const_frame(const void* tag = nullptr);
+ explicit const_frame(std::shared_future<array<const std::uint8_t>> image,
+ audio_buffer audio_data,
+ const void* tag,
+ const pixel_format_desc& desc,
+ const audio_channel_layout& channel_layout);
+ const_frame(mutable_frame&& other);
+ ~const_frame();
+
+ // Methods
+
+ const_frame(const_frame&& other);
+ const_frame& operator=(const_frame&& other);
+ const_frame(const const_frame&);
+ const_frame(const const_frame::impl&);
+ const_frame& operator=(const const_frame& other);
+
+ const_frame key_only() const;
+
+ // Properties
+
+ const core::pixel_format_desc& pixel_format_desc() const;
+ const core::audio_channel_layout& audio_channel_layout() const;
+
+ array<const std::uint8_t> image_data(int index = 0) const;
+ const core::audio_buffer& audio_data() const;
+
+ std::size_t width() const;
+ std::size_t height() const;
+ std::size_t size() const;
+
+ const void* stream_tag() const;
+
+ const core::frame_geometry& geometry() const;
+ const_frame with_geometry(const frame_geometry& g) const;
+ int64_t get_age_millis() const;
+
+ bool operator==(const const_frame& other);
+ bool operator!=(const const_frame& other);
+ bool operator<(const const_frame& other);
+ bool operator>(const const_frame& other);
+
+private:
+ spl::shared_ptr<impl> impl_;
+};
+
+}}