From: Steinar H. Gunderson Date: Sun, 15 Jan 2017 20:05:39 +0000 (+0100) Subject: Add a flag to output Y'CbCr using Rec. 709 coefficients. X-Git-Tag: 1.5.0~74 X-Git-Url: https://git.sesse.net/?p=nageru;a=commitdiff_plain;h=498987ac24daccf573b385107540f12929eb89b2 Add a flag to output Y'CbCr using Rec. 709 coefficients. We will be needing this for HDMI/SDI output. --- diff --git a/flags.cpp b/flags.cpp index 1983c75..02ea81b 100644 --- a/flags.cpp +++ b/flags.cpp @@ -46,7 +46,8 @@ enum LongOption { OPTION_DISABLE_ALSA_OUTPUT, OPTION_NO_FLUSH_PBOS, OPTION_PRINT_VIDEO_LATENCY, - OPTION_AUDIO_QUEUE_LENGTH_MS + OPTION_AUDIO_QUEUE_LENGTH_MS, + OPTION_OUTPUT_YCBCR_COEFFICIENTS }; void usage() @@ -102,6 +103,8 @@ void usage() fprintf(stderr, " possible to run with apitrace in real time)\n"); fprintf(stderr, " --print-video-latency print out measurements of video latency on stdout\n"); fprintf(stderr, " --audio-queue-length-ms length of audio resampling queue (default 100.0)\n"); + fprintf(stderr, " --output-ycbcr-coefficients={rec601,rec709}\n"); + fprintf(stderr, " Y'CbCr coefficient standard of output (default rec601)\n"); } void parse_flags(int argc, char * const argv[]) @@ -149,9 +152,11 @@ void parse_flags(int argc, char * const argv[]) { "no-flush-pbos", no_argument, 0, OPTION_NO_FLUSH_PBOS }, { "print-video-latency", no_argument, 0, OPTION_PRINT_VIDEO_LATENCY }, { "audio-queue-length-ms", required_argument, 0, OPTION_AUDIO_QUEUE_LENGTH_MS }, + { "output-ycbcr-coefficients", required_argument, 0, OPTION_OUTPUT_YCBCR_COEFFICIENTS }, { 0, 0, 0, 0 } }; vector theme_dirs; + string output_ycbcr_coefficients = "rec601"; for ( ;; ) { int option_index = 0; int c = getopt_long(argc, argv, "c:t:I:v:m:M:w:h:", long_options, &option_index); @@ -304,6 +309,9 @@ void parse_flags(int argc, char * const argv[]) case OPTION_AUDIO_QUEUE_LENGTH_MS: global_flags.audio_queue_length_ms = atof(optarg); break; + case OPTION_OUTPUT_YCBCR_COEFFICIENTS: + output_ycbcr_coefficients = optarg; + break; case OPTION_HELP: usage(); exit(0); @@ -353,4 +361,13 @@ void parse_flags(int argc, char * const argv[]) exit(1); } } + + if (output_ycbcr_coefficients == "rec709") { + global_flags.ycbcr_rec709_coefficients = true; + } else if (output_ycbcr_coefficients == "rec601") { + global_flags.ycbcr_rec709_coefficients = false; + } else { + fprintf(stderr, "ERROR: --output-ycbcr-coefficients must be “rec601” or “rec709”\n"); + exit(1); + } } diff --git a/flags.h b/flags.h index b3e676d..06b08d1 100644 --- a/flags.h +++ b/flags.h @@ -42,6 +42,7 @@ struct Flags { std::string midi_mapping_filename; // Empty for none. bool print_video_latency = false; double audio_queue_length_ms = 100.0; + bool ycbcr_rec709_coefficients = false; }; extern Flags global_flags; diff --git a/quicksync_encoder.cpp b/quicksync_encoder.cpp index 749eb63..875b264 100644 --- a/quicksync_encoder.cpp +++ b/quicksync_encoder.cpp @@ -322,6 +322,7 @@ void QuickSyncEncoderImpl::sps_rbsp(bitstream *bs) if ( false ) { bitstream_put_ui(bs, 0, 1); /* vui_parameters_present_flag */ } else { + // See H.264 annex E for the definition of this header. 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 */ @@ -333,7 +334,11 @@ void QuickSyncEncoderImpl::sps_rbsp(bitstream *bs) { bitstream_put_ui(bs, 1, 8); /* colour_primaries (1 = BT.709) */ bitstream_put_ui(bs, 2, 8); /* transfer_characteristics (2 = unspecified, since we use sRGB) */ - bitstream_put_ui(bs, 6, 8); /* matrix_coefficients (6 = BT.601/SMPTE 170M) */ + if (global_flags.ycbcr_rec709_coefficients) { + bitstream_put_ui(bs, 1, 8); /* matrix_coefficients (1 = BT.709) */ + } else { + bitstream_put_ui(bs, 6, 8); /* matrix_coefficients (6 = BT.601/SMPTE 170M) */ + } } } bitstream_put_ui(bs, 0, 1); /* chroma_loc_info_present_flag */ diff --git a/theme.cpp b/theme.cpp index ef63576..24c6cdc 100644 --- a/theme.cpp +++ b/theme.cpp @@ -265,13 +265,11 @@ int EffectChain_finalize(lua_State* L) // happens in a pass not run by Movit (see ChromaSubsampler::subsample_chroma()). output_ycbcr_format.chroma_subsampling_x = 1; output_ycbcr_format.chroma_subsampling_y = 1; - - // Rec. 709 would be the sane thing to do, but it seems many players - // (e.g. MPlayer and VLC) just default to BT.601 coefficients no matter - // what (see discussions in e.g. https://trac.ffmpeg.org/ticket/4978). - // We _do_ set the right flags, though, so that a player that works - // properly doesn't have to guess. - output_ycbcr_format.luma_coefficients = YCBCR_REC_601; + if (global_flags.ycbcr_rec709_coefficients) { + output_ycbcr_format.luma_coefficients = YCBCR_REC_709; + } else { + output_ycbcr_format.luma_coefficients = YCBCR_REC_601; + } output_ycbcr_format.full_range = false; output_ycbcr_format.num_levels = 256; diff --git a/x264_encoder.cpp b/x264_encoder.cpp index fcd20e7..f9b5624 100644 --- a/x264_encoder.cpp +++ b/x264_encoder.cpp @@ -101,13 +101,16 @@ void X264Encoder::init_x264() param.i_frame_reference = 16; // Because speedcontrol is never allowed to change this above what we set at start. } - // NOTE: These should be in sync with the ones in h264encode.cpp (sbs_rbsp()). + // NOTE: These should be in sync with the ones in quicksync_encoder.cpp (sps_rbsp()). param.vui.i_vidformat = 5; // Unspecified. param.vui.b_fullrange = 0; param.vui.i_colorprim = 1; // BT.709. param.vui.i_transfer = 2; // Unspecified (since we use sRGB). - param.vui.i_colmatrix = 6; // BT.601/SMPTE 170M. - + if (global_flags.ycbcr_rec709_coefficients) { + param.vui.i_colmatrix = 1; // BT.709. + } else { + param.vui.i_colmatrix = 6; // BT.601/SMPTE 170M. + } param.rc.i_rc_method = X264_RC_ABR; param.rc.i_bitrate = global_flags.x264_bitrate;