]> git.sesse.net Git - casparcg/blobdiff - core/frame/frame.cpp
Fixed bug where non empty CALL responses where lost with an error.
[casparcg] / core / frame / frame.cpp
index d52658350c9cb6612229ab971fa4774fb0c28bc3..19a83d286e1671a9d4e4d8b9775debe3122e6a1c 100644 (file)
 * Author: Robert Nagy, ronag89@gmail.com
 */
 
-#include "../stdafx.h"
+#include "../StdAfx.h"
 
 #include "frame.h"
 
 #include <common/except.h>
 #include <common/array.h>
 #include <common/future.h>
+#include <common/timer.h>
 
 #include <core/frame/frame_visitor.h>
 #include <core/frame/pixel_format.h>
 #include <core/frame/geometry.h>
+#include <core/frame/audio_channel_layout.h>
+
+#include <cstdint>
+#include <vector>
 
 #include <boost/lexical_cast.hpp>
 #include <boost/thread/future.hpp>
@@ -39,15 +44,23 @@ namespace caspar { namespace core {
 struct mutable_frame::impl : boost::noncopyable
 {                      
        std::vector<array<std::uint8_t>>                        buffers_;
-       core::audio_buffer                                                      audio_data_;
+       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();
+       core::frame_geometry                                            geometry_                               = frame_geometry::get_default();
+       caspar::timer                                                           since_created_timer_;
        
-       impl(std::vector<array<std::uint8_t>> buffers, audio_buffer audio_buffer, const void* tag, const core::pixel_format_desc& desc) 
+       impl(
+                       std::vector<array<std::uint8_t>> 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_buffer))
+               , audio_data_(std::move(audio_data))
                , desc_(desc)
+               , channel_layout_(channel_layout)
                , tag_(tag)
        {
                for (auto& buffer : buffers_)
@@ -56,8 +69,13 @@ struct mutable_frame::impl : boost::noncopyable
        }
 };
        
-mutable_frame::mutable_frame(std::vector<array<std::uint8_t>> image_buffers, audio_buffer audio_buffer, const void* tag, const core::pixel_format_desc& desc) 
-       : impl_(new impl(std::move(image_buffers), std::move(audio_buffer), tag, desc)){}
+mutable_frame::mutable_frame(
+               std::vector<array<std::uint8_t>> 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)
@@ -67,16 +85,17 @@ mutable_frame& mutable_frame::operator=(mutable_frame&& other)
 }
 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<std::uint8_t>& 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_;}
+const core::mutable_audio_buffer& mutable_frame::audio_data() const{return impl_->audio_data_;}
 array<std::uint8_t>& mutable_frame::image_data(std::size_t index){return impl_->buffers_.at(index);}
-core::audio_buffer& mutable_frame::audio_data(){return impl_->audio_data_;}
+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 void* mutable_frame::data_tag()const{return impl_.get();}        
 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()
 {
@@ -88,44 +107,64 @@ const const_frame& const_frame::empty()
 struct const_frame::impl : boost::noncopyable
 {                      
        mutable std::vector<std::shared_future<array<const std::uint8_t>>>      future_buffers_;
-       int                                                                                     id_;
-       core::audio_buffer                                                      audio_data_;
-       const core::pixel_format_desc                           desc_;
-       const void*                                                                     tag_;
-       core::frame_geometry                                            geometry_;
+       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<int64_t>                                                                            recorded_age_;
 
        impl(const void* tag)
-               : desc_(core::pixel_format::invalid)
+               : audio_data_(0, 0, true, 0)
+               , desc_(core::pixel_format::invalid)
+               , channel_layout_(audio_channel_layout::invalid())
                , tag_(tag)     
-               , id_(0)
                , geometry_(frame_geometry::get_default())
+               , should_record_age_(true)
        {
+               recorded_age_ = 0;
        }
        
-       impl(std::shared_future<array<const std::uint8_t>> image, audio_buffer audio_buffer, const void* tag, const core::pixel_format_desc& desc) 
-               : audio_data_(std::move(audio_buffer))
+       impl(
+                       std::shared_future<array<const std::uint8_t>> image,
+                       audio_buffer audio_data,
+                       const void* tag,
+                       const core::pixel_format_desc& desc,
+                       const core::audio_channel_layout& channel_layout)
+               : audio_data_(std::move(audio_data))
                , desc_(desc)
+               , channel_layout_(channel_layout)
                , tag_(tag)
-               , id_(reinterpret_cast<int>(this))
                , geometry_(frame_geometry::get_default())
+               , should_record_age_(false)
        {
-               if(desc.format != core::pixel_format::bgra)
+               if (desc.format != core::pixel_format::bgra)
                        CASPAR_THROW_EXCEPTION(not_implemented());
                
                future_buffers_.push_back(std::move(image));
        }
 
        impl(mutable_frame&& other)
-               : audio_data_(other.audio_data())
+               : 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())
-               , id_(reinterpret_cast<int>(this))
                , geometry_(other.geometry())
+               , since_created_timer_(other.since_created())
+               , should_record_age_(true)
        {
-               for(std::size_t n = 0; n < desc_.planes.size(); ++n)
+               spl::shared_ptr<mutable_audio_buffer> 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<array<const std::uint8_t>>(std::move(other.image_data(n))).share());
                }
+
+               recorded_age_ = -1;
        }
 
        array<const std::uint8_t> image_data(int index) const
@@ -147,11 +186,29 @@ struct const_frame::impl : boost::noncopyable
        {
                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<int64_t>(since_created_timer_.elapsed() * 1000.0);
+
+                       return recorded_age_;
+               }
+               else
+                       return static_cast<int64_t>(since_created_timer_.elapsed() * 1000.0);
+       }
 };
        
 const_frame::const_frame(const void* tag) : impl_(new impl(tag)){}
-const_frame::const_frame(std::shared_future<array<const std::uint8_t>> image, audio_buffer audio_buffer, const void* tag, const core::pixel_format_desc& desc) 
-       : impl_(new impl(std::move(image), std::move(audio_buffer), tag, desc)){}
+const_frame::const_frame(
+               std::shared_future<array<const std::uint8_t>> 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_)){}
@@ -168,17 +225,18 @@ const_frame& const_frame::operator=(const const_frame& other)
 }
 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_;}
+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 std::uint8_t> 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 void* const_frame::data_tag()const{return impl_.get();}  
 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(); }
 
-}}
\ No newline at end of file
+}}