std::unique_ptr<audio_decoder> audio_decoder_; \r
std::unique_ptr<frame_muxer> muxer_;\r
\r
+ const double fps_;\r
const int start_;\r
const bool loop_;\r
const size_t length_;\r
, frame_factory_(frame_factory) \r
, format_desc_(frame_factory->get_video_format_desc())\r
, input_(graph_, filename_, loop, start, length)\r
+ , fps_(read_fps(*input_.context(), format_desc_.fps))\r
, start_(start)\r
, loop_(loop)\r
, length_(length)\r
if(!video_decoder_ && !audio_decoder_)\r
BOOST_THROW_EXCEPTION(averror_stream_not_found() << msg_info("No streams found"));\r
\r
- muxer_.reset(new frame_muxer(video_decoder_ ? video_decoder_->fps() : frame_factory->get_video_format_desc().fps, frame_factory, filter));\r
+ muxer_.reset(new frame_muxer(fps_, frame_factory, filter));\r
}\r
\r
// frame_producer\r
\r
virtual int64_t file_nb_frames() const override\r
{\r
- // This function estimates nb_frames until input has read all packets for one loop, at which point the count should be accurate.\r
-\r
- int64_t nb_frames = input_.nb_frames();\r
- if(input_.nb_loops() < 1) // input still hasn't counted all frames\r
- {\r
- auto video_nb_frames = video_decoder_ ? video_decoder_->nb_frames() : std::numeric_limits<int64_t>::max();\r
- //auto audio_nb_frames = audio_decoder_ ? audio_decoder_->nb_frames() : std::numeric_limits<int64_t>::max();\r
-\r
- nb_frames = std::max(nb_frames, video_nb_frames);\r
- }\r
- return nb_frames;\r
+ return video_decoder_ ? video_decoder_->nb_frames() : std::numeric_limits<int64_t>::max();\r
}\r
\r
virtual int64_t frame_number() const override\r
if(video_decoder_)\r
{\r
std::wostringstream fps_ss;\r
- fps_ss << std::fixed << std::setprecision(2) << (video_decoder_->is_progressive() ? video_decoder_->fps() : 2.0 * video_decoder_->fps());\r
+ fps_ss << std::fixed << std::setprecision(2) << (video_decoder_->is_progressive() ? fps_ : 2.0 * fps_);\r
\r
return L"ffmpeg[" + boost::filesystem::wpath(filename_).filename() + L"|" \r
+ boost::lexical_cast<std::wstring>(video_decoder_->width()) + L"x" + boost::lexical_cast<std::wstring>(video_decoder_->height())\r
\r
size_t file_frame_number = 0;\r
file_frame_number = std::max(file_frame_number, video_decoder_ ? video_decoder_->file_frame_number() : 0);\r
- file_frame_number = std::max(file_frame_number, audio_decoder_ ? audio_decoder_->file_frame_number() : 0);\r
+ //file_frame_number = std::max(file_frame_number, audio_decoder_ ? audio_decoder_->file_frame_number() : 0);\r
\r
for(auto frame = muxer_->poll(); frame; frame = muxer_->poll())\r
frame_buffer_.push(std::make_pair(make_safe_ptr(frame), file_frame_number));\r
boost::condition_variable buffer_cond_;\r
boost::mutex buffer_mutex_;\r
\r
- tbb::atomic<size_t> nb_frames_;\r
- tbb::atomic<size_t> nb_loops_;\r
-\r
boost::thread thread_;\r
tbb::atomic<bool> is_running_;\r
tbb::atomic<bool> is_eof_;\r
is_eof_ = false;\r
loop_ = loop;\r
buffer_size_ = 0;\r
- nb_frames_ = 0;\r
- nb_loops_ = 0;\r
-\r
- buffer_size_ = 0;\r
- nb_frames_ = 0;\r
- nb_loops_ = 0;\r
\r
if(start_ > 0) \r
do_seek(start_);\r
try\r
{\r
CASPAR_LOG(info) << print() << " Thread Started.";\r
- \r
- CASPAR_ASSERT(nb_frames_ < 1000);\r
\r
while(is_running_)\r
{\r
\r
if(is_eof(ret)) \r
{\r
- ++nb_loops_;\r
frame_number_ = 0;\r
is_eof_ = true;\r
\r
THROW_ON_ERROR(ret, "av_read_frame", print());\r
\r
if(packet->stream_index == default_stream_index_)\r
- {\r
- if(nb_loops_ == 0)\r
- ++nb_frames_;\r
++frame_number_;\r
- }\r
\r
THROW_ON_ERROR2(av_dup_packet(packet.get()), print());\r
\r
}\r
}\r
\r
- auto time_base = format_context_->streams[default_stream_index_]->time_base;\r
- auto fixed_target = (target*time_base.den)/time_base.num;\r
- auto fixed_time_base = fix_time_base(time_base);\r
- fixed_target = (fixed_target * fixed_time_base.num) / fixed_time_base.den;\r
- fixed_target = fixed_target * format_context_->streams[default_stream_index_]->codec->ticks_per_frame;\r
-\r
+ auto stream = format_context_->streams[default_stream_index_];\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);\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
\r
is_eof_ = false;\r
bool is_eof(int ret)\r
{\r
if(ret == AVERROR(EIO))\r
- CASPAR_LOG(trace) << print() << " Received EIO, assuming EOF. " << nb_frames_;\r
+ CASPAR_LOG(trace) << print() << " Received EIO, assuming EOF. ";\r
if(ret == AVERROR_EOF)\r
- CASPAR_LOG(debug) << print() << " Received EOF. " << nb_frames_;\r
+ CASPAR_LOG(debug) << print() << " Received EOF. ";\r
\r
return ret == AVERROR_EOF || ret == AVERROR(EIO) || frame_number_ >= length_; // av_read_frame doesn't always correctly return AVERROR_EOF;\r
}\r
bool input::eof() const {return impl_->is_eof_;}\r
bool input::try_pop(std::shared_ptr<AVPacket>& packet){return impl_->try_pop(packet);}\r
safe_ptr<AVFormatContext> input::context(){return impl_->format_context_;}\r
-size_t input::nb_frames() const {return impl_->nb_frames_;}\r
-size_t input::nb_loops() const {return impl_->nb_loops_;}\r
void input::loop(bool value){impl_->loop_ = value;}\r
bool input::loop() const{return impl_->loop_;}\r
void input::seek(int64_t target){impl_->seek(target);}\r
bool try_pop(std::shared_ptr<AVPacket>& packet);\r
bool eof() const;\r
\r
- size_t nb_frames() const;\r
- size_t nb_loops() const;\r
-\r
void loop(bool value);\r
bool loop() const;\r
\r
return time_base;\r
}\r
\r
-void fix_meta_data(AVFormatContext& context)\r
-{\r
+double read_fps(AVFormatContext& context, double fail_value)\r
+{ \r
auto video_index = av_find_best_stream(&context, AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0);\r
auto audio_index = av_find_best_stream(&context, AVMEDIA_TYPE_AUDIO, -1, -1, 0, 0);\r
-\r
+ \r
if(video_index > -1)\r
{\r
- auto video_context = context.streams[video_index]->codec;\r
- auto video_stream = context.streams[video_index];\r
+ const auto video_context = context.streams[video_index]->codec;\r
+ const auto video_stream = context.streams[video_index];\r
\r
+ AVRational time_base = video_context->time_base;\r
+\r
if(boost::filesystem2::path(context.filename).extension() == ".flv")\r
{\r
try\r
{\r
auto meta = read_flv_meta_info(context.filename);\r
- double fps = boost::lexical_cast<double>(meta["framerate"]);\r
- video_context->time_base.num = 1000000;\r
- video_context->time_base.den = static_cast<int>(fps*1000000.0);\r
- video_stream->nb_frames = static_cast<int64_t>(boost::lexical_cast<double>(meta["duration"])*fps);\r
+ return boost::lexical_cast<double>(meta["framerate"]);\r
+ }\r
+ catch(...)\r
+ {\r
+ return 0.0;\r
}\r
- catch(...){}\r
}\r
else\r
{\r
- video_context->time_base.num *= video_context->ticks_per_frame;\r
+ time_base.num *= video_context->ticks_per_frame;\r
\r
- if(!is_sane_fps(video_context->time_base))\r
+ if(!is_sane_fps(time_base))\r
{ \r
- video_context->time_base = fix_time_base(video_context->time_base);\r
+ time_base = fix_time_base(time_base);\r
\r
- if(!is_sane_fps(video_context->time_base) && audio_index > -1)\r
+ if(!is_sane_fps(time_base) && audio_index > -1)\r
{\r
auto& audio_context = *context.streams[audio_index]->codec;\r
auto& audio_stream = *context.streams[audio_index];\r
\r
double duration_sec = audio_stream.duration / static_cast<double>(audio_context.sample_rate);\r
\r
- video_context->time_base.num = static_cast<int>(duration_sec*100000.0);\r
- video_context->time_base.den = static_cast<int>(video_stream->nb_frames*100000);\r
+ time_base.num = static_cast<int>(duration_sec*100000.0);\r
+ time_base.den = static_cast<int>(video_stream->nb_frames*100000);\r
}\r
}\r
- \r
- //if(audio_index > -1) // Check for invalid double frame-rate\r
- //{\r
- // auto& audio_context = *context.streams[audio_index]->codec;\r
- // auto& audio_stream = *context.streams[audio_index];\r
- // \r
- // double duration_sec = audio_stream.duration / static_cast<double>(audio_context.sample_rate);\r
- // double fps = static_cast<double>(video_context->time_base.den) / static_cast<double>(video_context->time_base.num);\r
-\r
- // double fps_nb_frames = static_cast<double>(duration_sec*fps);\r
- // double stream_nb_frames = static_cast<double>(video_stream->nb_frames);\r
- // double diff = std::abs(fps_nb_frames - stream_nb_frames*2.0);\r
- // if(diff < fps_nb_frames*0.05)\r
- // video_context->time_base.num *= 2;\r
- //}\r
- //else\r
- //{\r
- // video_context->time_base.den = video_stream->r_frame_rate.num;\r
- // video_context->time_base.num = video_stream->r_frame_rate.den;\r
- //}\r
}\r
-\r
- auto nb_frames = static_cast<double>(video_stream->duration*video_stream->time_base.num)/static_cast<double>(video_stream->time_base.den);\r
- nb_frames = (nb_frames*video_context->time_base.den)/video_context->time_base.num;\r
- video_stream->nb_frames = static_cast<int64_t>(nb_frames+0.5);\r
-\r
- double fps = static_cast<double>(video_context->time_base.den) / static_cast<double>(video_context->time_base.num);\r
+ \r
+ double fps = static_cast<double>(time_base.den) / static_cast<double>(time_base.num);\r
\r
double closest_fps = 0.0;\r
for(int n = 0; n < core::video_format::count; ++n)\r
closest_fps = format.fps;\r
}\r
\r
- video_context->time_base.num = 1000000;\r
- video_context->time_base.den = static_cast<int>(closest_fps*1000000.0);\r
+ return closest_fps;\r
+ }\r
+\r
+ return fail_value; \r
+}\r
+\r
+void fix_meta_data(AVFormatContext& context)\r
+{\r
+ auto video_index = av_find_best_stream(&context, AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0);\r
+\r
+ if(video_index > -1)\r
+ {\r
+ auto video_stream = context.streams[video_index];\r
+ auto video_context = context.streams[video_index]->codec;\r
+ \r
+ if(boost::filesystem2::path(context.filename).extension() == ".flv")\r
+ {\r
+ try\r
+ {\r
+ auto meta = read_flv_meta_info(context.filename);\r
+ double fps = boost::lexical_cast<double>(meta["framerate"]);\r
+ video_stream->nb_frames = static_cast<int64_t>(boost::lexical_cast<double>(meta["duration"])*fps);\r
+ }\r
+ catch(...){}\r
+ }\r
+ else\r
+ {\r
+ video_stream->nb_frames = (video_stream->duration*video_stream->time_base.num*video_context->time_base.den)/(video_stream->time_base.den*video_context->time_base.num*video_context->ticks_per_frame); \r
+ }\r
}\r
}\r
\r
bool is_sane_fps(AVRational time_base);\r
AVRational fix_time_base(AVRational time_base);\r
\r
-//void av_dup_frame(AVFrame* frame);\r
+double read_fps(AVFormatContext& context, double fail_value);\r
\r
}}
\ No newline at end of file
\r
std::queue<safe_ptr<AVPacket>> packets_;\r
\r
- const double fps_;\r
const int64_t nb_frames_;\r
\r
const size_t width_;\r
public:\r
explicit implementation(const safe_ptr<AVFormatContext>& context) \r
: codec_context_(open_codec(*context, AVMEDIA_TYPE_VIDEO, index_))\r
- , fps_(static_cast<double>(codec_context_->time_base.den) / static_cast<double>(codec_context_->time_base.num))\r
, nb_frames_(context->streams[index_]->nb_frames)\r
, width_(codec_context_->width)\r
, height_(codec_context_->height)\r
{\r
return packets_.size() > 10;\r
}\r
- \r
- double fps() const\r
- {\r
- return fps_;\r
- }\r
};\r
\r
video_decoder::video_decoder(const safe_ptr<AVFormatContext>& context) : impl_(new implementation(context)){}\r
void video_decoder::push(const std::shared_ptr<AVPacket>& packet){impl_->push(packet);}\r
std::shared_ptr<AVFrame> video_decoder::poll(){return impl_->poll();}\r
bool video_decoder::ready() const{return impl_->ready();}\r
-double video_decoder::fps() const{return impl_->fps();}\r
int64_t video_decoder::nb_frames() const{return impl_->nb_frames_;}\r
size_t video_decoder::width() const{return impl_->width_;}\r
size_t video_decoder::height() const{return impl_->height_;}\r
size_t width() const;\r
size_t height() const;\r
int64_t nb_frames() const;\r
- double fps() const;\r
bool is_progressive() const;\r
\r
size_t file_frame_number() const;\r