diff --git a/source/encoder.cpp b/source/encoder.cpp index 0364f57..8ac76ba 100644 --- a/source/encoder.cpp +++ b/source/encoder.cpp @@ -632,25 +632,23 @@ obsffmpeg::encoder::encoder(obs_data_t* settings, obs_encoder_t* encoder, bool i } } - _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->width = voi->width; + _context->height = voi->height; + ffmpeg::tools::setup_obs_color(voi->colorspace, voi->range, _context); + _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; + _context->framerate.num = _context->time_base.den = voi->fps_num; + _context->framerate.den = _context->time_base.num = voi->fps_den; _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_color(_context->color_range == AVCOL_RANGE_JPEG, _context->colorspace); _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_color(_context->color_range == AVCOL_RANGE_JPEG, _context->colorspace); _swscale.set_target_format(_pixfmt_target); // Create Scaler @@ -679,8 +677,9 @@ obsffmpeg::encoder::encoder(obs_data_t* settings, obs_encoder_t* encoder, bool i ffmpeg::tools::get_pixel_format_name(_swscale.get_target_format()), ffmpeg::tools::get_color_space_name(_swscale.get_target_colorspace()), _swscale.is_target_full_range() ? "Full" : "Partial"); - PLOG_INFO("[%s] Framerate: %ld/%ld (%f", id, _context->time_base.num, _context->time_base.den, - _context->time_base.num / _context->time_base.den); + PLOG_INFO("[%s] Framerate: %ld/%ld (%f FPS)", id, _context->time_base.den, _context->time_base.num, + static_cast(_context->time_base.den) + / static_cast(_context->time_base.num)); } // Update settings @@ -866,11 +865,13 @@ bool obsffmpeg::encoder::video_encode(encoder_frame* frame, encoder_packet* pack ScopeProfiler profile("convert"); #endif - vframe->height = _context->height; - vframe->format = _context->pix_fmt; - vframe->color_range = _context->color_range; - vframe->colorspace = _context->colorspace; - vframe->pts = frame->pts; + vframe->height = _context->height; + vframe->format = _context->pix_fmt; + vframe->color_range = _context->color_range; + vframe->colorspace = _context->colorspace; + vframe->color_primaries = _context->color_primaries; + vframe->color_trc = _context->color_trc; + vframe->pts = frame->pts; if ((_swscale.is_source_full_range() == _swscale.is_target_full_range()) && (_swscale.get_source_colorspace() == _swscale.get_target_colorspace()) @@ -1016,6 +1017,9 @@ int obsffmpeg::encoder::receive_packet(bool* received_packet, struct encoder_pac } else if (_codec->id == AV_CODEC_ID_HEVC) { obsffmpeg::codecs::hevc::extract_header_sei(_current_packet.data, _current_packet.size, _extra_data, _sei_data); + } else if (_context->extradata != nullptr) { + _extra_data.resize(_context->extradata_size); + std::memcpy(_extra_data.data(), _context->extradata, _context->extradata_size); } _have_first_frame = true; } diff --git a/source/ffmpeg/tools.cpp b/source/ffmpeg/tools.cpp index fa04138..b86b18e 100644 --- a/source/ffmpeg/tools.cpp +++ b/source/ffmpeg/tools.cpp @@ -220,10 +220,10 @@ AVColorRange ffmpeg::tools::obs_videorangetype_to_avcolorrange(video_range_type { switch (v) { case VIDEO_RANGE_DEFAULT: - case VIDEO_RANGE_FULL: - return AVCOL_RANGE_JPEG; case VIDEO_RANGE_PARTIAL: return AVCOL_RANGE_MPEG; + case VIDEO_RANGE_FULL: + return AVCOL_RANGE_JPEG; } throw std::invalid_argument("unknown range"); } @@ -378,3 +378,36 @@ AVPixelFormat ffmpeg::tools::get_best_compatible_format(const AVPixelFormat* lis return best; } + +void ffmpeg::tools::setup_obs_color(video_colorspace colorspace, video_range_type range, AVCodecContext* context) +{ + std::map> + colorspaces = { + {VIDEO_CS_DEFAULT, {AVCOL_SPC_BT470BG, AVCOL_PRI_BT470BG, AVCOL_TRC_SMPTE170M}}, + {VIDEO_CS_601, {AVCOL_SPC_BT470BG, AVCOL_PRI_BT470BG, AVCOL_TRC_SMPTE170M}}, + {VIDEO_CS_709, {AVCOL_SPC_BT709, AVCOL_PRI_BT709, AVCOL_TRC_BT709}}, + }; + std::map colorranges = { + {VIDEO_RANGE_DEFAULT, AVCOL_RANGE_MPEG}, + {VIDEO_RANGE_PARTIAL, AVCOL_RANGE_MPEG}, + {VIDEO_RANGE_FULL, AVCOL_RANGE_JPEG}, + }; + + { + auto found = colorspaces.find(colorspace); + if (found != colorspaces.end()) { + context->colorspace = std::get(found->second); + context->color_primaries = std::get(found->second); + context->color_trc = std::get(found->second); + } + } + { + auto found = colorranges.find(range); + if (found != colorranges.end()) { + context->color_range = found->second; + } + } + + // Downscaling should result in downscaling, not pixelation + context->chroma_sample_location = AVCHROMA_LOC_CENTER; +} diff --git a/source/ffmpeg/tools.hpp b/source/ffmpeg/tools.hpp index 0437245..7348d30 100644 --- a/source/ffmpeg/tools.hpp +++ b/source/ffmpeg/tools.hpp @@ -28,8 +28,8 @@ #include extern "C" { -#include #include +#include } namespace ffmpeg { @@ -57,6 +57,8 @@ namespace ffmpeg { std::vector get_software_formats(const AVPixelFormat* list); AVPixelFormat get_best_compatible_format(const AVPixelFormat* list, AVPixelFormat source); + + void setup_obs_color(video_colorspace colorspace, video_range_type range, AVCodecContext* context); } // namespace tools } // namespace ffmpeg