<ClInclude Include="stdafx.h" />\r
<ClInclude Include="utility\assert.h" />\r
<ClInclude Include="utility\move_on_copy.h" />\r
+ <ClInclude Include="utility\param.h" />\r
<ClInclude Include="utility\string.h" />\r
<ClInclude Include="utility\timer.h" />\r
<ClInclude Include="utility\tweener.h" />\r
<ClInclude Include="concurrency\target.h">\r
<Filter>source\concurrency</Filter>\r
</ClInclude>\r
+ <ClInclude Include="utility\param.h">\r
+ <Filter>source\utility</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
--- /dev/null
+#pragma once\r
+\r
+#include <boost/lexical_cast.hpp>\r
+\r
+#include <type_traits>\r
+#include <string>\r
+\r
+namespace caspar {\r
+ \r
+template<typename T, typename C>\r
+typename std::enable_if<!std::is_convertible<T, std::wstring>::value, typename std::decay<T>::type>::type get_param(const std::wstring& name, C&& params, T fail_value = T())\r
+{ \r
+ auto it = std::find(std::begin(params), std::end(params), name);\r
+ if(it == params.end() || ++it == params.end()) \r
+ return fail_value;\r
+ \r
+ T value = fail_value;\r
+ try\r
+ {\r
+ value = boost::lexical_cast<std::decay<T>::type>(*it);\r
+ }\r
+ catch(boost::bad_lexical_cast&){}\r
+\r
+ return value;\r
+}\r
+\r
+template<typename C>\r
+std::wstring get_param(const std::wstring& name, C&& params, const std::wstring& fail_value = L"")\r
+{ \r
+ auto it = std::find(std::begin(params), std::end(params), name);\r
+ if(it == params.end() || ++it == params.end()) \r
+ return fail_value;\r
+ return *it;\r
+}\r
+\r
+}
\ No newline at end of file
safe_ptr<core::frame_producer> create_producer(const safe_ptr<frame_factory>&, const std::wstring& params);\r
safe_ptr<core::frame_producer> create_producer_destroy_proxy(safe_ptr<core::frame_producer>&& producer);\r
\r
-template<typename T>\r
-typename std::decay<T>::type get_param(const std::wstring& name, const std::vector<std::wstring>& params, T fail_value)\r
-{ \r
- auto it = std::find(params.begin(), params.end(), name);\r
- if(it == params.end() || ++it == params.end()) \r
- return fail_value;\r
- \r
- T value = fail_value;\r
- try\r
- {\r
- value = boost::lexical_cast<std::decay<T>::type>(*it);\r
- }\r
- catch(boost::bad_lexical_cast&){}\r
-\r
- return value;\r
-}\r
-\r
}}\r
\r
\r
/* File created by MIDL compiler version 7.00.0555 */\r
-/* at Fri Dec 02 22:18:37 2011\r
+/* at Sun Dec 04 16:03:37 2011\r
*/\r
/* Compiler settings for interop\DeckLinkAPI.idl:\r
Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 \r
\r
\r
/* File created by MIDL compiler version 7.00.0555 */\r
-/* at Fri Dec 02 22:18:37 2011\r
+/* at Sun Dec 04 16:03:37 2011\r
*/\r
/* Compiler settings for interop\DeckLinkAPI.idl:\r
Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 \r
#include "../../ffmpeg/producer/muxer/frame_muxer.h"\r
#include "../../ffmpeg/producer/muxer/display_mode.h"\r
\r
-#include <common/log/log.h>\r
-#include <common/diagnostics/graph.h>\r
#include <common/concurrency/com_context.h>\r
+#include <common/diagnostics/graph.h>\r
#include <common/exception/exceptions.h>\r
+#include <common/log/log.h>\r
#include <common/memory/memclr.h>\r
+#include <common/utility/param.h>\r
\r
#include <core/mixer/write_frame.h>\r
#include <core/producer/frame/frame_transform.h>\r
if(params.empty() || !boost::iequals(params[0], "decklink"))\r
return core::frame_producer::empty();\r
\r
- auto device_index = core::get_param(L"DEVICE", params, 1);\r
- auto filter_str = core::get_param<std::wstring>(L"FILTER", params, L""); \r
- auto length = core::get_param(L"LENGTH", params, std::numeric_limits<int64_t>::max()); \r
+ auto device_index = get_param(L"DEVICE", params, 1);\r
+ auto filter_str = get_param(L"FILTER", params); \r
+ auto length = get_param(L"LENGTH", params, std::numeric_limits<int64_t>::max()); \r
+ auto format_desc = core::video_format_desc::get(get_param(L"FORMAT", params, L"INVALID"));\r
\r
boost::replace_all(filter_str, L"DEINTERLACE", L"YADIF=0:-1");\r
boost::replace_all(filter_str, L"DEINTERLACE_BOB", L"YADIF=1:-1");\r
-\r
- auto format_desc = core::video_format_desc::get(core::get_param<std::wstring>(L"FORMAT", params, L"INVALID"));\r
-\r
+ \r
if(format_desc.format == core::video_format::invalid)\r
format_desc = frame_factory->get_video_format_desc();\r
\r
\r
#include <common/concurrency/executor.h>\r
#include <common/diagnostics/graph.h>\r
-#include <common/utility/string.h>\r
#include <common/env.h>\r
+#include <common/utility/string.h>\r
+#include <common/utility/param.h>\r
\r
#include <boost/algorithm/string.hpp>\r
#include <boost/timer.hpp>\r
if(params.size() < 1 || params[0] != L"FILE")\r
return core::frame_consumer::empty();\r
\r
- auto filename = (params.size() > 1 ? params[1] : L"");\r
-\r
- bool key_only = std::find(params.begin(), params.end(), L"KEY_ONLY") != params.end();\r
-\r
- std::wstring codec = L"libx264";\r
- auto codec_it = std::find(params.begin(), params.end(), L"CODEC");\r
- if(codec_it != params.end() && codec_it++ != params.end())\r
- codec = *codec_it;\r
-\r
+ auto filename = (params.size() > 1 ? params[1] : L"");\r
+ bool key_only = get_param(L"KEY_ONLY", params, false);\r
+ auto codec = get_param(L"CODEC", params, L"libx264");\r
+ auto options = get_param(L"OPTIONS", params);\r
+ \r
if(codec == L"H264")\r
codec = L"libx264";\r
\r
if(codec == L"DVCPRO")\r
codec = L"dvvideo";\r
\r
- std::wstring options = L"";\r
- auto options_it = std::find(params.begin(), params.end(), L"OPTIONS");\r
- if(options_it != params.end() && options_it++ != params.end())\r
- options = *options_it;\r
+ boost::to_lower(options);\r
\r
- return make_safe<ffmpeg_consumer_proxy>(env::media_folder() + filename, key_only, codec, boost::to_lower_copy(options));\r
+ return make_safe<ffmpeg_consumer_proxy>(env::media_folder() + filename, key_only, codec, options);\r
}\r
\r
safe_ptr<core::frame_consumer> create_consumer(const boost::property_tree::ptree& ptree)\r
\r
#include <common/env.h>\r
#include <common/utility/assert.h>\r
+#include <common/utility/param.h>\r
#include <common/diagnostics/graph.h>\r
\r
#include <core/video_format.h>\r
std::unique_ptr<frame_muxer> muxer_;\r
\r
const double fps_;\r
- const int start_;\r
+ const int64_t start_;\r
+ const int64_t length_;\r
const bool loop_;\r
- const size_t length_;\r
\r
safe_ptr<core::basic_frame> last_frame_;\r
\r
int64_t file_frame_number_;;\r
\r
public:\r
- explicit ffmpeg_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& filename, const std::wstring& filter, bool loop, int start, size_t length) \r
+ explicit ffmpeg_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& filename, const std::wstring& filter, bool loop, int64_t start, int64_t length) \r
: filename_(filename)\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
+ , loop_(loop)\r
, last_frame_(core::basic_frame::empty())\r
, frame_number_(0)\r
{\r
\r
safe_ptr<core::frame_producer> create_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::vector<std::wstring>& params)\r
{ \r
- static const std::vector<std::wstring> extensions = boost::assign::list_of\r
- (L"mpg")(L"mpeg")(L"m2v")(L"m4v")(L"mp3")(L"mp4")(L"mpga")\r
- (L"avi")\r
- (L"mov")\r
- (L"qt")\r
- (L"webm")\r
- (L"dv") \r
- (L"f4v")(L"flv")\r
- (L"mkv")(L"mka")\r
- (L"mxf")\r
- (L"wmv")(L"wma")(L"wav")\r
- (L"rm")(L"ram")\r
- (L"ogg")(L"ogv")(L"oga")(L"ogx")\r
- (L"divx")(L"xvid");\r
-\r
- std::wstring filename = env::media_folder() + L"\\" + params[0];\r
- \r
- auto ext = boost::find_if(extensions, [&](const std::wstring& ex)\r
- { \r
- return boost::filesystem::is_regular_file(boost::filesystem::wpath(filename + L"." + ex));\r
- });\r
+ auto filename = probe_stem(env::media_folder() + L"\\" + params.at(0));\r
\r
- if(ext == extensions.end())\r
+ if(filename.empty())\r
return core::frame_producer::empty();\r
-\r
- auto path = filename + L"." + *ext;\r
+ \r
auto loop = boost::range::find(params, L"LOOP") != params.end();\r
- auto start = core::get_param(L"SEEK", params, 0);\r
- auto length = core::get_param(L"LENGTH", params, std::numeric_limits<size_t>::max());\r
- auto filter_str = core::get_param<std::wstring>(L"FILTER", params, L""); \r
+ auto start = get_param(L"SEEK", params, static_cast<uint64_t>(0));\r
+ auto length = get_param(L"LENGTH", params, std::numeric_limits<uint64_t>::max());\r
+ auto filter_str = get_param(L"FILTER", params, L""); \r
\r
boost::replace_all(filter_str, L"DEINTERLACE", L"YADIF=0:-1");\r
boost::replace_all(filter_str, L"DEINTERLACE_BOB", L"YADIF=1:-1");\r
\r
- return create_producer_destroy_proxy(make_safe<ffmpeg_producer>(frame_factory, path, filter_str, loop, start, length));\r
+ return create_producer_destroy_proxy(make_safe<ffmpeg_producer>(frame_factory, filename, filter_str, loop, start, length));\r
}\r
\r
}}
\ No newline at end of file
\r
const std::wstring filename_;\r
tbb::atomic<bool> loop_;\r
- const size_t start_; \r
- const size_t length_;\r
+ const uint64_t start_; \r
+ const uint64_t length_;\r
size_t frame_number_;\r
\r
tbb::concurrent_bounded_queue<std::shared_ptr<AVPacket>> buffer_;\r
\r
tbb::recursive_mutex mutex_;\r
\r
- explicit implementation(const safe_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop, size_t start, size_t length) \r
+ explicit implementation(const safe_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop, int64_t start, int64_t length) \r
: graph_(graph)\r
, format_context_(open_input(filename)) \r
, default_stream_index_(av_find_default_stream_index(format_context_.get()))\r
}\r
};\r
\r
-input::input(const safe_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop, size_t start, size_t length) \r
+input::input(const safe_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop, int64_t start, int64_t length) \r
: impl_(new implementation(graph, filename, loop, start, length)){}\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
class input : boost::noncopyable\r
{\r
public:\r
- explicit input(const safe_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop, size_t start = 0, size_t length = std::numeric_limits<size_t>::max());\r
+ explicit input(const safe_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop, int64_t start, int64_t length);\r
\r
bool try_pop(std::shared_ptr<AVPacket>& packet);\r
bool eof() const;\r
\r
return boost::lexical_cast<std::wstring>(width) + L"x" + boost::lexical_cast<std::wstring>(height) + (!interlaced ? L"p" : L"i") + fps_ss.str();\r
}\r
+\r
+bool is_valid_file(const std::wstring filename)\r
+{ \r
+ auto filename2 = narrow(filename);\r
+\r
+ std::ifstream file(filename2);\r
+\r
+ std::vector<unsigned char> buf;\r
+ for(auto file_it = std::istreambuf_iterator<char>(file); file_it != std::istreambuf_iterator<char>() && buf.size() < 2048; ++file_it)\r
+ buf.push_back(*file_it);\r
+\r
+ if(buf.empty())\r
+ return nullptr;\r
+\r
+ AVProbeData pb;\r
+ pb.filename = filename2.c_str();\r
+ pb.buf = buf.data();\r
+ pb.buf_size = buf.size();\r
+\r
+ int score = 0;\r
+ return av_probe_input_format2(&pb, true, &score) != nullptr;\r
+}\r
+\r
+std::wstring probe_stem(const std::wstring stem)\r
+{\r
+ auto stem2 = boost::filesystem2::wpath(stem);\r
+ auto dir = stem2.parent_path();\r
+ for(auto it = boost::filesystem2::wdirectory_iterator(dir); it != boost::filesystem2::wdirectory_iterator(); ++it)\r
+ {\r
+ if(boost::iequals(it->path().stem(), stem2.filename()) && is_valid_file(it->path().file_string()))\r
+ return it->path().file_string();\r
+ }\r
+ return L"";\r
+}\r
//\r
//void av_dup_frame(AVFrame* frame)\r
//{\r
#include <core/producer/frame/pixel_format.h>\r
#include <core/mixer/audio/audio_mixer.h>\r
\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push)\r
-#pragma warning (disable : 4244)\r
-#endif\r
-extern "C" \r
-{\r
- #include <libavutil/pixfmt.h>\r
- #include <libavcodec/avcodec.h>\r
-}\r
-#if defined(_MSC_VER)\r
-#pragma warning (pop)\r
-#endif\r
-\r
+enum PixelFormat;\r
struct AVFrame;\r
struct AVFormatContext;\r
struct AVPacket;\r
+struct AVRational;\r
+struct AVCodecContext;\r
\r
namespace caspar {\r
\r
\r
// Utils\r
\r
-static const PixelFormat CASPAR_PIX_FMT_LUMA = PIX_FMT_MONOBLACK; // Just hijack some unual pixel format.\r
+static const int CASPAR_PIX_FMT_LUMA = 10; // Just hijack some unual pixel format.\r
\r
core::field_mode::type get_mode(const AVFrame& frame);\r
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
\r
std::wstring print_mode(size_t width, size_t height, double fps, bool interlaced);\r
\r
+std::wstring probe_stem(const std::wstring stem);\r
+bool is_valid_file(const std::wstring filename);\r
+\r
}}
\ No newline at end of file
#include <core/mixer/write_frame.h>\r
\r
#include <common/env.h>\r
+#include <common/log/log.h>\r
\r
#include <boost/assign.hpp>\r
#include <boost/filesystem.hpp>\r
std::copy_n(FreeImage_GetBits(bitmap.get()), frame->image_data().size(), frame->image_data().begin());\r
frame->commit();\r
frame_ = std::move(frame);\r
+\r
+ CASPAR_LOG(info) << print() << L" Initialized";\r
}\r
\r
// frame_producer\r
#include <core/mixer/write_frame.h>\r
\r
#include <common/env.h>\r
+#include <common/log/log.h>\r
#include <common/memory/memclr.h>\r
#include <common/exception/exceptions.h>\r
\r
start_offset_[0] = (std::ceil(static_cast<double>(width_) / static_cast<double>(format_desc_.width)) + 1.0) * 0.5;// - 1.5;\r
}\r
}\r
+\r
+ CASPAR_LOG(info) << print() << L" Initialized";\r
}\r
\r
// frame_producer\r
#include <modules/flash/util/swf.h>\r
#include <modules/flash/producer/flash_producer.h>\r
#include <modules/flash/producer/cg_producer.h>\r
+#include <modules/ffmpeg/producer/util/util.h>\r
\r
#include <algorithm>\r
#include <locale>\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
- else if(extension == TEXT(".SWF") || extension == TEXT(".DV") || extension == TEXT(".MOV") || extension == TEXT(".MPG") || \r
- extension == TEXT(".AVI") || extension == TEXT(".FLV") || extension == TEXT(".F4V") || extension == TEXT(".MP4") ||\r
- extension == L".M2V" || extension == L".H264" || extension == L".MKV" || extension == L".WMV" || extension == L".DIVX" || \r
- extension == L".XVID" || extension == L".OGG" || extension == L".CT" || extension == L".MXF")\r
- clipttype = TEXT(" MOVIE ");\r
else if(extension == TEXT(".WAV") || extension == TEXT(".MP3"))\r
clipttype = TEXT(" STILL ");\r
+ else if(caspar::ffmpeg::is_valid_file(path.file_string()) || extension == L".CT")\r
+ clipttype = TEXT(" MOVIE ");\r
\r
if(clipttype != TEXT(" N/A "))\r
{ \r
<ProjectReference Include="..\core\core.vcxproj">\r
<Project>{79388c20-6499-4bf6-b8b9-d8c33d7d4ddd}</Project>\r
</ProjectReference>\r
+ <ProjectReference Include="..\modules\ffmpeg\ffmpeg.vcxproj">\r
+ <Project>{f6223af3-be0b-4b61-8406-98922ce521c2}</Project>\r
+ </ProjectReference>\r
<ProjectReference Include="..\modules\flash\flash.vcxproj">\r
<Project>{816deaba-3757-4306-afe0-c27cf96c4dea}</Project>\r
</ProjectReference>\r
<channel>\r
<video-mode>PAL</video-mode>\r
<consumers>\r
- <bluefish>\r
+ <decklink>\r
<embedded-audio>true</embedded-audio>\r
- </bluefish>\r
- </consumers>\r
- </channel>\r
- <channel>\r
- <video-mode>PAL</video-mode>\r
- <consumers>\r
- <screen>\r
- <device>2</device>\r
- </screen>\r
- <system-audio></system-audio>\r
+ </decklink>\r
</consumers>\r
</channel>\r
</channels>\r