paused_ = value;\r
}\r
\r
- draw_frame last_frame() const\r
+ draw_frame last_frame()\r
{\r
return draw_frame::still(last_frame_);\r
}\r
impl_->paused(value);\r
}\r
\r
-draw_frame frame_producer_base::last_frame() const\r
+draw_frame frame_producer_base::last_frame()\r
{\r
return impl_->last_frame();\r
}\r
std::wstring name() const override {return L"empty";}\r
uint32_t frame_number() const override {return 0;}\r
boost::unique_future<std::wstring> call(const std::wstring& params) override{CASPAR_THROW_EXCEPTION(not_supported());}\r
- draw_frame last_frame() const {return draw_frame::empty();}\r
+ draw_frame last_frame() {return draw_frame::empty();}\r
\r
boost::property_tree::wptree info() const override\r
{\r
boost::unique_future<std::wstring> call(const std::wstring& str) override {return producer_->call(str);}\r
void leading_producer(const spl::shared_ptr<frame_producer>& producer) override {return producer_->leading_producer(producer);}\r
uint32_t nb_frames() const override {return producer_->nb_frames();}\r
- class draw_frame last_frame() const {return producer_->last_frame();}\r
+ class draw_frame last_frame() {return producer_->last_frame();}\r
void subscribe(const monitor::observable::observer_ptr& o) {return producer_->subscribe(o);}\r
void unsubscribe(const monitor::observable::observer_ptr& o) {return producer_->unsubscribe(o);}\r
};\r
virtual boost::property_tree::wptree info() const = 0;\r
virtual uint32_t nb_frames() const = 0;\r
virtual uint32_t frame_number() const = 0;\r
- virtual class draw_frame last_frame() const = 0;\r
+ virtual class draw_frame last_frame() = 0;\r
virtual void leading_producer(const spl::shared_ptr<frame_producer>&) {} \r
};\r
\r
void paused(bool value) override; \r
uint32_t nb_frames() const override;\r
uint32_t frame_number() const override;\r
- virtual class draw_frame last_frame() const override;\r
+ virtual class draw_frame last_frame() override;\r
\r
private:\r
virtual class draw_frame receive() override;\r
if(preview)\r
{\r
play();\r
- foreground_->receive();\r
foreground_->paused(true);\r
}\r
\r
return frame;\r
}\r
\r
- draw_frame last_frame() const\r
+ draw_frame last_frame()\r
{\r
return draw_frame::mask(fill_producer_->last_frame(), key_producer_->last_frame());\r
}\r
return compose(dest, source);\r
}\r
\r
- draw_frame last_frame() const override\r
+ draw_frame last_frame() override\r
{\r
if(current_frame_ >= info_.duration)\r
return dest_producer_->last_frame();\r
, output_format_(format_desc, filename, options)\r
, executor_(print())\r
{\r
+ check_space();\r
+\r
// TODO: Ask stakeholders about case where file already exists.\r
boost::filesystem::remove(boost::filesystem::path(env::media_folder() + u16(filename))); // Delete the file if it exists\r
\r
return buffer;\r
}\r
\r
+ void check_space()\r
+ {\r
+ auto space = boost::filesystem::space(boost::filesystem::path(filename_).parent_path());\r
+ if(space.available < 512*1000000)\r
+ BOOST_THROW_EXCEPTION(file_write_error() << msg_info("out of space"));\r
+ }\r
+\r
void encode(const core::const_frame& frame)\r
{\r
try\r
{\r
if(frame_number_ % 25 == 0)\r
- {\r
- auto space = boost::filesystem::space(boost::filesystem::path(filename_).parent_path());\r
- if(space.available < 512*1000000)\r
- BOOST_THROW_EXCEPTION(file_write_error() << msg_info("out of space"));\r
- }\r
+ check_space();\r
\r
boost::timer frame_timer;\r
\r
tbb::atomic<uint32_t> frame_number_;\r
\r
core::draw_frame last_frame_;\r
+\r
+ boost::optional<uint32_t> seek_target_;\r
\r
public:\r
explicit ffmpeg_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, \r
auto frame = core::draw_frame::late(); \r
\r
boost::timer frame_timer;\r
+ \r
+ end_seek();\r
\r
if(paused_)\r
frame = last_frame(); \r
return frame;\r
}\r
\r
- core::draw_frame last_frame() const override\r
+ core::draw_frame last_frame() override\r
{\r
+ end_seek();\r
+\r
return core::draw_frame::still(last_frame_);\r
}\r
\r
\r
// ffmpeg_producer\r
\r
+ void end_seek()\r
+ {\r
+ for(int n = 0; n < 16 && (last_frame_ == core::draw_frame::empty() || (seek_target_ && file_frame_number() != *seek_target_)); ++n)\r
+ {\r
+ decode_next_frame();\r
+ if(!muxer_.empty())\r
+ {\r
+ last_frame_ = std::move(muxer_.front());\r
+ muxer_.pop();\r
+ seek_target_.reset();\r
+ }\r
+ }\r
+ }\r
+\r
void loop(bool value)\r
{\r
input_.loop(value);\r
}\r
\r
void seek(uint32_t target)\r
- {\r
- muxer_.clear();\r
- \r
- // TODO: Fix HACK.\r
- \r
- target = std::min(target, file_nb_frames());\r
- target = std::max<uint32_t>(target, 2) - 2;\r
+ { \r
+ seek_target_ = std::min(target, file_nb_frames());\r
\r
- input_.seek(target);\r
+ input_.seek(*seek_target_);\r
muxer_.clear();\r
- \r
- // BEGIN HACK: There is no way to flush yadif. Need to poll 2 frames.\r
- for(int n = 0; n < 25 && file_frame_number() != target+2; ++n)\r
- {\r
- decode_next_frame();\r
- if(!muxer_.empty())\r
- {\r
- last_frame_ = std::move(muxer_.front());\r
- muxer_.pop();\r
- }\r
- }\r
- // END HACK \r
}\r
\r
std::wstring print_mode() const\r
std::shared_ptr<AVPacket> packet;\r
while(packets_.try_pop(packet));\r
}\r
-\r
+ \r
size_type size() const\r
{\r
return index_ != -1 ? packets_.size() : std::numeric_limits<size_type>::max();\r
tbb::atomic<uint32_t> start_; \r
tbb::atomic<uint32_t> length_;\r
tbb::atomic<bool> loop_;\r
- tbb::atomic<bool> eof_;\r
double fps_;\r
uint32_t frame_number_;\r
\r
stream video_stream_;\r
stream audio_stream_;\r
\r
- tbb::atomic<uint32_t> seek_target_;\r
+ boost::optional<uint32_t> seek_target_;\r
\r
tbb::atomic<bool> is_running_;\r
boost::mutex mutex_;\r
start_ = start;\r
length_ = length;\r
loop_ = loop;\r
- eof_ = false;\r
- seek_target_ = start_ != 0 ? start_ : std::numeric_limits<uint32_t>::max();\r
is_running_ = true;\r
\r
- while(!full())\r
- tick();\r
- \r
+ if(start_ != 0)\r
+ seek_target_ = start_;\r
+ \r
graph_->set_color("seek", diagnostics::color(1.0f, 0.5f, 0.0f)); \r
graph_->set_color("audio-buffer", diagnostics::color(0.7f, 0.4f, 0.4f));\r
graph_->set_color("video-buffer", diagnostics::color(1.0f, 1.0f, 0.0f)); \r
seek_target_ = target;\r
video_stream_.clear();\r
audio_stream_.clear();\r
- eof_ = false;\r
}\r
-\r
- while(!full())\r
- tick();\r
-\r
+ \r
cond_.notify_one();\r
}\r
\r
\r
void tick()\r
{\r
- auto target = seek_target_.fetch_and_store(std::numeric_limits<uint32_t>::max());\r
- if(target != std::numeric_limits<uint32_t>::max()) \r
- internal_seek(target);\r
+ if(seek_target_) \r
+ {\r
+ internal_seek(*seek_target_);\r
+ seek_target_.reset();\r
+ }\r
\r
auto packet = create_packet();\r
\r
internal_seek(start_);\r
graph_->set_tag("seek"); \r
}\r
- else\r
- eof_ = true;\r
}\r
else\r
{ \r
{\r
boost::unique_lock<boost::mutex> lock(mutex_);\r
\r
- while((full() || eof_) && is_running_)\r
+ while(full() && !seek_target_ && is_running_)\r
cond_.wait(lock);\r
\r
tick();\r