X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=core%2Fframe%2Fframe.cpp;h=f2c5fa01a4b0108794895f0a02ec7de1ebae1ed4;hb=f09adb004af5d444dd8e5f1a13e12ad4641a595d;hp=31f7cba963269d7f58ea8ff3bbdd3def0b630e8e;hpb=e7ffa545a261c031601bb3e9ef2c0a6c6e1a0f48;p=casparcg diff --git a/core/frame/frame.cpp b/core/frame/frame.cpp index 31f7cba96..f2c5fa01a 100644 --- a/core/frame/frame.cpp +++ b/core/frame/frame.cpp @@ -1,192 +1,268 @@ -/* -* Copyright (c) 2011 Sveriges Television AB -* -* This file is part of CasparCG (www.casparcg.com). -* -* CasparCG is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* CasparCG is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with CasparCG. If not, see . -* -* Author: Robert Nagy, ronag89@gmail.com -*/ - -#include "../stdafx.h" - -#include "frame.h" - -#include -#include - -#include -#include - -#include -#include - -namespace caspar { namespace core { - -struct mutable_frame::impl : boost::noncopyable -{ - std::vector> buffers_; - core::audio_buffer audio_data_; - const core::pixel_format_desc desc_; - const void* tag_; - double frame_rate_; - core::field_mode field_mode_; - - impl(std::vector> buffers, audio_buffer audio_buffer, const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode) - : buffers_(std::move(buffers)) - , audio_data_(std::move(audio_buffer)) - , desc_(desc) - , tag_(tag) - , frame_rate_(frame_rate) - , field_mode_(field_mode) - { - BOOST_FOREACH(auto& buffer, buffers_) - if(!buffer.data()) - BOOST_THROW_EXCEPTION(invalid_argument() << msg_info("mutable_frame: null argument")); - } -}; - -mutable_frame::mutable_frame(std::vector> image_buffers, audio_buffer audio_buffer, const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode) - : impl_(new impl(std::move(image_buffers), std::move(audio_buffer), tag, desc, frame_rate, field_mode)){} -mutable_frame::~mutable_frame(){} -mutable_frame::mutable_frame(mutable_frame&& other) : impl_(std::move(other.impl_)){} -mutable_frame& mutable_frame::operator=(mutable_frame&& other) -{ - impl_ = std::move(other.impl_); - return *this; -} -void mutable_frame::swap(mutable_frame& other){impl_.swap(other.impl_);} -const core::pixel_format_desc& mutable_frame::pixel_format_desc() const{return impl_->desc_;} -const array& mutable_frame::image_data(std::size_t index) const{return impl_->buffers_.at(index);} -const core::audio_buffer& mutable_frame::audio_data() const{return impl_->audio_data_;} -array& mutable_frame::image_data(std::size_t index){return impl_->buffers_.at(index);} -core::audio_buffer& mutable_frame::audio_data(){return impl_->audio_data_;} -double mutable_frame::frame_rate() const{return impl_->frame_rate_;} -core::field_mode mutable_frame::field_mode() const{return impl_->field_mode_;} -std::size_t mutable_frame::width() const{return impl_->desc_.planes.at(0).width;} -std::size_t mutable_frame::height() const{return impl_->desc_.planes.at(0).height;} -const void* mutable_frame::tag() const{return impl_->tag_;} - - -const const_frame& const_frame::empty() -{ - static int dummy; - static const_frame empty(&dummy); - return empty; -} - -struct const_frame::impl : boost::noncopyable -{ - mutable std::vector>> future_buffers_; - int id_; - core::audio_buffer audio_data_; - const core::pixel_format_desc desc_; - const void* tag_; - double frame_rate_; - core::field_mode field_mode_; - - impl(const void* tag) - : desc_(core::pixel_format::invalid) - , tag_(tag) - , id_(0) - , field_mode_(core::field_mode::empty) - { - } - - impl(boost::shared_future> image, audio_buffer audio_buffer, const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode) - : audio_data_(std::move(audio_buffer)) - , desc_(desc) - , tag_(tag) - , id_(reinterpret_cast(this)) - , frame_rate_(frame_rate) - , field_mode_(field_mode) - { - if(desc.format != core::pixel_format::bgra) - BOOST_THROW_EXCEPTION(not_implemented()); - - future_buffers_.push_back(std::move(image)); - } - - impl(mutable_frame&& other) - : audio_data_(other.audio_data()) - , desc_(other.pixel_format_desc()) - , tag_(other.tag()) - , id_(reinterpret_cast(this)) - , frame_rate_(other.frame_rate()) - , field_mode_(other.field_mode()) - { - for(std::size_t n = 0; n < desc_.planes.size(); ++n) - { - boost::promise> p; - p.set_value(std::move(other.image_data(n))); - future_buffers_.push_back(p.get_future()); - } - } - - array image_data(int index) const - { - return tag_ != empty().tag() ? future_buffers_.at(index).get() : array(nullptr, 0, true, 0); - } - - std::size_t width() const - { - return tag_ != empty().tag() ? desc_.planes.at(0).width : 0; - } - - std::size_t height() const - { - return tag_ != empty().tag() ? desc_.planes.at(0).height : 0; - } - - std::size_t size() const - { - return tag_ != empty().tag() ? desc_.planes.at(0).size : 0; - } - - bool operator==(const impl& other) - { - return tag_ == other.tag_ && id_ == other.id_; - } -}; - -const_frame::const_frame(const void* tag) : impl_(new impl(tag)){} -const_frame::const_frame(boost::shared_future> image, audio_buffer audio_buffer, const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode) - : impl_(new impl(std::move(image), std::move(audio_buffer), tag, desc, frame_rate, field_mode)){} -const_frame::const_frame(mutable_frame&& other) : impl_(new impl(std::move(other))){} -const_frame::~const_frame(){} -const_frame::const_frame(const_frame&& other) : impl_(std::move(other.impl_)){} -const_frame& const_frame::operator=(const_frame&& other) -{ - impl_ = std::move(other.impl_); - return *this; -} -const_frame::const_frame(const const_frame& other) : impl_(other.impl_){} -const_frame& const_frame::operator=(const const_frame& other) -{ - impl_ = other.impl_; - return *this; -} -bool const_frame::operator==(const const_frame& other){return *impl_ == *other.impl_;} -bool const_frame::operator!=(const const_frame& other){return !(*this == other);} -const core::pixel_format_desc& const_frame::pixel_format_desc()const{return impl_->desc_;} -array const_frame::image_data(int index)const{return impl_->image_data(index);} -const core::audio_buffer& const_frame::audio_data()const{return impl_->audio_data_;} -double const_frame::frame_rate()const{return impl_->frame_rate_;} -core::field_mode const_frame::field_mode()const{return impl_->field_mode_;} -std::size_t const_frame::width()const{return impl_->width();} -std::size_t const_frame::height()const{return impl_->height();} -std::size_t const_frame::size()const{return impl_->size();} -const void* const_frame::tag()const{return impl_->tag_;} - -}} \ No newline at end of file +/* +* Copyright (c) 2011 Sveriges Television AB +* +* This file is part of CasparCG (www.casparcg.com). +* +* CasparCG is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* CasparCG is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with CasparCG. If not, see . +* +* Author: Robert Nagy, ronag89@gmail.com +*/ + +#include "../StdAfx.h" + +#include "frame.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace caspar { namespace core { + +struct mutable_frame::impl : boost::noncopyable +{ + std::vector> buffers_; + core::mutable_audio_buffer audio_data_; + const core::pixel_format_desc desc_; + const core::audio_channel_layout channel_layout_; + const void* tag_; + core::frame_geometry geometry_ = frame_geometry::get_default(); + caspar::timer since_created_timer_; + + impl( + std::vector> buffers, + mutable_audio_buffer audio_data, + const void* tag, + const core::pixel_format_desc& desc, + const core::audio_channel_layout& channel_layout) + : buffers_(std::move(buffers)) + , audio_data_(std::move(audio_data)) + , desc_(desc) + , channel_layout_(channel_layout) + , tag_(tag) + { + for (auto& buffer : buffers_) + if(!buffer.data()) + CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("mutable_frame: null argument")); + } +}; + +mutable_frame::mutable_frame( + std::vector> image_buffers, + mutable_audio_buffer audio_data, + const void* tag, + const core::pixel_format_desc& desc, + const core::audio_channel_layout& channel_layout) + : impl_(new impl(std::move(image_buffers), std::move(audio_data), tag, desc, channel_layout)){} +mutable_frame::~mutable_frame(){} +mutable_frame::mutable_frame(mutable_frame&& other) : impl_(std::move(other.impl_)){} +mutable_frame& mutable_frame::operator=(mutable_frame&& other) +{ + impl_ = std::move(other.impl_); + return *this; +} +void mutable_frame::swap(mutable_frame& other){impl_.swap(other.impl_);} +const core::pixel_format_desc& mutable_frame::pixel_format_desc() const{return impl_->desc_;} +const core::audio_channel_layout& mutable_frame::audio_channel_layout() const { return impl_->channel_layout_; } +const array& mutable_frame::image_data(std::size_t index) const{return impl_->buffers_.at(index);} +const core::mutable_audio_buffer& mutable_frame::audio_data() const{return impl_->audio_data_;} +array& mutable_frame::image_data(std::size_t index){return impl_->buffers_.at(index);} +core::mutable_audio_buffer& mutable_frame::audio_data(){return impl_->audio_data_;} +std::size_t mutable_frame::width() const{return impl_->desc_.planes.at(0).width;} +std::size_t mutable_frame::height() const{return impl_->desc_.planes.at(0).height;} +const void* mutable_frame::stream_tag()const{return impl_->tag_;} +const frame_geometry& mutable_frame::geometry() const { return impl_->geometry_; } +void mutable_frame::set_geometry(const frame_geometry& g) { impl_->geometry_ = g; } +caspar::timer mutable_frame::since_created() const { return impl_->since_created_timer_; } + +const const_frame& const_frame::empty() +{ + static int dummy; + static const_frame empty(&dummy); + return empty; +} + +struct const_frame::impl : boost::noncopyable +{ + mutable std::vector>> future_buffers_; + mutable core::audio_buffer audio_data_; + const core::pixel_format_desc desc_; + const core::audio_channel_layout channel_layout_; + const void* tag_; + core::frame_geometry geometry_; + caspar::timer since_created_timer_; + bool should_record_age_; + mutable tbb::atomic recorded_age_; + std::shared_future> key_only_on_demand_; + + impl(const void* tag) + : audio_data_(0, 0, true, 0) + , desc_(core::pixel_format::invalid) + , channel_layout_(audio_channel_layout::invalid()) + , tag_(tag) + , geometry_(frame_geometry::get_default()) + , should_record_age_(true) + { + recorded_age_ = 0; + } + + impl( + std::shared_future> image, + audio_buffer audio_data, + const void* tag, + const core::pixel_format_desc& desc, + const core::audio_channel_layout& channel_layout, + caspar::timer since_created_timer = caspar::timer()) + : audio_data_(std::move(audio_data)) + , desc_(desc) + , channel_layout_(channel_layout) + , tag_(tag) + , geometry_(frame_geometry::get_default()) + , since_created_timer_(std::move(since_created_timer)) + , should_record_age_(false) + { + if (desc.format != core::pixel_format::bgra) + CASPAR_THROW_EXCEPTION(not_implemented()); + + future_buffers_.push_back(image); + + key_only_on_demand_ = std::async(std::launch::deferred, [image] + { + auto fill = image.get(); + auto key = cache_aligned_vector(fill.size()); + + aligned_memshfl(key.data(), fill.data(), fill.size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303); + + return array(key.data(), key.size(), false, std::move(key)); + }).share(); + } + + impl(mutable_frame&& other) + : audio_data_(0, 0, true, 0) // Complex init done in body instead. + , desc_(other.pixel_format_desc()) + , channel_layout_(other.audio_channel_layout()) + , tag_(other.stream_tag()) + , geometry_(other.geometry()) + , since_created_timer_(other.since_created()) + , should_record_age_(true) + { + spl::shared_ptr shared_audio_data(new mutable_audio_buffer(std::move(other.audio_data()))); + // pointer returned by vector::data() should be the same after move, but just to be safe. + audio_data_ = audio_buffer(shared_audio_data->data(), shared_audio_data->size(), true, std::move(shared_audio_data)); + + for (std::size_t n = 0; n < desc_.planes.size(); ++n) + { + future_buffers_.push_back(make_ready_future>(std::move(other.image_data(n))).share()); + } + + recorded_age_ = -1; + } + + array image_data(int index) const + { + return tag_ != empty().stream_tag() ? future_buffers_.at(index).get() : array(nullptr, 0, true, 0); + } + + spl::shared_ptr key_only() const + { + return spl::make_shared(key_only_on_demand_, audio_data_, tag_, desc_, channel_layout_, since_created_timer_); + } + + std::size_t width() const + { + return tag_ != empty().stream_tag() ? desc_.planes.at(0).width : 0; + } + + std::size_t height() const + { + return tag_ != empty().stream_tag() ? desc_.planes.at(0).height : 0; + } + + std::size_t size() const + { + return tag_ != empty().stream_tag() ? desc_.planes.at(0).size : 0; + } + + int64_t get_age_millis() const + { + if (should_record_age_) + { + if (recorded_age_ == -1) + recorded_age_ = static_cast(since_created_timer_.elapsed() * 1000.0); + + return recorded_age_; + } + else + return static_cast(since_created_timer_.elapsed() * 1000.0); + } +}; + +const_frame::const_frame(const void* tag) : impl_(new impl(tag)){} +const_frame::const_frame( + std::shared_future> image, + audio_buffer audio_data, + const void* tag, + const core::pixel_format_desc& desc, + const core::audio_channel_layout& channel_layout) + : impl_(new impl(std::move(image), std::move(audio_data), tag, desc, channel_layout)){} +const_frame::const_frame(mutable_frame&& other) : impl_(new impl(std::move(other))){} +const_frame::~const_frame(){} +const_frame::const_frame(const_frame&& other) : impl_(std::move(other.impl_)){} +const_frame& const_frame::operator=(const_frame&& other) +{ + impl_ = std::move(other.impl_); + return *this; +} +const_frame::const_frame(const const_frame& other) : impl_(other.impl_){} +const_frame& const_frame::operator=(const const_frame& other) +{ + impl_ = other.impl_; + return *this; +} +bool const_frame::operator==(const const_frame& other){return impl_ == other.impl_;} +bool const_frame::operator!=(const const_frame& other){return !(*this == other);} +bool const_frame::operator<(const const_frame& other){return impl_ < other.impl_;} +bool const_frame::operator>(const const_frame& other){return impl_ > other.impl_;} +const core::pixel_format_desc& const_frame::pixel_format_desc()const{return impl_->desc_;} +const core::audio_channel_layout& const_frame::audio_channel_layout()const { return impl_->channel_layout_; } +array const_frame::image_data(int index)const{return impl_->image_data(index);} +const core::audio_buffer& const_frame::audio_data()const{return impl_->audio_data_;} +std::size_t const_frame::width()const{return impl_->width();} +std::size_t const_frame::height()const{return impl_->height();} +std::size_t const_frame::size()const{return impl_->size();} +const void* const_frame::stream_tag()const{return impl_->tag_;} +const frame_geometry& const_frame::geometry() const { return impl_->geometry_; } +void const_frame::set_geometry(const frame_geometry& g) { impl_->geometry_ = g; } +int64_t const_frame::get_age_millis() const { return impl_->get_age_millis(); } +const_frame const_frame::key_only() const +{ + auto result = const_frame(); + result.impl_ = impl_->key_only(); + + return result; +} + +}}