From 345b65e8f95fba76164f9ac8e1304138fd984b3d Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Sun, 1 Nov 2015 15:30:20 +0100 Subject: [PATCH] Fix a bunch of colorspace issues, after practical testing. There is still some left in the output, though. --- h264encode.cpp | 12 +++++++++++- httpd.cpp | 11 +++++++++++ theme.cpp | 17 ++++++++++++++--- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/h264encode.cpp b/h264encode.cpp index 55ed9a1..d63fe89 100644 --- a/h264encode.cpp +++ b/h264encode.cpp @@ -340,7 +340,17 @@ static void sps_rbsp(bitstream *bs) bitstream_put_ui(bs, 1, 1); /* vui_parameters_present_flag */ bitstream_put_ui(bs, 0, 1); /* aspect_ratio_info_present_flag */ bitstream_put_ui(bs, 0, 1); /* overscan_info_present_flag */ - bitstream_put_ui(bs, 0, 1); /* video_signal_type_present_flag */ + bitstream_put_ui(bs, 1, 1); /* video_signal_type_present_flag */ + { + bitstream_put_ui(bs, 5, 3); /* video_format (5 = Unspecified) */ + bitstream_put_ui(bs, 0, 1); /* video_full_range_flag */ + bitstream_put_ui(bs, 1, 1); /* colour_description_present_flag */ + { + bitstream_put_ui(bs, 1, 8); /* colour_primaries (1 = BT.709) */ + bitstream_put_ui(bs, 1, 8); /* transfer_characteristics (1 = BT.709) */ + bitstream_put_ui(bs, 1, 8); /* matrix_coefficients (1 = BT.709) */ + } + } bitstream_put_ui(bs, 0, 1); /* chroma_loc_info_present_flag */ bitstream_put_ui(bs, 1, 1); /* timing_info_present_flag */ { diff --git a/httpd.cpp b/httpd.cpp index 38e685e..de0af8e 100644 --- a/httpd.cpp +++ b/httpd.cpp @@ -89,6 +89,17 @@ HTTPD::Mux::Mux(AVFormatContext *avctx, int width, int height) avstream_video->codec->time_base = AVRational{1, TIMEBASE}; avstream_video->codec->ticks_per_frame = 1; // or 2? + // Colorspace details. Closely correspond to settings in EffectChain_finalize, + // as noted in each comment. + // Note that the H.264 stream also contains this information and depending on the + // mux, this might simply get ignored. See sps_rbsp(). + avstream_video->codec->color_primaries = AVCOL_PRI_BT709; // RGB colorspace (inout_format.color_space). + avstream_video->codec->color_trc = AVCOL_TRC_BT709; // Gamma curve (inout_format.gamma_curve). + avstream_video->codec->colorspace = AVCOL_SPC_BT709; // YUV colorspace (output_ycbcr_format.luma_coefficients). + avstream_video->codec->color_range = AVCOL_RANGE_MPEG; // Full vs. limited range (output_ycbcr_format.full_range). + avstream_video->codec->chroma_sample_location = AVCHROMA_LOC_LEFT; // Chroma sample location. See chroma_offset_0[] in Mixer::subsample_chroma(). + avstream_video->codec->field_order = AV_FIELD_PROGRESSIVE; + AVCodec *codec_audio = avcodec_find_encoder(AV_CODEC_ID_MP3); avstream_audio = avformat_new_stream(avctx, codec_audio); if (avstream_audio == nullptr) { diff --git a/theme.cpp b/theme.cpp index 767abac..56d5f84 100644 --- a/theme.cpp +++ b/theme.cpp @@ -123,15 +123,21 @@ int EffectChain_finalize(lua_State* L) bool is_main_chain = checkbool(L, 2); // Add outputs as needed. + // NOTE: If you change any details about the output format, you will need to + // also update what's given to the muxer (HTTPD::Mux constructor) and + // what's put in the H.264 stream (sps_rbsp()). ImageFormat inout_format; - inout_format.color_space = COLORSPACE_sRGB; - inout_format.gamma_curve = GAMMA_sRGB; + inout_format.color_space = COLORSPACE_REC_709; + inout_format.gamma_curve = GAMMA_REC_709; if (is_main_chain) { YCbCrFormat output_ycbcr_format; + // We actually output 4:2:0 in the end, but chroma subsampling + // happens in a pass not run by Movit (see Mixer::subsample_chroma()). output_ycbcr_format.chroma_subsampling_x = 1; output_ycbcr_format.chroma_subsampling_y = 1; output_ycbcr_format.luma_coefficients = YCBCR_REC_709; output_ycbcr_format.full_range = false; + output_ycbcr_format.num_levels = 256; chain->add_ycbcr_output(inout_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, output_ycbcr_format, YCBCR_OUTPUT_SPLIT_Y_AND_CBCR); chain->set_dither_bits(8); @@ -319,6 +325,11 @@ LiveInputWrapper::LiveInputWrapper(Theme *theme, EffectChain *chain, bool overri inout_format.color_space = COLORSPACE_sRGB; inout_format.gamma_curve = GAMMA_sRGB; + // The Blackmagic driver docs claim that the device outputs Y'CbCr + // according to Rec. 601, but practical testing indicates it definitely + // is Rec. 709 (at least up to errors attributable to rounding errors). + // Perhaps 601 was only to indicate the subsampling positions, not the + // colorspace itself? Tested with a Lenovo X1 gen 3 as input. YCbCrFormat input_ycbcr_format; input_ycbcr_format.chroma_subsampling_x = 2; input_ycbcr_format.chroma_subsampling_y = 1; @@ -326,7 +337,7 @@ LiveInputWrapper::LiveInputWrapper(Theme *theme, EffectChain *chain, bool overri input_ycbcr_format.cr_x_position = 0.0; input_ycbcr_format.cb_y_position = 0.5; input_ycbcr_format.cr_y_position = 0.5; - input_ycbcr_format.luma_coefficients = YCBCR_REC_601; + input_ycbcr_format.luma_coefficients = YCBCR_REC_709; input_ycbcr_format.full_range = false; if (override_bounce) { -- 2.39.2