From 0e8e12e282ce9f222ba9726d2d9d418c594121ed Mon Sep 17 00:00:00 2001 From: ronag Date: Sun, 4 Dec 2011 22:07:21 +0000 Subject: [PATCH] 2.0.2: - Updated get_param. - Changed how ffmpeg decides if it can open file. Try to probe the file before looking at extension. - image_producer: Print initialization. git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.2@1786 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d --- common/common.vcxproj | 1 + common/common.vcxproj.filters | 3 ++ common/utility/param.h | 36 +++++++++++++++ core/producer/frame_producer.h | 17 ------- modules/decklink/interop/DeckLinkAPI_h.h | 2 +- modules/decklink/interop/DeckLinkAPI_i.c | 2 +- .../decklink/producer/decklink_producer.cpp | 16 +++---- modules/ffmpeg/consumer/ffmpeg_consumer.cpp | 24 ++++------ modules/ffmpeg/producer/ffmpeg_producer.cpp | 44 +++++-------------- modules/ffmpeg/producer/input/input.cpp | 8 ++-- modules/ffmpeg/producer/input/input.h | 2 +- modules/ffmpeg/producer/util/util.cpp | 34 ++++++++++++++ modules/ffmpeg/producer/util/util.h | 22 +++------- modules/image/producer/image_producer.cpp | 3 ++ .../image/producer/image_scroll_producer.cpp | 3 ++ protocol/amcp/AMCPCommandsImpl.cpp | 8 ++-- protocol/protocol.vcxproj | 3 ++ shell/casparcg.config | 13 +----- 18 files changed, 131 insertions(+), 110 deletions(-) create mode 100644 common/utility/param.h diff --git a/common/common.vcxproj b/common/common.vcxproj index ccb0b48bd..98c2b1750 100644 --- a/common/common.vcxproj +++ b/common/common.vcxproj @@ -228,6 +228,7 @@ + diff --git a/common/common.vcxproj.filters b/common/common.vcxproj.filters index 9986cc11a..a6a80de9c 100644 --- a/common/common.vcxproj.filters +++ b/common/common.vcxproj.filters @@ -130,5 +130,8 @@ source\concurrency + + source\utility + \ No newline at end of file diff --git a/common/utility/param.h b/common/utility/param.h new file mode 100644 index 000000000..94ec4923c --- /dev/null +++ b/common/utility/param.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include +#include + +namespace caspar { + +template +typename std::enable_if::value, typename std::decay::type>::type get_param(const std::wstring& name, C&& params, T fail_value = T()) +{ + auto it = std::find(std::begin(params), std::end(params), name); + if(it == params.end() || ++it == params.end()) + return fail_value; + + T value = fail_value; + try + { + value = boost::lexical_cast::type>(*it); + } + catch(boost::bad_lexical_cast&){} + + return value; +} + +template +std::wstring get_param(const std::wstring& name, C&& params, const std::wstring& fail_value = L"") +{ + auto it = std::find(std::begin(params), std::end(params), name); + if(it == params.end() || ++it == params.end()) + return fail_value; + return *it; +} + +} \ No newline at end of file diff --git a/core/producer/frame_producer.h b/core/producer/frame_producer.h index b1f3aa556..c18fc55ca 100644 --- a/core/producer/frame_producer.h +++ b/core/producer/frame_producer.h @@ -85,21 +85,4 @@ safe_ptr create_producer(const safe_ptr&, c safe_ptr create_producer(const safe_ptr&, const std::wstring& params); safe_ptr create_producer_destroy_proxy(safe_ptr&& producer); -template -typename std::decay::type get_param(const std::wstring& name, const std::vector& params, T fail_value) -{ - auto it = std::find(params.begin(), params.end(), name); - if(it == params.end() || ++it == params.end()) - return fail_value; - - T value = fail_value; - try - { - value = boost::lexical_cast::type>(*it); - } - catch(boost::bad_lexical_cast&){} - - return value; -} - }} diff --git a/modules/decklink/interop/DeckLinkAPI_h.h b/modules/decklink/interop/DeckLinkAPI_h.h index 6474be151..6d98b32bc 100644 --- a/modules/decklink/interop/DeckLinkAPI_h.h +++ b/modules/decklink/interop/DeckLinkAPI_h.h @@ -4,7 +4,7 @@ /* File created by MIDL compiler version 7.00.0555 */ -/* at Fri Dec 02 22:18:37 2011 +/* at Sun Dec 04 16:03:37 2011 */ /* Compiler settings for interop\DeckLinkAPI.idl: Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 diff --git a/modules/decklink/interop/DeckLinkAPI_i.c b/modules/decklink/interop/DeckLinkAPI_i.c index ace0b473a..23d0474f0 100644 --- a/modules/decklink/interop/DeckLinkAPI_i.c +++ b/modules/decklink/interop/DeckLinkAPI_i.c @@ -6,7 +6,7 @@ /* File created by MIDL compiler version 7.00.0555 */ -/* at Fri Dec 02 22:18:37 2011 +/* at Sun Dec 04 16:03:37 2011 */ /* Compiler settings for interop\DeckLinkAPI.idl: Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 diff --git a/modules/decklink/producer/decklink_producer.cpp b/modules/decklink/producer/decklink_producer.cpp index 6a0fd2d10..d88ff9cf9 100644 --- a/modules/decklink/producer/decklink_producer.cpp +++ b/modules/decklink/producer/decklink_producer.cpp @@ -31,11 +31,12 @@ #include "../../ffmpeg/producer/muxer/frame_muxer.h" #include "../../ffmpeg/producer/muxer/display_mode.h" -#include -#include #include +#include #include +#include #include +#include #include #include @@ -309,15 +310,14 @@ safe_ptr create_producer(const safe_ptr(L"FILTER", params, L""); - auto length = core::get_param(L"LENGTH", params, std::numeric_limits::max()); + auto device_index = get_param(L"DEVICE", params, 1); + auto filter_str = get_param(L"FILTER", params); + auto length = get_param(L"LENGTH", params, std::numeric_limits::max()); + auto format_desc = core::video_format_desc::get(get_param(L"FORMAT", params, L"INVALID")); boost::replace_all(filter_str, L"DEINTERLACE", L"YADIF=0:-1"); boost::replace_all(filter_str, L"DEINTERLACE_BOB", L"YADIF=1:-1"); - - auto format_desc = core::video_format_desc::get(core::get_param(L"FORMAT", params, L"INVALID")); - + if(format_desc.format == core::video_format::invalid) format_desc = frame_factory->get_video_format_desc(); diff --git a/modules/ffmpeg/consumer/ffmpeg_consumer.cpp b/modules/ffmpeg/consumer/ffmpeg_consumer.cpp index d0fb6bf65..2a93beac8 100644 --- a/modules/ffmpeg/consumer/ffmpeg_consumer.cpp +++ b/modules/ffmpeg/consumer/ffmpeg_consumer.cpp @@ -32,8 +32,9 @@ #include #include -#include #include +#include +#include #include #include @@ -447,27 +448,20 @@ safe_ptr create_consumer(const std::vector& if(params.size() < 1 || params[0] != L"FILE") return core::frame_consumer::empty(); - auto filename = (params.size() > 1 ? params[1] : L""); - - bool key_only = std::find(params.begin(), params.end(), L"KEY_ONLY") != params.end(); - - std::wstring codec = L"libx264"; - auto codec_it = std::find(params.begin(), params.end(), L"CODEC"); - if(codec_it != params.end() && codec_it++ != params.end()) - codec = *codec_it; - + auto filename = (params.size() > 1 ? params[1] : L""); + bool key_only = get_param(L"KEY_ONLY", params, false); + auto codec = get_param(L"CODEC", params, L"libx264"); + auto options = get_param(L"OPTIONS", params); + if(codec == L"H264") codec = L"libx264"; if(codec == L"DVCPRO") codec = L"dvvideo"; - std::wstring options = L""; - auto options_it = std::find(params.begin(), params.end(), L"OPTIONS"); - if(options_it != params.end() && options_it++ != params.end()) - options = *options_it; + boost::to_lower(options); - return make_safe(env::media_folder() + filename, key_only, codec, boost::to_lower_copy(options)); + return make_safe(env::media_folder() + filename, key_only, codec, options); } safe_ptr create_consumer(const boost::property_tree::ptree& ptree) diff --git a/modules/ffmpeg/producer/ffmpeg_producer.cpp b/modules/ffmpeg/producer/ffmpeg_producer.cpp index 21004c357..bca113f8c 100644 --- a/modules/ffmpeg/producer/ffmpeg_producer.cpp +++ b/modules/ffmpeg/producer/ffmpeg_producer.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -74,9 +75,9 @@ struct ffmpeg_producer : public core::frame_producer std::unique_ptr muxer_; const double fps_; - const int start_; + const int64_t start_; + const int64_t length_; const bool loop_; - const size_t length_; safe_ptr last_frame_; @@ -86,15 +87,15 @@ struct ffmpeg_producer : public core::frame_producer int64_t file_frame_number_;; public: - explicit ffmpeg_producer(const safe_ptr& frame_factory, const std::wstring& filename, const std::wstring& filter, bool loop, int start, size_t length) + explicit ffmpeg_producer(const safe_ptr& frame_factory, const std::wstring& filename, const std::wstring& filter, bool loop, int64_t start, int64_t length) : filename_(filename) , frame_factory_(frame_factory) , format_desc_(frame_factory->get_video_format_desc()) , input_(graph_, filename_, loop, start, length) , fps_(read_fps(*input_.context(), format_desc_.fps)) , start_(start) - , loop_(loop) , length_(length) + , loop_(loop) , last_frame_(core::basic_frame::empty()) , frame_number_(0) { @@ -324,41 +325,20 @@ public: safe_ptr create_producer(const safe_ptr& frame_factory, const std::vector& params) { - static const std::vector extensions = boost::assign::list_of - (L"mpg")(L"mpeg")(L"m2v")(L"m4v")(L"mp3")(L"mp4")(L"mpga") - (L"avi") - (L"mov") - (L"qt") - (L"webm") - (L"dv") - (L"f4v")(L"flv") - (L"mkv")(L"mka") - (L"mxf") - (L"wmv")(L"wma")(L"wav") - (L"rm")(L"ram") - (L"ogg")(L"ogv")(L"oga")(L"ogx") - (L"divx")(L"xvid"); - - std::wstring filename = env::media_folder() + L"\\" + params[0]; - - auto ext = boost::find_if(extensions, [&](const std::wstring& ex) - { - return boost::filesystem::is_regular_file(boost::filesystem::wpath(filename + L"." + ex)); - }); + auto filename = probe_stem(env::media_folder() + L"\\" + params.at(0)); - if(ext == extensions.end()) + if(filename.empty()) return core::frame_producer::empty(); - - auto path = filename + L"." + *ext; + auto loop = boost::range::find(params, L"LOOP") != params.end(); - auto start = core::get_param(L"SEEK", params, 0); - auto length = core::get_param(L"LENGTH", params, std::numeric_limits::max()); - auto filter_str = core::get_param(L"FILTER", params, L""); + auto start = get_param(L"SEEK", params, static_cast(0)); + auto length = get_param(L"LENGTH", params, std::numeric_limits::max()); + auto filter_str = get_param(L"FILTER", params, L""); boost::replace_all(filter_str, L"DEINTERLACE", L"YADIF=0:-1"); boost::replace_all(filter_str, L"DEINTERLACE_BOB", L"YADIF=1:-1"); - return create_producer_destroy_proxy(make_safe(frame_factory, path, filter_str, loop, start, length)); + return create_producer_destroy_proxy(make_safe(frame_factory, filename, filter_str, loop, start, length)); } }} \ No newline at end of file diff --git a/modules/ffmpeg/producer/input/input.cpp b/modules/ffmpeg/producer/input/input.cpp index 093bc7ac4..ffa43eadd 100644 --- a/modules/ffmpeg/producer/input/input.cpp +++ b/modules/ffmpeg/producer/input/input.cpp @@ -70,8 +70,8 @@ struct input::implementation : boost::noncopyable const std::wstring filename_; tbb::atomic loop_; - const size_t start_; - const size_t length_; + const uint64_t start_; + const uint64_t length_; size_t frame_number_; tbb::concurrent_bounded_queue> buffer_; @@ -85,7 +85,7 @@ struct input::implementation : boost::noncopyable tbb::recursive_mutex mutex_; - explicit implementation(const safe_ptr& graph, const std::wstring& filename, bool loop, size_t start, size_t length) + explicit implementation(const safe_ptr& graph, const std::wstring& filename, bool loop, int64_t start, int64_t length) : graph_(graph) , format_context_(open_input(filename)) , default_stream_index_(av_find_default_stream_index(format_context_.get())) @@ -275,7 +275,7 @@ struct input::implementation : boost::noncopyable } }; -input::input(const safe_ptr& graph, const std::wstring& filename, bool loop, size_t start, size_t length) +input::input(const safe_ptr& graph, const std::wstring& filename, bool loop, int64_t start, int64_t length) : impl_(new implementation(graph, filename, loop, start, length)){} bool input::eof() const {return impl_->is_eof_;} bool input::try_pop(std::shared_ptr& packet){return impl_->try_pop(packet);} diff --git a/modules/ffmpeg/producer/input/input.h b/modules/ffmpeg/producer/input/input.h index b62a1eea6..32df1e52f 100644 --- a/modules/ffmpeg/producer/input/input.h +++ b/modules/ffmpeg/producer/input/input.h @@ -45,7 +45,7 @@ namespace ffmpeg { class input : boost::noncopyable { public: - explicit input(const safe_ptr& graph, const std::wstring& filename, bool loop, size_t start = 0, size_t length = std::numeric_limits::max()); + explicit input(const safe_ptr& graph, const std::wstring& filename, bool loop, int64_t start, int64_t length); bool try_pop(std::shared_ptr& packet); bool eof() const; diff --git a/modules/ffmpeg/producer/util/util.cpp b/modules/ffmpeg/producer/util/util.cpp index 8a46f65eb..6c5bb324a 100644 --- a/modules/ffmpeg/producer/util/util.cpp +++ b/modules/ffmpeg/producer/util/util.cpp @@ -459,6 +459,40 @@ std::wstring print_mode(size_t width, size_t height, double fps, bool interlaced return boost::lexical_cast(width) + L"x" + boost::lexical_cast(height) + (!interlaced ? L"p" : L"i") + fps_ss.str(); } + +bool is_valid_file(const std::wstring filename) +{ + auto filename2 = narrow(filename); + + std::ifstream file(filename2); + + std::vector buf; + for(auto file_it = std::istreambuf_iterator(file); file_it != std::istreambuf_iterator() && buf.size() < 2048; ++file_it) + buf.push_back(*file_it); + + if(buf.empty()) + return nullptr; + + AVProbeData pb; + pb.filename = filename2.c_str(); + pb.buf = buf.data(); + pb.buf_size = buf.size(); + + int score = 0; + return av_probe_input_format2(&pb, true, &score) != nullptr; +} + +std::wstring probe_stem(const std::wstring stem) +{ + auto stem2 = boost::filesystem2::wpath(stem); + auto dir = stem2.parent_path(); + for(auto it = boost::filesystem2::wdirectory_iterator(dir); it != boost::filesystem2::wdirectory_iterator(); ++it) + { + if(boost::iequals(it->path().stem(), stem2.filename()) && is_valid_file(it->path().file_string())) + return it->path().file_string(); + } + return L""; +} // //void av_dup_frame(AVFrame* frame) //{ diff --git a/modules/ffmpeg/producer/util/util.h b/modules/ffmpeg/producer/util/util.h index f87e977c0..2960c2e94 100644 --- a/modules/ffmpeg/producer/util/util.h +++ b/modules/ffmpeg/producer/util/util.h @@ -27,23 +27,12 @@ #include #include - -#if defined(_MSC_VER) -#pragma warning (push) -#pragma warning (disable : 4244) -#endif -extern "C" -{ - #include - #include -} -#if defined(_MSC_VER) -#pragma warning (pop) -#endif - +enum PixelFormat; struct AVFrame; struct AVFormatContext; struct AVPacket; +struct AVRational; +struct AVCodecContext; namespace caspar { @@ -64,7 +53,7 @@ std::shared_ptr empty_video(); // Utils -static const PixelFormat CASPAR_PIX_FMT_LUMA = PIX_FMT_MONOBLACK; // Just hijack some unual pixel format. +static const int CASPAR_PIX_FMT_LUMA = 10; // Just hijack some unual pixel format. core::field_mode::type get_mode(const AVFrame& frame); 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. @@ -82,4 +71,7 @@ double read_fps(AVFormatContext& context, double fail_value); std::wstring print_mode(size_t width, size_t height, double fps, bool interlaced); +std::wstring probe_stem(const std::wstring stem); +bool is_valid_file(const std::wstring filename); + }} \ No newline at end of file diff --git a/modules/image/producer/image_producer.cpp b/modules/image/producer/image_producer.cpp index 776890e17..a21ec9166 100644 --- a/modules/image/producer/image_producer.cpp +++ b/modules/image/producer/image_producer.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -61,6 +62,8 @@ struct image_producer : public core::frame_producer std::copy_n(FreeImage_GetBits(bitmap.get()), frame->image_data().size(), frame->image_data().begin()); frame->commit(); frame_ = std::move(frame); + + CASPAR_LOG(info) << print() << L" Initialized"; } // frame_producer diff --git a/modules/image/producer/image_scroll_producer.cpp b/modules/image/producer/image_scroll_producer.cpp index 3f8c12d0b..25aebb2af 100644 --- a/modules/image/producer/image_scroll_producer.cpp +++ b/modules/image/producer/image_scroll_producer.cpp @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -155,6 +156,8 @@ struct image_scroll_producer : public core::frame_producer start_offset_[0] = (std::ceil(static_cast(width_) / static_cast(format_desc_.width)) + 1.0) * 0.5;// - 1.5; } } + + CASPAR_LOG(info) << print() << L" Initialized"; } // frame_producer diff --git a/protocol/amcp/AMCPCommandsImpl.cpp b/protocol/amcp/AMCPCommandsImpl.cpp index 3d5c06ac3..e69286580 100644 --- a/protocol/amcp/AMCPCommandsImpl.cpp +++ b/protocol/amcp/AMCPCommandsImpl.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -95,13 +96,10 @@ std::wstring MediaInfo(const boost::filesystem::wpath& path) if(extension == TEXT(".TGA") || extension == TEXT(".COL") || extension == L".PNG" || extension == L".JPEG" || extension == L".JPG" || extension == L"GIF" || extension == L"BMP") clipttype = TEXT(" STILL "); - else if(extension == TEXT(".SWF") || extension == TEXT(".DV") || extension == TEXT(".MOV") || extension == TEXT(".MPG") || - extension == TEXT(".AVI") || extension == TEXT(".FLV") || extension == TEXT(".F4V") || extension == TEXT(".MP4") || - extension == L".M2V" || extension == L".H264" || extension == L".MKV" || extension == L".WMV" || extension == L".DIVX" || - extension == L".XVID" || extension == L".OGG" || extension == L".CT" || extension == L".MXF") - clipttype = TEXT(" MOVIE "); else if(extension == TEXT(".WAV") || extension == TEXT(".MP3")) clipttype = TEXT(" STILL "); + else if(caspar::ffmpeg::is_valid_file(path.file_string()) || extension == L".CT") + clipttype = TEXT(" MOVIE "); if(clipttype != TEXT(" N/A ")) { diff --git a/protocol/protocol.vcxproj b/protocol/protocol.vcxproj index 3364ad207..4977c49a1 100644 --- a/protocol/protocol.vcxproj +++ b/protocol/protocol.vcxproj @@ -25,6 +25,9 @@ {79388c20-6499-4bf6-b8b9-d8c33d7d4ddd} + + {f6223af3-be0b-4b61-8406-98922ce521c2} + {816deaba-3757-4306-afe0-c27cf96c4dea} diff --git a/shell/casparcg.config b/shell/casparcg.config index 9e3226620..4d3d10108 100644 --- a/shell/casparcg.config +++ b/shell/casparcg.config @@ -10,18 +10,9 @@ PAL - + true - - - - - PAL - - - 2 - - + -- 2.39.2