\r
frame_muxer muxer_;\r
\r
+ int late_frames_;\r
const int start_;\r
- int64_t nb_frames_;\r
const bool loop_;\r
\r
safe_ptr<core::basic_frame> last_frame_;\r
, video_decoder_(input_.context(), frame_factory, filter)\r
, audio_decoder_(input_.context(), frame_factory->get_video_format_desc())\r
, muxer_(video_decoder_.fps(), frame_factory)\r
+ , late_frames_(0)\r
, start_(start)\r
- , nb_frames_(video_decoder_.nb_frames() - start)\r
, loop_(loop)\r
, last_frame_(core::basic_frame::empty())\r
{\r
else\r
{\r
graph_->add_tag("underflow"); \r
- ++nb_frames_; \r
+ ++late_frames_; \r
}\r
}\r
\r
\r
virtual int64_t nb_frames() const\r
{\r
- return loop_ ? 0 : nb_frames_;\r
+ auto nb_frames = input_.nb_frames() != 0 ? input_.nb_frames() : video_decoder_.nb_frames();\r
+ return loop_ ? 0 : (nb_frames + late_frames_ - start_);\r
}\r
\r
virtual std::wstring print() const\r
\r
boost::thread thread_;\r
tbb::atomic<bool> is_running_;\r
+ tbb::atomic<size_t> nb_frames_;\r
+ int64_t frame_number_;\r
+\r
+ int default_stream_index_;\r
public:\r
explicit implementation(const safe_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop, int start) \r
: graph_(graph)\r
, loop_(loop)\r
, filename_(filename)\r
, start_(std::max(start, 0))\r
+ , frame_number_(0)\r
{ \r
is_running_ = true;\r
+ nb_frames_ = 0;\r
\r
AVFormatContext* weak_format_context_ = nullptr;\r
THROW_ON_ERROR2(avformat_open_input(&weak_format_context_, narrow(filename).c_str(), nullptr, nullptr), print());\r
\r
THROW_ON_ERROR2(avformat_find_stream_info(format_context_.get(), nullptr), print());\r
\r
+ default_stream_index_ = THROW_ON_ERROR2(av_find_default_stream_index(format_context_.get()), print());\r
+\r
if(start_ != 0) \r
seek_frame(start_);\r
\r
return result;\r
}\r
\r
+ size_t nb_frames() const\r
+ {\r
+ return nb_frames_;\r
+ }\r
+\r
private:\r
\r
void run()\r
\r
if(is_eof(ret)) \r
{\r
+ if(nb_frames_ == 0)\r
+ nb_frames_ = static_cast<size_t>(frame_number_);\r
+\r
if(loop_)\r
{\r
seek_frame(start_, AVSEEK_FLAG_BACKWARD);\r
{ \r
THROW_ON_ERROR(ret, print(), "av_read_frame");\r
\r
+ if(read_packet->stream_index == default_stream_index_)\r
+ ++frame_number_;\r
+\r
THROW_ON_ERROR2(av_dup_packet(read_packet.get()), print());\r
\r
// Make sure that the packet is correctly deallocated even if size and data is modified during decoding.\r
}\r
\r
void seek_frame(int64_t frame, int flags = 0)\r
- { \r
- static const AVRational base_q = {1, AV_TIME_BASE};\r
-\r
- int stream_index = av_find_default_stream_index(format_context_.get());\r
- THROW_ON_ERROR(stream_index, print(), "av_find_default_stream_index");\r
- \r
- const int ret = av_seek_frame(format_context_.get(), stream_index, frame, flags);\r
- THROW_ON_ERROR(ret, print(), "av_seek_frame");\r
- \r
+ { \r
+ THROW_ON_ERROR2(av_seek_frame(format_context_.get(), default_stream_index_, frame, flags), print()); \r
buffer_.push(nullptr);\r
} \r
\r
bool input::eof() const {return !impl_->is_running_;}\r
bool input::try_pop(std::shared_ptr<AVPacket>& packet){return impl_->try_pop(packet);}\r
std::shared_ptr<AVFormatContext> input::context(){return impl_->format_context_;}\r
+size_t input::nb_frames() const {return impl_->nb_frames();}\r
}
\ No newline at end of file