g_destroyer.destroy(std::move(producer_));\r
}\r
\r
-safe_ptr<basic_frame> destroy_producer_proxy::receive(){return producer_->receive();} \r
+safe_ptr<basic_frame> destroy_producer_proxy::receive(){return core::receive(producer_);} \r
std::wstring destroy_producer_proxy::print() const {return producer_->print();} \r
\r
void destroy_producer_proxy::param(const std::wstring& param){producer_->param(param);} \r
\r
#include <boost/range/iterator_range.hpp>\r
\r
+#include <vector>\r
+\r
namespace caspar { namespace core {\r
\r
class image_transform;\r
return producer;\r
} \r
\r
+safe_ptr<basic_frame> frame_producer::receive_w_last()\r
+{\r
+ auto frame = receive();\r
+ if(frame != core::basic_frame::late())\r
+ {\r
+ last_frame_ = make_safe<basic_frame>(frame);\r
+ last_frame_->get_audio_transform().set_has_audio(false);\r
+ } \r
+ return frame;\r
+}\r
+\r
+safe_ptr<basic_frame> receive(safe_ptr<frame_producer>& producer)\r
+{\r
+ return producer->receive_w_last();\r
+}\r
+\r
safe_ptr<basic_frame> receive_and_follow(safe_ptr<frame_producer>& producer)\r
{ \r
if(producer == frame_producer::empty())\r
auto frame = basic_frame::eof();\r
try\r
{\r
- frame = producer->receive();\r
+ frame = receive(producer);\r
}\r
catch(...)\r
{\r
return frame;\r
}\r
\r
+safe_ptr<basic_frame> receive_and_follow_w_last(safe_ptr<frame_producer>& producer)\r
+{\r
+ auto frame = receive_and_follow(producer);\r
+ if(frame == basic_frame::late())\r
+ frame = producer->last_frame();\r
+ return frame;\r
+}\r
+\r
void register_producer_factory(const producer_factory_t& factory)\r
{\r
g_factories.push_back(factory);\r
*/\r
#pragma once\r
\r
+#include "frame/basic_frame.h"\r
+#include "frame/audio_transform.h"\r
+\r
#include <common/memory/safe_ptr.h>\r
\r
#include "frame/frame_factory.h"\r
class frame_producer : boost::noncopyable\r
{\r
public:\r
+ frame_producer() : last_frame_(core::basic_frame::empty()){}\r
virtual ~frame_producer(){} \r
\r
- virtual safe_ptr<basic_frame> receive() = 0;\r
virtual std::wstring print() const = 0; // nothrow\r
\r
virtual void param(const std::wstring&){}\r
virtual void set_leading_producer(const safe_ptr<frame_producer>&) {} // nothrow\r
\r
static const safe_ptr<frame_producer>& empty(); // nothrow\r
+\r
+ safe_ptr<core::basic_frame> last_frame() const {return last_frame_;}\r
+ \r
+private:\r
+ virtual safe_ptr<basic_frame> receive() = 0;\r
+ friend safe_ptr<basic_frame> receive(safe_ptr<frame_producer>& producer);\r
+\r
+ safe_ptr<basic_frame> receive_w_last();\r
+\r
+ safe_ptr<core::basic_frame> last_frame_;\r
};\r
\r
+safe_ptr<basic_frame> receive(safe_ptr<frame_producer>& producer);\r
safe_ptr<basic_frame> receive_and_follow(safe_ptr<frame_producer>& producer);\r
+safe_ptr<basic_frame> receive_and_follow_w_last(safe_ptr<frame_producer>& producer);\r
\r
typedef std::function<safe_ptr<core::frame_producer>(const safe_ptr<frame_factory>&, const std::vector<std::wstring>&)> producer_factory_t;\r
void register_producer_factory(const producer_factory_t& factory); // Not thread-safe.\r
{ \r
safe_ptr<frame_producer> foreground_;\r
safe_ptr<frame_producer> background_;\r
- safe_ptr<basic_frame> last_frame_;\r
bool is_paused_;\r
public:\r
implementation() \r
: foreground_(frame_producer::empty())\r
, background_(frame_producer::empty())\r
- , last_frame_(basic_frame::empty())\r
, is_paused_(false){}\r
\r
void pause(){is_paused_ = true;}\r
void stop()\r
{\r
pause();\r
- last_frame_ = basic_frame::empty();\r
foreground_ = frame_producer::empty();\r
}\r
\r
safe_ptr<basic_frame> receive()\r
{ \r
if(is_paused_)\r
- return last_frame_;\r
-\r
- auto next_frame = receive_and_follow(foreground_);\r
- if(next_frame == core::basic_frame::late())\r
- return last_frame_;\r
- \r
- last_frame_ = basic_frame(next_frame);\r
- last_frame_->get_audio_transform().set_has_audio(false);\r
-\r
- return next_frame;\r
+ return foreground_->last_frame();\r
+ \r
+ return receive_and_follow_w_last(foreground_);\r
}\r
};\r
\r
explicit separated_producer(const safe_ptr<frame_producer>& fill, const safe_ptr<frame_producer>& key) \r
: fill_producer_(fill)\r
, key_producer_(key)\r
- , fill_(core::basic_frame::empty())\r
- , key_(core::basic_frame::empty()){}\r
+ , fill_(core::basic_frame::late())\r
+ , key_(core::basic_frame::late()){}\r
\r
// frame_producer\r
\r
(\r
[&]\r
{\r
- if(fill_ == core::basic_frame::empty())\r
+ if(fill_ == core::basic_frame::late())\r
fill_ = receive_and_follow(fill_producer_);\r
},\r
[&]\r
{\r
- if(key_ == core::basic_frame::empty())\r
+ if(key_ == core::basic_frame::late())\r
key_ = receive_and_follow(key_producer_);\r
}\r
);\r
\r
auto frame = basic_frame::fill_and_key(fill_, key_);\r
\r
- fill_ = basic_frame::empty();\r
- key_ = basic_frame::empty();\r
+ fill_ = basic_frame::late();\r
+ key_ = basic_frame::late();\r
\r
return frame;\r
}\r
\r
safe_ptr<frame_producer> dest_producer_;\r
safe_ptr<frame_producer> source_producer_;\r
- safe_ptr<basic_frame> last_dest_;\r
- safe_ptr<basic_frame> last_source_;\r
\r
explicit transition_producer(const video_mode::type& mode, const safe_ptr<frame_producer>& dest, const transition_info& info) \r
: mode_(mode)\r
, current_frame_(0)\r
, info_(info)\r
, dest_producer_(dest)\r
- , source_producer_(frame_producer::empty())\r
- , last_dest_(core::basic_frame::empty())\r
- , last_source_(core::basic_frame::empty()){}\r
+ , source_producer_(frame_producer::empty()){}\r
\r
// frame_producer\r
\r
if(current_frame_++ >= info_.duration)\r
return basic_frame::eof();\r
\r
+ safe_ptr<core::basic_frame> dest;\r
+ safe_ptr<core::basic_frame> source;\r
+\r
tbb::parallel_invoke\r
(\r
- [&]{last_dest_ = receive_and_follow_w_last(dest_producer_, last_dest_);},\r
- [&]{last_source_ = receive_and_follow_w_last(source_producer_, last_source_);}\r
+ [&]{dest = receive_and_follow_w_last(dest_producer_);},\r
+ [&]{source = receive_and_follow_w_last(source_producer_);}\r
);\r
\r
- return compose(last_dest_, last_source_);\r
+ return compose(dest, source);\r
}\r
\r
virtual std::wstring print() const\r
{\r
return L"transition";\r
}\r
-\r
- safe_ptr<basic_frame> receive_and_follow_w_last(safe_ptr<frame_producer>& producer, safe_ptr<basic_frame> last_frame)\r
- {\r
- auto frame = core::receive_and_follow(producer);\r
- if(frame == basic_frame::late())\r
- {\r
- last_frame->get_audio_transform().set_has_audio(false);\r
- frame = last_frame;\r
- }\r
- return frame;\r
- }\r
-\r
+ \r
// transition_producer\r
\r
safe_ptr<basic_frame> compose(const safe_ptr<basic_frame>& dest_frame, const safe_ptr<basic_frame>& src_frame) \r
{ \r
if(!audio_packet)\r
return;\r
+ \r
+ if(audio_packet->size == 0)\r
+ {\r
+ avcodec_flush_buffers(&codec_context_);\r
+ return;\r
+ }\r
\r
auto s = current_chunk_.size();\r
current_chunk_.resize(s + 4*format_desc_.audio_sample_rate*2+FF_INPUT_BUFFER_PADDING_SIZE/2);\r
buffer_.push(pkt); \r
}\r
\r
+ void flush()\r
+ {\r
+ if(index_ == -1)\r
+ return;\r
+\r
+ std::shared_ptr<AVPacket> flsh_pkt(new AVPacket);\r
+ flsh_pkt->size = 0;\r
+ buffer_.push(flsh_pkt); \r
+ }\r
+\r
const std::shared_ptr<AVCodecContext>& ctx() { return ctx_; }\r
\r
operator bool(){return ctx_ != nullptr;}\r
boost::errinfo_api_function("av_seek_frame") <<\r
boost::errinfo_errno(AVUNERROR(errn)));\r
}\r
+\r
+ video_stream_.flush();\r
+ audio_stream_.flush();\r
} \r
\r
bool is_eof(int errn)\r
{ \r
if(!video_packet)\r
return;\r
+\r
+ if(video_packet->size == 0)\r
+ {\r
+ avcodec_flush_buffers(&codec_context_);\r
+ return;\r
+ }\r
\r
safe_ptr<AVFrame> decoded_frame(avcodec_alloc_frame(), av_free);\r
\r
\r
safe_ptr<core::basic_frame> receive()\r
{\r
- return flash_producer_->receive();\r
+ return core::receive(flash_producer_);\r
}\r
\r
std::wstring print() const\r