X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fffmpeg%2Fffmpeg.cpp;h=9f9dc549fcc8e57c86ae87793579a901b6588734;hb=b17a5351a13075978b5e5d4c817fb683224d9d38;hp=ad416eebdd6dbd6d243f9dec8b35ed4389cce796;hpb=cf0f4d2c469511037ff43fbd340ad4c1611c71ff;p=casparcg diff --git a/modules/ffmpeg/ffmpeg.cpp b/modules/ffmpeg/ffmpeg.cpp index ad416eebd..9f9dc549f 100644 --- a/modules/ffmpeg/ffmpeg.cpp +++ b/modules/ffmpeg/ffmpeg.cpp @@ -1,129 +1,293 @@ -/* -* copyright (c) 2010 Sveriges Television AB -* -* This file is part of CasparCG. -* -* CasparCG is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* CasparCG is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. - -* You should have received a copy of the GNU General Public License -* along with CasparCG. If not, see . -* -*/ -#include "StdAfx.h" - -#include "consumer/ffmpeg_consumer.h" -#include "producer/ffmpeg_producer.h" - -#include -#include - -#include - -#if defined(_MSC_VER) -#pragma warning (disable : 4244) -#endif - -extern "C" -{ - #define __STDC_CONSTANT_MACROS - #define __STDC_LIMIT_MACROS - #include - #include - #include - #include -} - -namespace caspar { - -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::mutex(); - break; - } - case AV_LOCK_OBTAIN: - { - if(my_mutex) - my_mutex->lock(); - break; - } - case AV_LOCK_RELEASE: - { - if(my_mutex) - my_mutex->unlock(); - break; - } - case AV_LOCK_DESTROY: - { - delete my_mutex; - *mutex = nullptr; - break; - } - } - return 0; -} - -void init_ffmpeg() -{ - av_register_all(); - avcodec_init(); - av_lockmgr_register(ffmpeg_lock_callback); - - core::register_consumer_factory([](const std::vector& params){return create_ffmpeg_consumer(params);}); - core::register_producer_factory(create_ffmpeg_producer); -} - -void uninit_ffmpeg() -{ - av_lockmgr_register(nullptr); -} - -std::wstring make_version(unsigned int ver) -{ - std::wstringstream str; - str << ((ver >> 16) & 0xFF) << L"." << ((ver >> 8) & 0xFF) << L"." << ((ver >> 0) & 0xFF); - return str.str(); -} - -std::wstring get_avcodec_version() -{ - return make_version(avcodec_version()); -} - -std::wstring get_avformat_version() -{ - return make_version(avformat_version()); -} - -std::wstring get_avutil_version() -{ - return make_version(avutil_version()); -} - -std::wstring get_avfilter_version() -{ - return make_version(avfilter_version()); -} - -std::wstring get_swscale_version() -{ - return make_version(swscale_version()); -} - -} \ No newline at end of file +/* +* Copyright (c) 2011 Sveriges Television AB +* +* This file is part of CasparCG (www.casparcg.com). +* +* CasparCG is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* CasparCG is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with CasparCG. If not, see . +* +* Author: Robert Nagy, ronag89@gmail.com +*/ + +#include "StdAfx.h" + +#include "ffmpeg.h" + +#include "consumer/ffmpeg_consumer.h" +#include "producer/ffmpeg_producer.h" +#include "producer/util/util.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#if defined(_MSC_VER) +#pragma warning (disable : 4244) +#pragma warning (disable : 4603) +#pragma warning (disable : 4996) +#endif + +extern "C" +{ + #define __STDC_CONSTANT_MACROS + #define __STDC_LIMIT_MACROS + #include + #include + #include + #include + #include +} + +namespace caspar { namespace ffmpeg { +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: + { + if(my_mutex) + my_mutex->lock(); + break; + } + case AV_LOCK_RELEASE: + { + if(my_mutex) + my_mutex->unlock(); + break; + } + case AV_LOCK_DESTROY: + { + delete my_mutex; + *mutex = nullptr; + break; + } + } + return 0; +} + +static void sanitize(uint8_t *line) +{ + while(*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 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 (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'; + + strcpy(prev, line); + sanitize((uint8_t*)line); + + auto len = strlen(line); + if(len > 0) + line[len-1] = 0; + + 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) +{ + std::wstringstream str; + str << ((ver >> 16) & 0xFF) << L"." << ((ver >> 8) & 0xFF) << L"." << ((ver >> 0) & 0xFF); + return str.str(); +} + +std::wstring avcodec_version() +{ + return make_version(::avcodec_version()); +} + +std::wstring avformat_version() +{ + return make_version(::avformat_version()); +} + +std::wstring avutil_version() +{ + return make_version(::avutil_version()); +} + +std::wstring avfilter_version() +{ + return make_version(::avfilter_version()); +} + +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_for_thread); + + avfilter_register_all(); + //fix_yadif_filter_format_query(); + av_register_all(); + 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_ffmpeg_consumer, describe_ffmpeg_consumer); + dependencies.consumer_registry->register_preconfigured_consumer_factory(L"ffmpeg", create_preconfigured_ffmpeg_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 + { + 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, true)) + return false; + + info.clip_type = L"MOVIE"; + + return try_get_duration(file, info.duration, info.time_base); + }); + dependencies.system_info_provider_repo->register_system_info_provider([](boost::property_tree::wptree& info) + { + info.add(L"system.ffmpeg.avcodec", avcodec_version()); + info.add(L"system.ffmpeg.avformat", avformat_version()); + info.add(L"system.ffmpeg.avfilter", avfilter_version()); + info.add(L"system.ffmpeg.avutil", avutil_version()); + info.add(L"system.ffmpeg.swscale", swscale_version()); + }); +} + +void uninit() +{ + avfilter_uninit(); + avformat_network_deinit(); + av_lockmgr_register(nullptr); +} +}}