From 71440ed3c55b7c5dccd0533bd43d3d842cd00f60 Mon Sep 17 00:00:00 2001 From: Michael Fabian 'Xaymar' Dirks Date: Tue, 24 Sep 2019 16:00:53 +0200 Subject: [PATCH] encoder: Revert change 5c8939b4a83bca344a93a486faac944e880f90e2 Breaks more than intended, and this way is better anyway as the error that used to show up gave no indication as to what went wrong. With this reverted it now shows that starting encoding failed. --- source/encoder.cpp | 184 ++++++++++++++++++++------------------------- source/encoder.hpp | 7 +- 2 files changed, 84 insertions(+), 107 deletions(-) diff --git a/source/encoder.cpp b/source/encoder.cpp index 61ed130..6930f8e 100644 --- a/source/encoder.cpp +++ b/source/encoder.cpp @@ -333,7 +333,7 @@ obsffmpeg::encoder_factory::encoder_factory(const AVCodec* codec) : avcodec_ptr( info_fallback.oei.id = info_fallback.uid.c_str(); info_fallback.oei.codec = info.oei.codec; info_fallback.oei.caps = info.oei.caps; - info_fallback.oei.caps |= OBS_ENCODER_CAP_DEPRECATED; + //info_fallback.oei.caps |= OBS_ENCODER_CAP_DEPRECATED; info.oei.caps |= OBS_ENCODER_CAP_PASS_TEXTURE; } @@ -546,7 +546,7 @@ const obsffmpeg::encoder_info& obsffmpeg::encoder_factory::get_fallback() } obsffmpeg::encoder::encoder(obs_data_t* settings, obs_encoder_t* encoder, bool is_texture_encode) - : _self(encoder), _lag_in_frames(0), _count_send_frames(0), _have_first_frame(false), _initialized(false) + : _self(encoder), _lag_in_frames(0), _count_send_frames(0), _have_first_frame(false) { if (is_texture_encode) { throw obsffmpeg::unsupported_gpu_exception("not implemented yet"); @@ -594,8 +594,86 @@ obsffmpeg::encoder::encoder(obs_data_t* settings, obs_encoder_t* encoder, bool i // Update settings update(settings); + // Create 8MB of precached Packet data for use later on. av_init_packet(&_current_packet); av_new_packet(&_current_packet, 8 * 1024 * 1024); // 8 MB precached Packet size. + + if (_codec->type == AVMEDIA_TYPE_VIDEO) { + // Initialize Video Encoding + auto voi = video_output_get_info(obs_encoder_video(_self)); + + // Find a suitable Pixel Format. + AVPixelFormat _pixfmt_source = ffmpeg::tools::obs_videoformat_to_avpixelformat(voi->format); + AVPixelFormat _pixfmt_target = + static_cast(obs_data_get_int(settings, ST_FFMPEG_COLORFORMAT)); + if (_pixfmt_target == AV_PIX_FMT_NONE) { + // Find the best conversion format. + std::vector fmts = ffmpeg::tools::get_software_formats(_codec->pix_fmts); + _pixfmt_target = ffmpeg::tools::get_best_compatible_format(fmts.data(), _pixfmt_source); + } else { + // Use user override, guaranteed to be supported. + bool is_format_supported = false; + for (auto ptr = _codec->pix_fmts; *ptr != AV_PIX_FMT_NONE; ptr++) { + if (*ptr == _pixfmt_target) { + is_format_supported = true; + } + } + + if (!is_format_supported) { + std::stringstream sstr; + sstr << "Color Format '" << ffmpeg::tools::get_pixel_format_name(_pixfmt_target) + << "' is not supported by the encoder."; + throw std::exception(sstr.str().c_str()); + } + } + + _context->width = voi->width; + _context->height = voi->height; + _context->colorspace = ffmpeg::tools::obs_videocolorspace_to_avcolorspace(voi->colorspace); + _context->color_range = ffmpeg::tools::obs_videorangetype_to_avcolorrange(voi->range); + _context->pix_fmt = _pixfmt_target; + _context->field_order = AV_FIELD_PROGRESSIVE; + _context->time_base.num = voi->fps_den; + _context->time_base.den = voi->fps_num; + _context->ticks_per_frame = 1; + _context->sample_aspect_ratio.num = _context->sample_aspect_ratio.den = 1; + + _swscale.set_source_size(_context->width, _context->height); + _swscale.set_source_color(_context->color_range, _context->colorspace); + _swscale.set_source_full_range(voi->range == VIDEO_RANGE_FULL); + _swscale.set_source_format(_pixfmt_source); + + _swscale.set_target_size(_context->width, _context->height); + _swscale.set_target_color(_context->color_range, _context->colorspace); + _swscale.set_target_full_range(voi->range == VIDEO_RANGE_FULL); + _swscale.set_target_format(_pixfmt_target); + + // Create Scaler + if (!_swscale.initialize(SWS_POINT)) { + std::stringstream sstr; + sstr << "Initializing scaler failed for conversion from '" + << ffmpeg::tools::get_pixel_format_name(_swscale.get_source_format()) << "' to '" + << ffmpeg::tools::get_pixel_format_name(_swscale.get_target_format()) + << "' with color space '" + << ffmpeg::tools::get_color_space_name(_swscale.get_source_colorspace()) << "' and " + << (_swscale.is_source_full_range() ? "full" : "partial") << " range."; + throw std::runtime_error(sstr.str()); + } + } + + // Initialize Encoder + int res = avcodec_open2(_context, _codec, NULL); + if (res < 0) { + std::stringstream sstr; + sstr << "Initializing encoder '" << _codec->name + << "' failed with error: " << ffmpeg::tools::get_error_description(res) << " (code " << res << ")"; + throw std::runtime_error(sstr.str()); + } + + // Create Frame queue + _frame_queue.set_pixel_format(_context->pix_fmt); + _frame_queue.set_resolution(_context->width, _context->height); + _frame_queue.precache(2); } obsffmpeg::encoder::~encoder() @@ -622,84 +700,6 @@ obsffmpeg::encoder::~encoder() _swscale.finalize(); } -bool obsffmpeg::encoder::initialize() -{ - if (_initialized) - return true; - - // Detect supported - bool is_format_supported = false; - for (auto ptr = _codec->pix_fmts; *ptr != AV_PIX_FMT_NONE; ptr++) { - if (*ptr == _format) { - is_format_supported = true; - } - } - if (!is_format_supported) { - std::stringstream sstr; - sstr << "The color format " << ffmpeg::tools::get_pixel_format_name(_format) - << " is not supported by the encoder."; - throw std::exception(sstr.str().c_str()); - } - - if (_codec->type == AVMEDIA_TYPE_VIDEO) { - auto encvideo = obs_encoder_video(_self); - auto voi = video_output_get_info(encvideo); - - // Set Resolution - _context->width = static_cast(_resolution.first); - _context->height = static_cast(_resolution.second); - - // Set Color Space, Format and Range - _context->colorspace = ffmpeg::tools::obs_videocolorspace_to_avcolorspace(voi->colorspace); - _context->color_range = ffmpeg::tools::obs_videorangetype_to_avcolorrange(voi->range); - _context->pix_fmt = _format; - - // Set Framerate and Field Order - _context->field_order = AV_FIELD_PROGRESSIVE; - _context->time_base.num = voi->fps_den; - _context->time_base.den = voi->fps_num; - _context->ticks_per_frame = 1; - } - - // Initialize - int res = avcodec_open2(_context, _codec, NULL); - if (res < 0) { - std::stringstream sstr; - sstr << "Failed to initalized encoder '" << _codec->name - << "' due to error: " << ffmpeg::tools::get_error_description(res) << "(" << res << ")"; - throw std::runtime_error(sstr.str().c_str()); - } - - // Initialize Scaler and Frame Queue - if (_codec->type == AVMEDIA_TYPE_VIDEO) { - _swscale.set_source_format(_format); - _swscale.set_target_format(_context->pix_fmt); - _swscale.set_target_size(_context->width, _context->height); - _swscale.set_source_size(_context->width, _context->height); - _swscale.set_target_size(_context->width, _context->height); - _swscale.set_source_color(_context->color_range, _context->colorspace); - _swscale.set_target_color(_context->color_range, _context->colorspace); - - // Create Scaler - if (!_swscale.initialize(SWS_FAST_BILINEAR)) { - std::stringstream sstr; - sstr << "Failed to initialize frame scaler for pixel format '" - << ffmpeg::tools::get_pixel_format_name(_context->pix_fmt) << "' with color space '" - << ffmpeg::tools::get_color_space_name(_context->colorspace) << "' and " - << (_swscale.is_source_full_range() ? "full" : "partial") << " color range."; - throw std::runtime_error(sstr.str().c_str()); - } - - // Create Frame queue - _frame_queue.set_pixel_format(_context->pix_fmt); - _frame_queue.set_resolution(_context->width, _context->height); - _frame_queue.precache(2); - } - - _initialized = true; - return true; -} - void obsffmpeg::encoder::get_properties(obs_properties_t* props) { { // Handler @@ -769,18 +769,9 @@ bool obsffmpeg::encoder::audio_encode(encoder_frame*, encoder_packet*, bool*) void obsffmpeg::encoder::get_video_info(video_scale_info* vsi) { - obs_data_t* settings = obs_encoder_get_settings(_self); - - AVPixelFormat avformat = static_cast(obs_data_get_int(settings, ST_FFMPEG_COLORFORMAT)); - video_format obsformat = ffmpeg::tools::avpixelformat_to_obs_videoformat(avformat); - - if (obsformat != VIDEO_FORMAT_NONE) { - vsi->format = obsformat; - } - - _resolution.first = vsi->width; - _resolution.second = vsi->height; - _format = ffmpeg::tools::obs_videoformat_to_avpixelformat(vsi->format); + vsi->width = _swscale.get_source_width(); + vsi->height = _swscale.get_source_height(); + vsi->format = ffmpeg::tools::avpixelformat_to_obs_videoformat(_swscale.get_source_format()); } bool obsffmpeg::encoder::get_sei_data(uint8_t** data, size_t* size) @@ -835,15 +826,6 @@ static inline void copy_data(encoder_frame* frame, AVFrame* vframe) bool obsffmpeg::encoder::video_encode(encoder_frame* frame, encoder_packet* packet, bool* received_packet) { - // Ensure that the encoder was initialized. - try { - if (!initialize()) - return false; - } catch (std::exception& ex) { - PLOG_ERROR("%s", ex.what()); - return false; - } - // Convert frame. std::shared_ptr vframe = _frame_queue.pop(); // Retrieve an empty frame. { diff --git a/source/encoder.hpp b/source/encoder.hpp index d4930c4..7bcf84a 100644 --- a/source/encoder.hpp +++ b/source/encoder.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include "ffmpeg/avframe-queue.hpp" #include "ffmpeg/swscale.hpp" @@ -79,10 +80,6 @@ namespace obsffmpeg { const AVCodec* _codec; AVCodecContext* _context; - bool _initialized; - std::pair _resolution; - AVPixelFormat _format; - ffmpeg::avframe_queue _frame_queue; ffmpeg::avframe_queue _frame_queue_used; ffmpeg::swscale _swscale; @@ -100,8 +97,6 @@ namespace obsffmpeg { encoder(obs_data_t* settings, obs_encoder_t* encoder, bool is_texture_encode = false); virtual ~encoder(); - bool initialize(); - public: // OBS API // Shared void get_properties(obs_properties_t* props);