// POLL\r
\r
auto frame = core::draw_frame::late();\r
- if(muxer_.try_pop(frame))\r
+ if(!muxer_.empty())\r
{\r
+ frame = std::move(muxer_.front());\r
+ muxer_.pop();\r
+\r
if(!frame_buffer_.try_push(frame))\r
{\r
auto dummy = core::draw_frame::empty();\r
std::queue<spl::shared_ptr<AVPacket>> packets_;\r
\r
const int64_t nb_frames_;\r
- tbb::atomic<uint32_t> file_frame_number_;\r
+ uint32_t file_frame_number_;\r
public:\r
explicit impl() \r
: nb_frames_(0)//context->streams[index_]->nb_frames)\r
+ , file_frame_number_(0)\r
{ \r
- file_frame_number_ = 0; \r
}\r
\r
explicit impl(const std::shared_ptr<AVFormatContext>& context, const core::video_format_desc& format_desc) \r
if(packet->data == nullptr)\r
{\r
packets_.pop();\r
- file_frame_number_ = static_cast<uint32_t>(packet->pos);\r
+ file_frame_number_ = static_cast<uint32_t>(packet->pts);\r
avcodec_flush_buffers(codec_context_.get());\r
return flush_audio();\r
}\r
<< monitor::event("file/audio/channels") % codec_context_->channels\r
<< monitor::event("file/audio/format") % u8(av_get_sample_fmt_name(codec_context_->sample_fmt))\r
<< monitor::event("file/audio/codec") % u8(codec_context_->codec->long_name);\r
-\r
- ++file_frame_number_;\r
-\r
+ \r
+ file_frame_number_ = static_cast<uint32_t>(pkt.pts);\r
+ \r
return std::make_shared<core::audio_buffer>(samples, samples + n_samples);\r
}\r
\r
return last_frame();\r
\r
boost::timer frame_timer;\r
- \r
- auto frame = core::draw_frame::late(); \r
+ \r
+ decode_next_frame();\r
\r
- if(!try_decode_frame(frame))\r
+ auto frame = core::draw_frame::late(); \r
+ if(!muxer_.empty())\r
+ {\r
+ frame = std::move(muxer_.front());\r
+ muxer_.pop();\r
+ }\r
+ else\r
{\r
if(!input_.eof()) \r
graph_->set_tag("underflow"); \r
video_decoder_.clear();\r
audio_decoder_.clear();\r
\r
+ target = std::min(target, file_nb_frames()-3);\r
+\r
input_.seek(target);\r
\r
- auto frame = core::draw_frame::late(); \r
+ decode_next_frame();\r
+\r
+ for(int n = 0; n < 50 && video_decoder_.file_frame_number() != target+2 && !muxer_.empty(); ++n) // TODO: +2 since a frame can be stuck inside yadif filter.\r
+ {\r
+ muxer_.pop();\r
+ decode_next_frame();\r
+ }\r
\r
- // TODO\r
- try_decode_frame(frame);\r
- try_decode_frame(frame);\r
- try_decode_frame(frame);\r
- try_decode_frame(frame);\r
- try_decode_frame(frame);\r
-\r
- if(frame != core::draw_frame::late())\r
- last_frame_ = frame;\r
+ last_frame_ = !muxer_.empty() ? muxer_.front() : last_frame_; \r
}\r
\r
std::wstring print_mode() const\r
return ffmpeg::print_mode(video_decoder_.width(), video_decoder_.height(), fps_, !video_decoder_.is_progressive());\r
}\r
\r
- bool try_decode_frame(core::draw_frame& result)\r
+ void decode_next_frame()\r
{\r
- for(int n = 0; n < 32; ++n)\r
+ for(int n = 0; n < 64 && muxer_.empty(); ++n)\r
{\r
- if(muxer_.try_pop(result)) \r
- return true; \r
-\r
std::shared_ptr<AVPacket> pkt;\r
for(int n = 0; n < 32 && (!video_decoder_.ready() || !audio_decoder_.ready()) && input_.try_pop(pkt); ++n)\r
{\r
muxer_.push(video);\r
muxer_.push(audio);\r
}\r
-\r
- return false;\r
}\r
};\r
\r
tbb::atomic<bool> loop_;\r
tbb::atomic<bool> eof_;\r
uint32_t frame_number_;\r
+ double fps_;\r
\r
tbb::concurrent_bounded_queue<std::shared_ptr<AVPacket>> buffer_;\r
tbb::atomic<size_t> buffer_size_;\r
, default_stream_index_(av_find_default_stream_index(format_context_.get()))\r
, filename_(filename)\r
, frame_number_(0)\r
+ , fps_(read_fps(*format_context_, 25))\r
, executor_(print())\r
{ \r
start_ = start;\r
auto codec = stream->codec;\r
auto fixed_target = (target*stream->time_base.den*codec->time_base.num)/(stream->time_base.num*codec->time_base.den)*codec->ticks_per_frame;\r
\r
- THROW_ON_ERROR2(avformat_seek_file(format_context_.get(), default_stream_index_, std::numeric_limits<int64_t>::min(), fixed_target, std::numeric_limits<int64_t>::max(), 0), print()); \r
+ THROW_ON_ERROR2(avformat_seek_file(format_context_.get(), default_stream_index_, std::numeric_limits<int64_t>::min(), fixed_target, fixed_target, 0), print()); \r
\r
auto flush_packet = create_packet();\r
flush_packet->data = nullptr;\r
flush_packet->size = 0;\r
- flush_packet->pos = target;\r
+ flush_packet->pts = target;\r
\r
buffer_.push(flush_packet);\r
\r
packet->data = data; \r
});\r
\r
+ auto time_base = format_context_->streams[packet->stream_index]->time_base;\r
+ packet->pts = static_cast<uint64_t>((static_cast<double>(packet->pts * time_base.num)/time_base.den)*fps_);\r
+\r
+ CASPAR_LOG(trace) << packet->pts;\r
+\r
buffer_.try_push(packet);\r
buffer_size_ += packet->size;\r
\r
void push(const std::shared_ptr<AVFrame>& video_frame)\r
{ \r
if(!video_frame)\r
+ {\r
+ merge();\r
return;\r
- \r
+ }\r
+\r
if(video_frame == flush_video()) \r
- video_streams_.push(std::queue<core::mutable_frame>()); \r
+ video_streams_.push(std::queue<core::mutable_frame>()); \r
else if(video_frame == empty_video())\r
{\r
auto empty_frame = frame_factory_->create_frame(this, core::pixel_format_desc(core::pixel_format::invalid));\r
\r
if(video_streams_.back().size() > 32)\r
BOOST_THROW_EXCEPTION(invalid_operation() << source_info("frame_muxer") << msg_info("video-stream overflow. This can be caused by incorrect frame-rate. Check clip meta-data."));\r
+ \r
+ merge();\r
}\r
\r
void push(const std::shared_ptr<core::audio_buffer>& audio)\r
{\r
- if(!audio) \r
+ if(!audio)\r
+ {\r
+ merge();\r
return;\r
+ }\r
\r
- if(audio == flush_audio()) \r
- audio_streams_.push(core::audio_buffer()); \r
+ if(audio == flush_audio()) \r
+ audio_streams_.push(core::audio_buffer()); \r
else if(audio == empty_audio()) \r
boost::range::push_back(audio_streams_.back(), core::audio_buffer(audio_cadence_.front(), 0)); \r
else \r
\r
if(audio_streams_.back().size() > static_cast<size_t>(32*audio_cadence_.front()))\r
BOOST_THROW_EXCEPTION(invalid_operation() << source_info("frame_muxer") << msg_info("audio-stream overflow. This can be caused by incorrect frame-rate. Check clip meta-data."));\r
+\r
+ merge();\r
}\r
\r
bool video_ready() const\r
return audio_streams_.front().size() >= static_cast<size_t>(audio_cadence_.front());\r
}\r
}\r
- \r
- bool try_pop(core::draw_frame& result)\r
+\r
+ bool empty() const\r
{\r
- if(!frame_buffer_.empty())\r
- {\r
- result = std::move(frame_buffer_.front());\r
- frame_buffer_.pop(); \r
- return true;\r
- }\r
+ return frame_buffer_.empty();\r
+ }\r
+\r
+ core::draw_frame front() const\r
+ {\r
+ return frame_buffer_.front();\r
+ }\r
\r
+ void pop()\r
+ {\r
+ frame_buffer_.pop();\r
+ }\r
+ \r
+ void merge()\r
+ {\r
if(video_streams_.size() > 1 && audio_streams_.size() > 1 && (!video_ready2() || !audio_ready2()))\r
{\r
if(!video_streams_.front().empty() || !audio_streams_.front().empty())\r
}\r
\r
if(!video_ready2() || !audio_ready2() || display_mode_ == display_mode::invalid)\r
- return false;\r
+ return;\r
\r
auto frame1 = pop_video();\r
frame1.audio_data() = pop_audio();\r
default:\r
BOOST_THROW_EXCEPTION(invalid_operation());\r
}\r
- \r
- return try_pop(result);\r
}\r
\r
core::mutable_frame pop_video()\r
: impl_(new impl(in_fps, frame_factory, format_desc, filter)){}\r
void frame_muxer::push(const std::shared_ptr<AVFrame>& video_frame){impl_->push(video_frame);}\r
void frame_muxer::push(const std::shared_ptr<core::audio_buffer>& audio_samples){return impl_->push(audio_samples);}\r
-bool frame_muxer::try_pop(core::draw_frame& result){return impl_->try_pop(result);}\r
+bool frame_muxer::empty() const{return impl_->empty();}\r
+core::draw_frame frame_muxer::front() const{return impl_->front();}\r
+void frame_muxer::pop(){return impl_->pop();}\r
void frame_muxer::clear(){impl_->clear();}\r
uint32_t frame_muxer::calc_nb_frames(uint32_t nb_frames) const {return impl_->calc_nb_frames(nb_frames);}\r
bool frame_muxer::video_ready() const{return impl_->video_ready();}\r
bool audio_ready() const;\r
\r
void clear();\r
- bool try_pop(core::draw_frame& result);\r
+\r
+ bool empty() const;\r
+ core::draw_frame front() const;\r
+ void pop();\r
\r
uint32_t calc_nb_frames(uint32_t nb_frames) const;\r
private:\r
const int height_;\r
bool is_progressive_;\r
\r
- tbb::atomic<uint32_t> file_frame_number_;\r
+ uint32_t file_frame_number_;\r
\r
public:\r
explicit impl() \r
, width_(0)\r
, height_(0)\r
, is_progressive_(true)\r
+ , file_frame_number_(0)\r
{\r
- file_frame_number_ = 0;\r
}\r
\r
explicit impl(const spl::shared_ptr<AVFormatContext>& context) \r
}\r
\r
packets_.pop();\r
- file_frame_number_ = static_cast<uint32_t>(packet->pos);\r
+ file_frame_number_ = static_cast<uint32_t>(packet->pts);\r
avcodec_flush_buffers(codec_context_.get());\r
+ \r
return flush_video(); \r
}\r
\r
<< monitor::event("file/video/height") % height_\r
<< monitor::event("file/video/field") % u8(!decoded_frame->interlaced_frame ? "progressive" : (decoded_frame->top_field_first ? "upper" : "lower"))\r
<< monitor::event("file/video/codec") % u8(codec_context_->codec->long_name);\r
+ \r
+ file_frame_number_ = static_cast<uint32_t>(pkt.pts);\r
\r
- ++file_frame_number_;\r
+ decoded_frame->pts = file_frame_number_;\r
\r
return decoded_frame;\r
}\r