#include "pixel_format.h"\r
\r
namespace caspar { namespace core {\r
-\r
-data_frame::~data_frame()\r
-{\r
-}\r
-\r
+ \r
safe_ptr<data_frame> data_frame::empty()\r
{\r
struct empty_frame : public data_frame\r
{\r
+ empty_frame(){}\r
virtual const struct pixel_format_desc& get_pixel_format_desc() const override\r
{\r
static pixel_format_desc invalid(pixel_format::invalid);\r
return invalid;\r
}\r
- virtual const boost::iterator_range<const uint8_t*> image_data() const override\r
+ virtual const boost::iterator_range<const uint8_t*> image_data(int) const override\r
{\r
return boost::iterator_range<const uint8_t*>();\r
}\r
- virtual const boost::iterator_range<const int32_t*> audio_data() const override\r
+ virtual audio_buffer& audio_data() const override\r
{\r
- return boost::iterator_range<const int32_t*>();\r
+ static audio_buffer buffer;\r
+ return buffer;\r
}\r
- const boost::iterator_range<uint8_t*> image_data() override\r
+ const boost::iterator_range<uint8_t*> image_data(int) override\r
{\r
return boost::iterator_range<uint8_t*>();\r
}\r
- const boost::iterator_range<int32_t*> audio_data() override\r
+ audio_buffer& audio_data() override\r
{\r
- return boost::iterator_range<int32_t*>();\r
+ static audio_buffer buffer;\r
+ return buffer;\r
}\r
virtual double get_frame_rate() const override\r
{\r
{\r
return 0;\r
}\r
+ virtual const void* tag() const override\r
+ {\r
+ return 0;\r
+ }\r
};\r
\r
static safe_ptr<empty_frame> empty;\r
#include <boost/noncopyable.hpp>\r
#include <boost/range.hpp>\r
\r
+#include <tbb/cache_aligned_allocator.h>\r
+\r
#include <stdint.h>\r
\r
#include "../video_format.h"\r
\r
namespace caspar { namespace core {\r
+ \r
+typedef std::vector<int32_t, tbb::cache_aligned_allocator<int32_t>> audio_buffer;\r
\r
-struct pixel_format_desc;\r
-\r
-struct data_frame : boost::noncopyable\r
+struct data_frame\r
{\r
- virtual ~data_frame();\r
+ data_frame(){}\r
+ virtual ~data_frame(){}\r
\r
virtual const struct pixel_format_desc& get_pixel_format_desc() const = 0;\r
\r
- virtual const boost::iterator_range<const uint8_t*> image_data() const = 0;\r
- virtual const boost::iterator_range<const int32_t*> audio_data() const = 0;\r
+ virtual const boost::iterator_range<const uint8_t*> image_data(int index = 0) const = 0;\r
+ virtual const audio_buffer& audio_data() const = 0;\r
\r
- virtual const boost::iterator_range<uint8_t*> image_data() = 0;\r
- virtual const boost::iterator_range<int32_t*> audio_data() = 0;\r
+ virtual const boost::iterator_range<uint8_t*> image_data(int index) = 0;\r
+ virtual audio_buffer& audio_data() = 0;\r
\r
virtual double get_frame_rate() const = 0;\r
\r
virtual int width() const = 0;\r
virtual int height() const = 0;\r
\r
+ virtual const void* tag() const = 0;\r
+\r
static safe_ptr<data_frame> empty();\r
+private:\r
+ data_frame(const data_frame&);\r
+ data_frame& operator=(const data_frame&);\r
};\r
\r
}}
\ No newline at end of file
blend_func(c1, c2, c1, c2);\r
}\r
\r
-boost::unique_future<safe_ptr<device_buffer>> accelerator::copy_async(safe_ptr<host_buffer>&& source, int width, int height, int stride)\r
+boost::unique_future<safe_ptr<device_buffer>> accelerator::copy_async(safe_ptr<host_buffer>& source, int width, int height, int stride)\r
{\r
return executor_.begin_invoke([=]() -> safe_ptr<device_buffer>\r
{\r
\r
std::wstring version();\r
\r
- boost::unique_future<safe_ptr<device_buffer>> copy_async(safe_ptr<host_buffer>&& source, int width, int height, int stride);\r
+ boost::unique_future<safe_ptr<device_buffer>> copy_async(safe_ptr<host_buffer>& source, int width, int height, int stride);\r
\r
private:\r
safe_ptr<device_buffer> allocate_device_buffer(int width, int height, int stride);\r
{ \r
item item;\r
item.pix_desc = frame.get_pixel_format_desc();\r
- item.textures = frame.get_textures();\r
+\r
+ auto buffers = frame.get_buffers();\r
+ auto planes = frame.get_pixel_format_desc().planes;\r
+ for(size_t n = 0; n < planes.size(); ++n) \r
+ item.textures.push_back(ogl_->copy_async(buffers.at(n), planes[n].width, planes[n].height, planes[n].channels));\r
+ \r
item.transform = transform_stack_.back();\r
\r
layers_.back().second.push_back(item);\r
const audio_buffer audio_data_;\r
const video_format_desc video_desc_;\r
pixel_format_desc pixel_desc_;\r
+ const void* tag_;\r
\r
public:\r
- impl(boost::unique_future<safe_ptr<gpu::host_buffer>>&& image_data, audio_buffer&& audio_data, const video_format_desc& format_desc) \r
- : image_data_(std::move(image_data))\r
+ impl(const void* tag, boost::unique_future<safe_ptr<gpu::host_buffer>>&& image_data, audio_buffer&& audio_data, const video_format_desc& format_desc) \r
+ : tag_(tag)\r
+ , image_data_(std::move(image_data))\r
, audio_data_(std::move(audio_data))\r
, video_desc_(format_desc)\r
, pixel_desc_(core::pixel_format::bgra)\r
pixel_desc_.planes.push_back(core::pixel_format_desc::plane(format_desc.width, format_desc.height, 4));\r
} \r
\r
- const boost::iterator_range<const uint8_t*> image_data()\r
+ const boost::iterator_range<const uint8_t*> image_data(int)\r
{\r
auto ptr = static_cast<const uint8_t*>(image_data_.get()->data());\r
return boost::iterator_range<const uint8_t*>(ptr, ptr + image_data_.get()->size());\r
}\r
- const boost::iterator_range<const int32_t*> audio_data()\r
- {\r
- return boost::iterator_range<const int32_t*>(audio_data_.data(), audio_data_.data() + audio_data_.size());\r
- }\r
};\r
\r
-read_frame::read_frame(boost::unique_future<safe_ptr<gpu::host_buffer>>&& image_data, audio_buffer&& audio_data, const video_format_desc& format_desc) \r
- : impl_(new impl(std::move(image_data), std::move(audio_data), format_desc)){}\r
-const boost::iterator_range<const uint8_t*> read_frame::image_data() const{ return impl_->image_data();}\r
-const boost::iterator_range<const int32_t*> read_frame::audio_data() const{ return impl_->audio_data();}\r
+read_frame::read_frame(const void* tag, boost::unique_future<safe_ptr<gpu::host_buffer>>&& image_data, audio_buffer&& audio_data, const video_format_desc& format_desc) \r
+ : impl_(new impl(tag, std::move(image_data), std::move(audio_data), format_desc)){}\r
+const boost::iterator_range<const uint8_t*> read_frame::image_data(int index) const{ return impl_->image_data(index);}\r
+const audio_buffer& read_frame::audio_data() const{ return impl_->audio_data_;}\r
const pixel_format_desc& read_frame::get_pixel_format_desc() const{ return impl_->pixel_desc_;}\r
double read_frame::get_frame_rate() const {return impl_->video_desc_.fps;}\r
int read_frame::width() const {return impl_->video_desc_.width;}\r
int read_frame::height() const {return impl_->video_desc_.height;}\r
-\r
-safe_ptr<const read_frame> read_frame::create(boost::unique_future<safe_ptr<gpu::host_buffer>>&& image_data, audio_buffer&& audio_data, const struct video_format_desc& format_desc)\r
-{\r
- return safe_ptr<const read_frame>(new read_frame(std::move(image_data), std::move(audio_data), format_desc));\r
-}\r
+const void* read_frame::tag() const{return impl_->tag_;}\r
\r
//#include <tbb/scalable_allocator.h>\r
//#include <tbb/parallel_for.h>\r
\r
class read_frame sealed : public data_frame\r
{\r
- read_frame(boost::unique_future<safe_ptr<gpu::host_buffer>>&& image_data, audio_buffer&& audio_data, const struct video_format_desc& format_desc);\r
public:\r
- static safe_ptr<const read_frame> create(boost::unique_future<safe_ptr<gpu::host_buffer>>&& image_data, audio_buffer&& audio_data, const struct video_format_desc& format_desc);\r
- \r
+ read_frame(const void* tag, boost::unique_future<safe_ptr<gpu::host_buffer>>&& image_data, audio_buffer&& audio_data, const struct video_format_desc& format_desc);\r
+ \r
+ // data_frame\r
+\r
virtual const struct pixel_format_desc& get_pixel_format_desc() const override;\r
\r
- virtual const boost::iterator_range<const uint8_t*> image_data() const override;\r
- virtual const boost::iterator_range<const int32_t*> audio_data() const override;\r
+ virtual const boost::iterator_range<const uint8_t*> image_data(int index) const override;\r
+ virtual const audio_buffer& audio_data() const override;\r
\r
virtual double get_frame_rate() const override;\r
\r
virtual int width() const override;\r
virtual int height() const override;\r
\r
- virtual const boost::iterator_range<uint8_t*> image_data() override\r
+ virtual const boost::iterator_range<uint8_t*> image_data(int index) override\r
{\r
BOOST_THROW_EXCEPTION(invalid_operation());\r
}\r
- virtual const boost::iterator_range<int32_t*> audio_data() override\r
+ virtual audio_buffer& audio_data() override\r
{\r
BOOST_THROW_EXCEPTION(invalid_operation());\r
}\r
- \r
+ \r
+ virtual const void* tag() const override; \r
private:\r
struct impl;\r
std::shared_ptr<impl> impl_;\r
\r
struct write_frame::impl : boost::noncopyable\r
{ \r
- std::shared_ptr<gpu::accelerator> ogl_;\r
- std::vector<std::shared_ptr<gpu::host_buffer>> buffers_;\r
- std::vector<boost::shared_future<safe_ptr<gpu::device_buffer>>> textures_;\r
- audio_buffer audio_data_;\r
- const core::pixel_format_desc desc_;\r
- const void* tag_;\r
+ std::shared_ptr<gpu::accelerator> ogl_;\r
+ std::vector<safe_ptr<gpu::host_buffer>> buffers_;\r
+ audio_buffer audio_data_;\r
+ const core::pixel_format_desc desc_;\r
+ const void* tag_;\r
\r
impl(const void* tag)\r
: desc_(core::pixel_format::invalid)\r
{\r
return ogl_->create_host_buffer(plane.size, gpu::host_buffer::usage::write_only);\r
});\r
- textures_.resize(desc.planes.size());\r
}\r
\r
void accept(write_frame& self, core::frame_visitor& visitor)\r
auto ptr = static_cast<uint8_t*>(buffers_[index]->data());\r
return boost::iterator_range<uint8_t*>(ptr, ptr+buffers_[index]->size());\r
}\r
- \r
- void commit()\r
- {\r
- for(int n = 0; n < buffers_.size(); ++n)\r
- commit(n);\r
- }\r
-\r
- void commit(int plane_index)\r
- {\r
- if(plane_index >= buffers_.size())\r
- return;\r
- \r
- auto buffer = std::move(buffers_[plane_index]); // Release buffer once done.\r
-\r
- if(!buffer)\r
- return;\r
- \r
- auto plane = desc_.planes.at(plane_index);\r
- textures_.at(plane_index) = ogl_->copy_async(make_safe_ptr(std::move(buffer)), plane.width, plane.height, plane.channels);\r
- }\r
};\r
\r
write_frame::write_frame(const void* tag) : impl_(new impl(tag)){}\r
return *this;\r
}\r
void write_frame::swap(write_frame& other){impl_.swap(other.impl_);}\r
-boost::iterator_range<uint8_t*> write_frame::image_data(int index){return impl_->image_data(index);}\r
-audio_buffer& write_frame::audio_data() { return impl_->audio_data_; }\r
-const void* write_frame::tag() const {return impl_->tag_;}\r
-const core::pixel_format_desc& write_frame::get_pixel_format_desc() const{return impl_->desc_;}\r
-const std::vector<boost::shared_future<safe_ptr<gpu::device_buffer>>>& write_frame::get_textures() const{return impl_->textures_;}\r
-void write_frame::commit(int plane_index){impl_->commit(plane_index);}\r
-void write_frame::commit(){impl_->commit();}\r
+\r
void write_frame::accept(core::frame_visitor& visitor){impl_->accept(*this, visitor);}\r
\r
+const pixel_format_desc& write_frame::get_pixel_format_desc() const{return impl_->desc_;}\r
+const boost::iterator_range<const uint8_t*> write_frame::image_data(int index) const{return impl_->image_data(index);}\r
+const audio_buffer& write_frame::audio_data() const{return impl_->audio_data_;}\r
+const boost::iterator_range<uint8_t*> write_frame::image_data(int index){return impl_->image_data(index);}\r
+audio_buffer& write_frame::audio_data(){return impl_->audio_data_;}\r
+double write_frame::get_frame_rate() const{return 0.0;} // TODO: what's this?\r
+int write_frame::width() const{return impl_->desc_.planes.at(0).width;}\r
+int write_frame::height() const{return impl_->desc_.planes.at(0).height;} \r
+const void* write_frame::tag() const{return impl_->tag_;} \r
+std::vector<safe_ptr<gpu::host_buffer>> write_frame::get_buffers(){return impl_->buffers_;}\r
+\r
+\r
}}
\ No newline at end of file
#include <common/forward.h>\r
\r
#include <core/frame/draw_frame.h>\r
+#include <core/frame/data_frame.h>\r
#include <core/video_format.h>\r
#include <core/mixer/audio/audio_mixer.h>\r
\r
#include <stdint.h>\r
#include <vector>\r
\r
-FORWARD1(boost, template<typename> class shared_future);\r
FORWARD3(caspar, core, gpu, class accelerator);\r
-FORWARD3(caspar, core, gpu, class device_buffer);\r
+FORWARD3(caspar, core, gpu, class host_buffer);\r
\r
namespace caspar { namespace core {\r
\r
-class write_frame sealed : public core::draw_frame\r
+class write_frame sealed : public core::draw_frame, public core::data_frame\r
{\r
+ write_frame(const write_frame&);\r
+ write_frame& operator=(const write_frame);\r
public: \r
explicit write_frame(const void* tag);\r
explicit write_frame(const safe_ptr<gpu::accelerator>& ogl, const void* tag, const struct pixel_format_desc& desc);\r
\r
write_frame(write_frame&& other);\r
write_frame& operator=(write_frame&& other);\r
+\r
+ void swap(write_frame& other);\r
\r
// draw_frame\r
\r
virtual void accept(struct frame_visitor& visitor) override;\r
\r
- // write _frame\r
-\r
- void swap(write_frame& other);\r
- \r
- boost::iterator_range<uint8_t*> image_data(int plane_index = 0); \r
- audio_buffer& audio_data();\r
- \r
- void commit(int plane_index);\r
- void commit();\r
+ // data_frame\r
\r
- const void* tag() const;\r
+ virtual const struct pixel_format_desc& get_pixel_format_desc() const override;\r
+\r
+ virtual const boost::iterator_range<const uint8_t*> image_data(int index) const override;\r
+ virtual const audio_buffer& audio_data() const override;\r
\r
- const struct pixel_format_desc& get_pixel_format_desc() const;\r
+ virtual const boost::iterator_range<uint8_t*> image_data(int index) override;\r
+ virtual audio_buffer& audio_data() override;\r
\r
- const std::vector<boost::shared_future<safe_ptr<gpu::device_buffer>>>& get_textures() const;\r
+ virtual double get_frame_rate() const override;\r
+\r
+ virtual int width() const override;\r
+ virtual int height() const override;\r
+ \r
+ virtual const void* tag() const override;\r
+ \r
+ // write_frames\r
+\r
+ std::vector<safe_ptr<gpu::host_buffer>> get_buffers();\r
private:\r
struct impl;\r
safe_ptr<impl> impl_;\r
auto image = (*image_mixer_)(format_desc);\r
auto audio = audio_mixer_(format_desc);\r
\r
- return read_frame::create(std::move(image), std::move(audio), format_desc); \r
+ return make_safe<read_frame>(this, std::move(image), std::move(audio), format_desc); \r
}\r
catch(...)\r
{\r
\r
// Read color from hex-string and write to frame pixel.\r
\r
- auto& value = *reinterpret_cast<uint32_t*>(frame->image_data().begin());\r
+ auto& value = *reinterpret_cast<uint32_t*>(frame->image_data(0).begin());\r
std::wstringstream str(color2.substr(1));\r
if(!(str >> std::hex >> value) || !str.eof())\r
BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("color") << arg_value_info(color2) << msg_info("Invalid color."));\r
-\r
- frame->commit();\r
- \r
+ \r
return frame;\r
}\r
\r
\r
// decklink_frame \r
\r
- const boost::iterator_range<const int32_t*> audio_data()\r
+ const core::audio_buffer& audio_data()\r
{\r
return frame_->audio_data();\r
}\r
}\r
case display_mode::duplicate: \r
{\r
- auto frame2 = make_safe<core::write_frame>(*frame1);\r
- frame2->audio_data() = pop_audio();\r
+ // TODO: Test this!\r
+ auto frame2 = frame1;\r
+ boost::range::push_back(frame2->audio_data(), pop_audio());\r
\r
frame_buffer_.push(frame1);\r
frame_buffer_.push(frame2);\r
avcodec_get_frame_defaults(av_frame.get()); \r
if(target_pix_fmt == PIX_FMT_BGRA)\r
{\r
- auto size = avpicture_fill(reinterpret_cast<AVPicture*>(av_frame.get()), write->image_data().begin(), PIX_FMT_BGRA, width, height);\r
- CASPAR_VERIFY(size == write->image_data().size()); \r
+ auto size = avpicture_fill(reinterpret_cast<AVPicture*>(av_frame.get()), write->image_data(0).begin(), PIX_FMT_BGRA, width, height);\r
+ CASPAR_VERIFY(size == write->image_data(0).size()); \r
}\r
else\r
{\r
}\r
\r
sws_scale(sws_context.get(), decoded_frame->data, decoded_frame->linesize, 0, height, av_frame->data, av_frame->linesize); \r
- pool.push(sws_context);\r
-\r
- write->commit(); \r
+ pool.push(sws_context); \r
}\r
else\r
{\r
for(int y = r.begin(); y != r.end(); ++y)\r
A_memcpy(result + y*plane.linesize, decoded + y*decoded_linesize, plane.linesize);\r
}, ap);\r
-\r
- write->commit(n);\r
}\r
}\r
\r
desc.planes.push_back(core::pixel_format_desc::plane(width_, height_, 4));\r
auto frame = frame_factory_->create_frame(this, desc);\r
\r
- A_memcpy(frame->image_data().begin(), bmp_.data(), width_*height_*4);\r
- frame->commit();\r
+ A_memcpy(frame->image_data(0).begin(), bmp_.data(), width_*height_*4);\r
head_ = frame;\r
} \r
\r
desc.planes.push_back(core::pixel_format_desc::plane(FreeImage_GetWidth(bitmap.get()), FreeImage_GetHeight(bitmap.get()), 4));\r
auto frame = frame_factory->create_frame(this, desc);\r
\r
- std::copy_n(FreeImage_GetBits(bitmap.get()), frame->image_data().size(), frame->image_data().begin());\r
- frame->commit();\r
+ std::copy_n(FreeImage_GetBits(bitmap.get()), frame->image_data(0).size(), frame->image_data(0).begin());\r
frame_ = std::move(frame);\r
}\r
\r
desc.planes.push_back(core::pixel_format_desc::plane(width_, format_desc_.height, 4));\r
auto frame = frame_factory->create_frame(reinterpret_cast<void*>(rand()), desc);\r
\r
- if(count >= frame->image_data().size())\r
+ if(count >= frame->image_data(0).size())\r
{ \r
- std::copy_n(bytes + count - frame->image_data().size(), frame->image_data().size(), frame->image_data().begin());\r
- count -= static_cast<int>(frame->image_data().size());\r
+ std::copy_n(bytes + count - frame->image_data(0).size(), frame->image_data(0).size(), frame->image_data(0).begin());\r
+ count -= static_cast<int>(frame->image_data(0).size());\r
}\r
else\r
{\r
- memset(frame->image_data().begin(), 0, frame->image_data().size()); \r
- std::copy_n(bytes, count, frame->image_data().begin() + format_desc_.size - count);\r
+ memset(frame->image_data(0).begin(), 0, frame->image_data(0).size()); \r
+ std::copy_n(bytes, count, frame->image_data(0).begin() + format_desc_.size - count);\r
count = 0;\r
}\r
\r
- frame->commit();\r
frames_.push_back(frame);\r
}\r
\r
core::pixel_format_desc desc = core::pixel_format::bgra;\r
desc.planes.push_back(core::pixel_format_desc::plane(format_desc_.width, height_, 4));\r
auto frame = frame_factory->create_frame(reinterpret_cast<void*>(rand()), desc);\r
- if(count >= frame->image_data().size())\r
+ if(count >= frame->image_data(0).size())\r
{ \r
for(int y = 0; y < height_; ++y)\r
- std::copy_n(bytes + i * format_desc_.width*4 + y * width_*4, format_desc_.width*4, frame->image_data().begin() + y * format_desc_.width*4);\r
+ std::copy_n(bytes + i * format_desc_.width*4 + y * width_*4, format_desc_.width*4, frame->image_data(0).begin() + y * format_desc_.width*4);\r
\r
++i;\r
- count -= static_cast<int>(frame->image_data().size());\r
+ count -= static_cast<int>(frame->image_data(0).size());\r
}\r
else\r
{\r
- memset(frame->image_data().begin(), 0, frame->image_data().size()); \r
+ memset(frame->image_data(0).begin(), 0, frame->image_data(0).size()); \r
int width2 = width_ % format_desc_.width;\r
for(int y = 0; y < height_; ++y)\r
- std::copy_n(bytes + i * format_desc_.width*4 + y * width_*4, width2*4, frame->image_data().begin() + y * format_desc_.width*4);\r
+ std::copy_n(bytes + i * format_desc_.width*4 + y * width_*4, width2*4, frame->image_data(0).begin() + y * format_desc_.width*4);\r
\r
count = 0;\r
}\r
\r
- frame->commit();\r
frames_.push_back(frame);\r
}\r
\r
\r
auto frame = frame_factory_->create_frame(this, read_frame->get_pixel_format_desc());\r
\r
- A_memcpy(frame->image_data().begin(), read_frame->image_data().begin(), read_frame->image_data().size());\r
- frame->commit();\r
+ A_memcpy(frame->image_data(0).begin(), read_frame->image_data().begin(), read_frame->image_data().size());\r
boost::push_back(frame->audio_data(), read_frame->audio_data());\r
\r
frame_buffer_.push(frame); \r
<configuration>\r
<paths>\r
<media-path>D:\casparcg\_media\</media-path>\r
- <log-path>D:\casparcgr\_log\</log-path>\r
+ <log-path>D:\casparcg\_log\</log-path>\r
<data-path>D:\casparcg\_data\</data-path>\r
- <template-path>C:\CasparCG\_templates\</template-path>\r
+ <template-path>D:\casparcg\_templates\</template-path>\r
</paths>\r
<blend-modes>true</blend-modes>\r
<log-level>trace</log-level>\r