std::queue<std::shared_ptr<AVPacket>> packets_;\r
\r
int64_t nb_frames_;\r
- double duration_;\r
public:\r
explicit implementation(const safe_ptr<AVFormatContext>& context, const core::video_format_desc& format_desc) \r
: format_desc_(format_desc) \r
, nb_frames_(0)\r
- , duration_(std::numeric_limits<double>::max())\r
{ \r
try\r
{\r
\r
buffer1_.resize(AVCODEC_MAX_AUDIO_FRAME_SIZE*2);\r
\r
- //nb_frames_ = context->streams[index_]->nb_frames;\r
- //if(nb_frames_ == 0)\r
- // nb_frames_ = context->streams[index_]->duration / (codec_context_->channels*codec_context_->sample_rate);\r
- duration_ = context->streams[index_]->duration / static_cast<double>(codec_context_->sample_rate);\r
-\r
if(codec_context_->sample_rate != static_cast<int>(format_desc_.audio_sample_rate) || \r
codec_context_->channels != static_cast<int>(format_desc_.audio_channels) ||\r
codec_context_->sample_fmt != AV_SAMPLE_FMT_S16)\r
bool audio_decoder::ready() const{return impl_->ready();}\r
std::vector<std::shared_ptr<std::vector<int16_t>>> audio_decoder::poll(){return impl_->poll();}\r
int64_t audio_decoder::nb_frames() const{return impl_->nb_frames_;}\r
-double audio_decoder::duration() const {return impl_->duration_;}\r
}
\ No newline at end of file
std::vector<std::shared_ptr<std::vector<int16_t>>> poll();\r
\r
int64_t nb_frames() const;\r
- double duration() const;\r
\r
private:\r
struct implementation;\r
#include <tbb/parallel_invoke.h>\r
\r
namespace caspar {\r
-\r
-double validate_fps(double fps, int64_t nb_frames, double duration_sec)\r
-{\r
- if(fps > 20.0 && fps < 80.0)\r
- return fps;\r
- \r
- auto est_fps = nb_frames/duration_sec;\r
-\r
- CASPAR_LOG(warning) << L"Invalid framerate detected, trying to estimate, fps: " << fps << L" nb_frames: " << nb_frames << L" duration_sec: " << duration_sec << L" => " << est_fps << L" fps.";\r
-\r
- return est_fps;\r
-}\r
- \r
+ \r
struct ffmpeg_producer : public core::frame_producer\r
{\r
const std::wstring filename_;\r
, input_(graph_, filename_, loop, start, length)\r
, video_decoder_(input_.context(), frame_factory, filter)\r
, audio_decoder_(input_.context(), frame_factory->get_video_format_desc())\r
- , fps_(validate_fps(video_decoder_.fps(), video_decoder_.nb_frames(), audio_decoder_.duration()))\r
+ , fps_(video_decoder_.fps())\r
, muxer_(fps_, frame_factory)\r
, late_frames_(0)\r
, start_(start)\r
virtual std::wstring print() const\r
{\r
return L"ffmpeg[" + boost::filesystem::wpath(filename_).filename() + L"|" \r
- + boost::lexical_cast<std::wstring>(fps_) + (is_progressive_ ? L"p" : L"i") +L"|"\r
- + boost::lexical_cast<std::wstring>(width_) + L"x" + boost::lexical_cast<std::wstring>(height_) + L"]";\r
+ + boost::lexical_cast<std::wstring>(width_) + L"x" + boost::lexical_cast<std::wstring>(height_)\r
+ + (is_progressive_ ? L"p" : L"i") + boost::lexical_cast<std::wstring>(fps_)\r
+ + L"]";\r
}\r
};\r
\r
}\r
}\r
\r
+bool is_sane_fps(AVRational time_base)\r
+{\r
+ double fps = static_cast<double>(time_base.den) / static_cast<double>(time_base.num);\r
+ return fps > 20.0 && fps < 65.0;\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
+ auto audio_index = av_find_best_stream(&context, AVMEDIA_TYPE_AUDIO, -1, -1, 0, 0);\r
+\r
+ if(video_index < 0)\r
+ return;\r
+\r
+ auto& video_context = *context.streams[video_index]->codec;\r
+ auto& video_stream = *context.streams[video_index];\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
+ }\r
+ catch(...){}\r
+ }\r
+ else\r
+ {\r
+ if(video_stream.nb_frames == 0)\r
+ video_stream.nb_frames = video_stream.duration;\r
+\r
+ if(!is_sane_fps(video_context.time_base))\r
+ { \r
+ if(video_context.time_base.num == 1)\r
+ video_context.time_base.num = static_cast<int>(std::pow(10.0, static_cast<int>(std::log10(static_cast<float>(video_context.time_base.den)))-1)); \r
+\r
+ if(!is_sane_fps(video_context.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
+ }\r
+ }\r
+ }\r
+\r
+ double fps = static_cast<double>(video_context.time_base.den) / static_cast<double>(video_context.time_base.num);\r
+\r
+ double closest_fps = 0.0;\r
+ for(int n = 0; n < core::video_format::count; ++n)\r
+ {\r
+ auto format = core::video_format_desc::get(static_cast<core::video_format::type>(n));\r
+\r
+ double diff1 = std::abs(format.fps - fps);\r
+ double diff2 = std::abs(closest_fps - fps);\r
+\r
+ if(diff1 < diff2)\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
+}\r
+\r
}
\ No newline at end of file
int make_alpha_format(int format); // NOTE: Be careful about CASPAR_PIX_FMT_LUMA, change it to PIX_FMT_GRAY8 if you want to use the frame inside some ffmpeg function.\r
safe_ptr<core::write_frame> make_write_frame(const void* tag, const safe_ptr<AVFrame>& decoded_frame, const safe_ptr<core::frame_factory>& frame_factory, int hints);\r
\r
+void fix_meta_data(AVFormatContext& context);\r
+\r
}
\ No newline at end of file
\r
#include "video_decoder.h"\r
\r
-#include "../format/flv.h"\r
#include "../util.h"\r
#include "../filter/filter.h"\r
\r
#endif\r
\r
namespace caspar {\r
- \r
+ \r
struct video_decoder::implementation : boost::noncopyable\r
{\r
const safe_ptr<core::frame_factory> frame_factory_;\r
CASPAR_LOG(debug) << "[video_decoder] " << context->streams[index_]->codec->codec->long_name;\r
\r
// Some files give an invalid time_base numerator, try to fix it.\r
- if(codec_context_ && codec_context_->time_base.num == 1)\r
- codec_context_->time_base.num = static_cast<int>(std::pow(10.0, static_cast<int>(std::log10(static_cast<float>(codec_context_->time_base.den)))-1)); \r
- \r
- if(boost::filesystem2::path(context->filename).extension() == ".flv")\r
- {\r
- try\r
- {\r
- auto meta = read_flv_meta_info(context->filename);\r
- fps_ = boost::lexical_cast<double>(meta["framerate"]);\r
- nb_frames_ = static_cast<int64_t>(boost::lexical_cast<double>(meta["duration"])*fps_);\r
- }\r
- catch(...){}\r
- }\r
- else\r
- {\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
- if(nb_frames_ == 0)\r
- nb_frames_ = context->streams[index_]->duration;// * context->streams[index_]->time_base.den;\r
- }\r
+\r
+ fix_meta_data(*context);\r
+ \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
\r
if(double_rate(filter))\r
fps_ *= 2;\r