X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fffmpeg%2Fffmpeg.cpp;h=0b9f8611f1a120aa42c82a2deca83c971e1f82d2;hb=5246e27a85b8309b43aac1b9b9cbbff83e1a599a;hp=66ebb1c9c957f7a37edb0b4588a6eee0561307eb;hpb=3eccdaf715845deac4c9b3afbef48a2eb3efa99a;p=casparcg diff --git a/modules/ffmpeg/ffmpeg.cpp b/modules/ffmpeg/ffmpeg.cpp index 66ebb1c9c..0b9f8611f 100644 --- a/modules/ffmpeg/ffmpeg.cpp +++ b/modules/ffmpeg/ffmpeg.cpp @@ -29,14 +29,18 @@ #include "producer/util/util.h" #include +#include #include +#include #include #include #include #include #include +#include +#include #include @@ -46,7 +50,7 @@ #pragma warning (disable : 4996) #endif -extern "C" +extern "C" { #define __STDC_CONSTANT_MACROS #define __STDC_LIMIT_MACROS @@ -54,155 +58,108 @@ extern "C" #include #include #include + #include } namespace caspar { namespace ffmpeg { - -int ffmpeg_lock_callback(void **mutex, enum AVLockOp op) -{ +int ffmpeg_lock_callback(void **mutex, enum AVLockOp op) +{ if(!mutex) return 0; auto my_mutex = reinterpret_cast(*mutex); - - switch(op) - { - case AV_LOCK_CREATE: - { - *mutex = new tbb::recursive_mutex(); - break; - } - case AV_LOCK_OBTAIN: - { + + switch(op) + { + case AV_LOCK_CREATE: + { + *mutex = new tbb::recursive_mutex(); + break; + } + case AV_LOCK_OBTAIN: + { if(my_mutex) - my_mutex->lock(); - break; - } - case AV_LOCK_RELEASE: - { + my_mutex->lock(); + break; + } + case AV_LOCK_RELEASE: + { if(my_mutex) - my_mutex->unlock(); - break; - } - case AV_LOCK_DESTROY: - { + my_mutex->unlock(); + break; + } + case AV_LOCK_DESTROY: + { delete my_mutex; *mutex = nullptr; - break; - } - } - return 0; -} + break; + } + } + return 0; +} static void sanitize(uint8_t *line) { - while(*line) + while(*line) { - if(*line < 0x08 || (*line > 0x0D && *line < 0x20)) - *line='?'; - line++; - } + if(*line < 0x08 || (*line > 0x0D && *line < 0x20)) + *line='?'; + line++; + } } void log_callback(void* ptr, int level, const char* fmt, va_list vl) { - static int print_prefix=1; - //static int count; - static char prev[1024]; - char line[8192]; - //static int is_atty; - AVClass* avc= ptr ? *(AVClass**)ptr : NULL; - if(level > av_log_get_level()) - return; - line[0]=0; - + static int print_prefix=1; + static char prev[1024]; + char line[8192]; + AVClass* avc= ptr ? *(AVClass**)ptr : NULL; + if (level > AV_LOG_DEBUG) + return; + line[0]=0; + #undef fprintf - if(print_prefix && avc) + if(print_prefix && avc) { - if (avc->parent_log_context_offset) + if (avc->parent_log_context_offset) { - AVClass** parent= *(AVClass***)(((uint8_t*)ptr) + avc->parent_log_context_offset); - if(parent && *parent) - std::sprintf(line, "[%s @ %p] ", (*parent)->item_name(parent), parent); - } - std::sprintf(line + strlen(line), "[%s @ %p] ", avc->item_name(ptr), ptr); - } - - std::vsprintf(line + strlen(line), fmt, vl); - - print_prefix = strlen(line) && line[strlen(line)-1] == '\n'; - - //if(print_prefix && !strcmp(line, prev)){ - // count++; - // if(is_atty==1) - // fprintf(stderr, " Last message repeated %d times\r", count); - // return; - //} - //if(count>0){ - // fprintf(stderr, " Last message repeated %d times\n", count); - // count=0; - //} - strcpy(prev, line); - sanitize((uint8_t*)line); + AVClass** parent= *(AVClass***)(((uint8_t*)ptr) + avc->parent_log_context_offset); + if(parent && *parent) + std::sprintf(line, "[%s @ %p] ", (*parent)->item_name(parent), parent); + } + std::sprintf(line + strlen(line), "[%s @ %p] ", avc->item_name(ptr), ptr); + } + + std::vsprintf(line + strlen(line), fmt, vl); + + print_prefix = strlen(line) && line[strlen(line)-1] == '\n'; + + strcpy(prev, line); + sanitize((uint8_t*)line); auto len = strlen(line); if(len > 0) line[len-1] = 0; - - if(level == AV_LOG_DEBUG) - CASPAR_LOG(debug) << L"[ffmpeg] " << line; - else if(level == AV_LOG_INFO) - CASPAR_LOG(info) << L"[ffmpeg] " << line; - else if(level == AV_LOG_WARNING) - CASPAR_LOG(warning) << L"[ffmpeg] " << line; - else if(level == AV_LOG_ERROR) - CASPAR_LOG(error) << L"[ffmpeg] " << line; - else if(level == AV_LOG_FATAL) - CASPAR_LOG(fatal) << L"[ffmpeg] " << line; - else - CASPAR_LOG(trace) << L"[ffmpeg] " << line; - - //colored_fputs(av_clip(level>>3, 0, 6), line); -} -//static int query_yadif_formats(AVFilterContext *ctx) -//{ -// static const int pix_fmts[] = { -// PIX_FMT_YUV444P, -// PIX_FMT_YUV422P, -// PIX_FMT_YUV420P, -// PIX_FMT_YUV410P, -// PIX_FMT_YUV411P, -// PIX_FMT_GRAY8, -// PIX_FMT_YUVJ444P, -// PIX_FMT_YUVJ422P, -// PIX_FMT_YUVJ420P, -// AV_NE( PIX_FMT_GRAY16BE, PIX_FMT_GRAY16LE ), -// PIX_FMT_YUV440P, -// PIX_FMT_YUVJ440P, -// AV_NE( PIX_FMT_YUV444P16BE, PIX_FMT_YUV444P16LE ), -// AV_NE( PIX_FMT_YUV422P16BE, PIX_FMT_YUV422P16LE ), -// AV_NE( PIX_FMT_YUV420P16BE, PIX_FMT_YUV420P16LE ), -// PIX_FMT_YUVA420P, -// PIX_FMT_NONE -// }; -// avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts)); -// -// return 0; -//} -// -//#pragma warning (push) -//#pragma warning (disable : 4706) -//void fix_yadif_filter_format_query() -//{ -// AVFilter** filter = nullptr; -// while((filter = av_filter_next(filter)) && *filter) -// { -// if(strstr((*filter)->name, "yadif") != 0) -// (*filter)->query_formats = query_yadif_formats; -// } -//} -//#pragma warning (pop) + try + { + if (level == AV_LOG_VERBOSE) + CASPAR_LOG(debug) << L"[ffmpeg] " << line; + else if (level == AV_LOG_INFO) + CASPAR_LOG(info) << L"[ffmpeg] " << line; + else if (level == AV_LOG_WARNING) + CASPAR_LOG(warning) << L"[ffmpeg] " << line; + else if (level == AV_LOG_ERROR) + CASPAR_LOG(error) << L"[ffmpeg] " << line; + else if (level == AV_LOG_FATAL) + CASPAR_LOG(fatal) << L"[ffmpeg] " << line; + else + CASPAR_LOG(trace) << L"[ffmpeg] " << line; + } + catch (...) + { + } +} std::wstring make_version(unsigned int ver) { @@ -235,36 +192,85 @@ std::wstring swscale_version() { return make_version(::swscale_version()); } +bool& get_quiet_logging_for_thread() +{ + static boost::thread_specific_ptr quiet_logging_for_thread; + + auto local = quiet_logging_for_thread.get(); + + if (!local) + { + local = new bool(false); + quiet_logging_for_thread.reset(local); + } + + return *local; +} + +void enable_quiet_logging_for_thread() +{ + get_quiet_logging_for_thread() = true; +} + +bool is_logging_quiet_for_thread() +{ + return get_quiet_logging_for_thread(); +} + +std::shared_ptr temporary_enable_quiet_logging_for_thread(bool enable) +{ + if (!enable || is_logging_quiet_for_thread()) + return std::shared_ptr(); + + get_quiet_logging_for_thread() = true; + + return std::shared_ptr(nullptr, [](void*) + { + get_quiet_logging_for_thread() = false; // Only works correctly if destructed in same thread as original caller. + }); +} + +void log_for_thread(void* ptr, int level, const char* fmt, va_list vl) +{ + ensure_gpf_handler_installed_for_thread("ffmpeg-thread"); + + int min_level = is_logging_quiet_for_thread() ? AV_LOG_DEBUG : AV_LOG_FATAL; + + log_callback(ptr, std::max(level, min_level), fmt, vl); +} void init(core::module_dependencies dependencies) { av_lockmgr_register(ffmpeg_lock_callback); - av_log_set_callback(log_callback); + av_log_set_callback(log_for_thread); - avfilter_register_all(); + avfilter_register_all(); //fix_yadif_filter_format_query(); av_register_all(); - avformat_network_init(); - avcodec_register_all(); - - core::register_consumer_factory(create_consumer); - core::register_consumer_factory(create_streaming_consumer); - core::register_preconfigured_consumer_factory(L"file", create_preconfigured_consumer); - core::register_preconfigured_consumer_factory(L"stream", create_preconfigured_streaming_consumer); - dependencies.producer_registry->register_producer_factory(create_producer); - - dependencies.media_info_repo->register_extractor( + avformat_network_init(); + avcodec_register_all(); + avdevice_register_all(); + + auto info_repo = dependencies.media_info_repo; + + dependencies.consumer_registry->register_consumer_factory(L"FFmpeg Consumer", create_consumer, describe_consumer); + dependencies.consumer_registry->register_consumer_factory(L"Streaming Consumer", create_streaming_consumer, describe_streaming_consumer); + dependencies.consumer_registry->register_preconfigured_consumer_factory(L"file", create_preconfigured_consumer); + dependencies.consumer_registry->register_preconfigured_consumer_factory(L"stream", create_preconfigured_streaming_consumer); + dependencies.producer_registry->register_producer_factory(L"FFmpeg Producer", boost::bind(&create_producer, _1, _2, info_repo), describe_producer); + dependencies.producer_registry->register_thumbnail_producer(boost::bind(&create_thumbnail_frame, _1, _2, info_repo)); + + info_repo->register_extractor( [](const std::wstring& file, const std::wstring& extension, core::media_info& info) -> bool { - // TODO: merge thumbnail generation from 2.0 - //auto disable_logging = temporary_disable_logging_for_thread(true); + auto quiet_logging = temporary_enable_quiet_logging_for_thread(true); if (extension == L".WAV" || extension == L".MP3") { info.clip_type = L"AUDIO"; return true; } - if (!is_valid_file(file)) + if (!is_valid_file(file, true)) return false; info.clip_type = L"MOVIE"; @@ -284,8 +290,7 @@ void init(core::module_dependencies dependencies) void uninit() { avfilter_uninit(); - avformat_network_deinit(); + avformat_network_deinit(); av_lockmgr_register(nullptr); } - -}} \ No newline at end of file +}}