\r
Microsoft Visual Studio Solution File, Format Version 12.00\r
-# Visual Studio 2010\r
+# Visual Studio 2012\r
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core", "core\core.vcxproj", "{79388C20-6499-4BF6-B8B9-D8C33D7D4DDD}"\r
EndProject\r
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shell", "shell\shell.vcxproj", "{8C26C94F-8092-4769-8D84-DEA479721C5B}"\r
{\r
const auto video_context = context.streams[video_index]->codec;\r
const auto video_stream = context.streams[video_index];\r
- \r
+ \r
+ auto frame_rate_time_base = video_stream->avg_frame_rate;\r
+ std::swap(frame_rate_time_base.num, frame_rate_time_base.den);\r
+\r
+ if(is_sane_fps(frame_rate_time_base))\r
+ {\r
+ return static_cast<double>(frame_rate_time_base.den) / static_cast<double>(frame_rate_time_base.num);\r
+ }\r
+\r
AVRational time_base = video_context->time_base;\r
\r
if(boost::filesystem2::path(context.filename).extension() == ".flv")\r
return is_valid_file(filename, invalid_exts);\r
}\r
\r
+bool try_get_duration(const std::wstring filename, std::int64_t& duration, boost::rational<std::int64_t>& time_base)\r
+{ \r
+ AVFormatContext* weak_context = nullptr;\r
+ if(avformat_open_input(&weak_context, narrow(filename).c_str(), nullptr, nullptr) < 0)\r
+ return false;\r
+\r
+ std::shared_ptr<AVFormatContext> context(weak_context, av_close_input_file);\r
+ \r
+ context->probesize = context->probesize / 10;\r
+ context->max_analyze_duration = context->probesize / 10;\r
+\r
+ if(avformat_find_stream_info(context.get(), nullptr) < 0)\r
+ return false;\r
+\r
+ const auto fps = read_fps(*context, 1.0);\r
+ \r
+ const auto rational_fps = boost::rational<std::int64_t>(static_cast<int>(fps * AV_TIME_BASE), AV_TIME_BASE);\r
+ \r
+ duration = boost::rational_cast<std::int64_t>(context->duration * rational_fps / AV_TIME_BASE);\r
+ time_base = 1/rational_fps;\r
+\r
+ return true;\r
+}\r
+\r
std::wstring probe_stem(const std::wstring stem, const std::vector<std::wstring>& invalid_exts)\r
{\r
auto stem2 = boost::filesystem2::wpath(stem);\r
#include <core/producer/frame/pixel_format.h>\r
#include <core/mixer/audio/audio_mixer.h>\r
\r
+#include <boost/rational.hpp>\r
+#include <boost/optional.hpp>\r
+\r
+#include <tuple>\r
+\r
+#include <cstdint>\r
+\r
enum PixelFormat;\r
struct AVFrame;\r
struct AVFormatContext;\r
std::wstring probe_stem(const std::wstring stem);\r
bool is_valid_file(const std::wstring filename, const std::vector<std::wstring>& invalid_exts);\r
bool is_valid_file(const std::wstring filename);\r
+bool try_get_duration(const std::wstring filename, std::int64_t& duration, boost::rational<std::int64_t>& time_base);\r
\r
core::channel_layout get_audio_channel_layout(const AVCodecContext& context, const std::wstring& custom_channel_order);\r
\r
{\r
if(boost::filesystem::is_regular_file(path))\r
{\r
+ std::int64_t duration = 0;\r
+ boost::rational<std::int64_t> time_base;\r
+ \r
std::wstring clipttype = TEXT(" N/A ");\r
std::wstring extension = boost::to_upper_copy(path.extension());\r
if(extension == TEXT(".TGA") || extension == TEXT(".COL") || extension == L".PNG" || extension == L".JPEG" || extension == L".JPG" ||\r
extension == L"GIF" || extension == L"BMP")\r
- clipttype = TEXT(" STILL ");\r
+ {\r
+ clipttype = TEXT(" STILL "); \r
+ }\r
else if(extension == TEXT(".WAV") || extension == TEXT(".MP3"))\r
+ {\r
clipttype = TEXT(" AUDIO ");\r
+ }\r
else if(extension == TEXT(".SWF") || extension == TEXT(".CT") || \r
extension == TEXT(".DV") || extension == TEXT(".MOV") || \r
extension == TEXT(".MPG") || extension == TEXT(".AVI") || \r
extension == TEXT(".MP4") || extension == TEXT(".FLV") || \r
extension == TEXT(".STGA") || \r
caspar::ffmpeg::is_valid_file(path.file_string()))\r
+ {\r
+ ffmpeg::try_get_duration(path.file_string(), duration, time_base);\r
clipttype = TEXT(" MOVIE ");\r
+ }\r
\r
if(clipttype != TEXT(" N/A "))\r
{ \r
auto str = relativePath.replace_extension(TEXT("")).external_file_string();\r
if(str[0] == '\\' || str[0] == '/')\r
str = std::wstring(str.begin() + 1, str.end());\r
-\r
- return std::wstring() + TEXT("\"") + str +\r
- + TEXT("\" ") + clipttype +\r
- + TEXT(" ") + sizeStr +\r
- + TEXT(" ") + writeTimeWStr +\r
- + TEXT("\r\n"); \r
+ \r
+ return std::wstring() \r
+ + L"\"" + str +\r
+ + L"\" " + clipttype +\r
+ + L" " + sizeStr +\r
+ + L" " + writeTimeWStr +\r
+ + L" " + boost::lexical_cast<std::wstring>(duration) +\r
+ + L" " + boost::lexical_cast<std::wstring>(time_base.numerator()) + L"/" + boost::lexical_cast<std::wstring>(time_base.denominator())\r
+ + L"\r\n"; \r
} \r
}\r
return L"";\r
}\r
\r
std::wstring ListMedia()\r
-{ \r
+{ \r
std::wstringstream replyString;\r
for (boost::filesystem::wrecursive_directory_iterator itr(env::media_folder()), end; itr != end; ++itr) \r
replyString << MediaInfo(itr->path());\r