Skip to content

Commit

Permalink
Added color_trc, color_primaries, colorspace and color_range parsing.
Browse files Browse the repository at this point in the history
  • Loading branch information
ggarra13 committed Feb 23, 2024
1 parent b2a1792 commit d3bc740
Showing 1 changed file with 186 additions and 38 deletions.
224 changes: 186 additions & 38 deletions lib/tlIO/FFmpegWrite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ extern "C"

}

#define LOG_INFO(x) std::cout << " [save] " << x << std::endl;

namespace tl
{
namespace ffmpeg
Expand Down Expand Up @@ -210,34 +212,128 @@ namespace tl
}
return target;
}

AVColorRange parseColorRange(const std::string& s)
{
AVColorRange out = AVCOL_RANGE_UNSPECIFIED;
if (s == "mpeg" || s == "tv")
out = AVCOL_RANGE_MPEG;
else if (s == "jpeg" || s == "pc")
out = AVCOL_RANGE_JPEG;
return out;
}

//! Return the color space matrix coefficients for a string.
const int* parseYUVType(const char *s, enum AVColorSpace colorspace)
AVColorPrimaries parseColorPrimaries(const std::string& s)
{
if (!s)
s = "bt601";
AVColorPrimaries out = AVCOL_PRI_BT709;
if (s == "unspecified")
out = AVCOL_PRI_UNSPECIFIED;
else if (s == "reserved")
out = AVCOL_PRI_RESERVED;
else if (s == "bt470m")
out = AVCOL_PRI_BT470M;
else if (s == "bt470bg")
out = AVCOL_PRI_BT470BG;
else if (s == "smpte170m")
out = AVCOL_PRI_SMPTE170M;
else if (s == "smpte240m" || s == "smpte-c")
out = AVCOL_PRI_SMPTE240M;
else if (s == "film")
out = AVCOL_PRI_FILM;
else if (s == "bt2020")
out = AVCOL_PRI_BT2020;
else if (s == "smpte428")
out = AVCOL_PRI_SMPTE428;
else if (s == "smpte431")
out = AVCOL_PRI_SMPTE431;
else if (s == "smpte432")
out = AVCOL_PRI_SMPTE432;
else if (s == "ebu3213" || s == "jedec-p22")
out = AVCOL_PRI_EBU3213;
return out;
}

AVColorTransferCharacteristic parseColorTRC(const std::string& s)
{
AVColorTransferCharacteristic out = AVCOL_TRC_BT709;
if (s == "reserved")
out = AVCOL_TRC_RESERVED;
else if (s == "unspecified")
out = AVCOL_TRC_UNSPECIFIED;
else if (s == "gamma22")
out = AVCOL_TRC_GAMMA22;
else if (s == "gamma28")
out = AVCOL_TRC_GAMMA28;
else if (s == "smpte170m" || s == "bt601" || s == "bt1358")
out = AVCOL_TRC_SMPTE170M;
else if (s == "smpte240m")
out = AVCOL_TRC_SMPTE240M;
else if (s == "linear")
out = AVCOL_TRC_LINEAR;
else if (s == "log")
out = AVCOL_TRC_LOG;
else if (s == "logsqrt" || s == "log_sqrt")
out = AVCOL_TRC_LOG_SQRT;
else if (s == "iec61966-2-4")
out = AVCOL_TRC_IEC61966_2_4;
else if (s == "bt1361" || s == "bt1361-ecg")
out = AVCOL_TRC_BT1361_ECG;
else if (s == "iec61966-2-1")
out = AVCOL_TRC_IEC61966_2_1;
else if (s == "bt2020-10")
out = AVCOL_TRC_BT2020_10;
else if (s == "bt2020-12")
out = AVCOL_TRC_BT2020_12;
else if (s == "smpte2084")
out = AVCOL_TRC_SMPTE2084;
else if (s == "arib-std-b67")
out = AVCOL_TRC_ARIB_STD_B67;

return out;
}

if (s && strstr(s, "bt709"))
AVColorSpace parseColorSpace(const std::string& s)
{
AVColorSpace out = AVCOL_SPC_RGB;
if (s == "bt709")
{
colorspace = AVCOL_SPC_BT709;
out = AVCOL_SPC_BT709;
}
else if (s && strstr(s, "fcc"))
else if (s == "fcc")
{
colorspace = AVCOL_SPC_FCC;
out = AVCOL_SPC_FCC;
}
else if (s && strstr(s, "smpte240m"))
else if (s == "smpte240m")
{
colorspace = AVCOL_SPC_SMPTE240M;
out = AVCOL_SPC_SMPTE240M;
}
else if (s && (strstr(s, "bt601") || strstr(s, "bt470") ||
strstr(s, "smpte170m")))
else if (s == "bt601" || s == "bt470" ||
s == "smpte170m")
{
colorspace = AVCOL_SPC_BT470BG;
out = AVCOL_SPC_BT470BG;
}
else if (s == "bt2020")
{
out = AVCOL_SPC_BT2020_NCL;
}
else if (s && strstr(s, "bt2020"))
else if (s == "unspecified")
{
colorspace = AVCOL_SPC_BT2020_NCL;
out = AVCOL_SPC_UNSPECIFIED;
}
else if (s == "reserved")
{
out = AVCOL_SPC_RESERVED;
}
return out;
}

//! Return the color space matrix coefficients for a string.
const int* parseYUVType(const char *s, enum AVColorSpace colorspace)
{
if (!s)
s = "bt601";

colorspace = parseColorSpace(s);

if (colorspace < 1 || colorspace > 10 || colorspace == 8) {
colorspace = AVCOL_SPC_BT470BG;
Expand Down Expand Up @@ -587,7 +683,8 @@ namespace tl
}
}
}


std::string msg;
if (info.audio.isValid() && avAudioCodecID != AV_CODEC_ID_NONE)
{
if (!avCodec)
Expand Down Expand Up @@ -757,10 +854,10 @@ namespace tl
}

const std::string codecName = avCodec->name;
const std::string msg =
string::Format("Saving audio with '{1}' codec.")
.arg(codecName);
std::cout << " [save] " << msg << std::endl;
msg = string::Format("Saving audio with '{1}' codec.")
.arg(codecName);
LOG_INFO(msg);

r = avcodec_parameters_from_context(
p.avAudioStream->codecpar, p.avAudioCodecContext);
if (r < 0)
Expand Down Expand Up @@ -965,10 +1062,59 @@ namespace tl
p.avCodecContext->time_base = { rational.second, rational.first };
p.avCodecContext->framerate = { rational.first, rational.second };

p.avCodecContext->color_range = AVCOL_RANGE_JPEG; // Equivalent to -color_range pc (2)
p.avCodecContext->colorspace = AVCOL_SPC_BT709; // Equivalent to -colorspace bt709
p.avCodecContext->color_primaries = AVCOL_PRI_BT709; // Equivalent to -color_primaries bt709
p.avCodecContext->color_trc = AVCOL_TRC_IEC61966_2_1; // Equivalent to -color_trc iec61966-2-1
if (avCodecID == AV_CODEC_ID_PRORES)
{
// Equivalent to -color_range tv (1)
p.avCodecContext->color_range = AVCOL_RANGE_MPEG;
}
else
{
// Equivalent to -color_range pc (2)
p.avCodecContext->color_range = AVCOL_RANGE_JPEG;
}

option = options.find("FFmpeg/ColorRange");
if (option != options.end())
{
std::string value;
std::stringstream ss(option->second);
ss >> value;
p.avCodecContext->color_range = parseColorRange(value);
}

// Equivalent to -colorspace bt709
p.avCodecContext->colorspace = AVCOL_SPC_BT709;
option = options.find("FFmpeg/ColorSpace");
if (option != options.end())
{
std::string value;
std::stringstream ss(option->second);
ss >> value;
p.avCodecContext->colorspace = parseColorSpace(value);
}

// Equivalent to -color_primaries bt709
p.avCodecContext->color_primaries = AVCOL_PRI_BT709;
option = options.find("FFmpeg/ColorPrimaries");
if (option != options.end())
{
std::string value;
std::stringstream ss(option->second);
ss >> value;
p.avCodecContext->color_primaries =
parseColorPrimaries(value);
}

// Equivalent to -color_trc iec61966-2-1 (ie. sRGB)
p.avCodecContext->color_trc = AVCOL_TRC_IEC61966_2_1;
option = options.find("FFmpeg/ColorTRC");
if (option != options.end())
{
std::string value;
std::stringstream ss(option->second);
ss >> value;
p.avCodecContext->color_trc = parseColorTRC(value);
}

if (p.avFormatContext->oformat->flags & AVFMT_GLOBALHEADER)
{
Expand Down Expand Up @@ -1028,10 +1174,9 @@ namespace tl
}

const std::string codecName = avCodec->name;
const std::string msg =
string::Format("Saving video with '{1}' codec.")
.arg(codecName);
std::cout << " [save] " << msg << std::endl;
msg = string::Format("Saving video with '{1}' codec.")
.arg(codecName);
LOG_INFO(msg);

r = avcodec_open2(p.avCodecContext, avCodec, &codecOptions);
if (r < 0)
Expand Down Expand Up @@ -1180,15 +1325,12 @@ namespace tl
throw std::runtime_error(string::Format("{0}: Cannot initialize sws context").arg(p.fileName));
}

// If doing 8 bit conversions, rely on swscale to do the mapping as
// the libswscale filter.
if (p.avCodecContext->pix_fmt == AV_PIX_FMT_YUV420P ||
p.avCodecContext->pix_fmt == AV_PIX_FMT_YUVA420P ||
p.avCodecContext->pix_fmt == AV_PIX_FMT_YUV422P ||
p.avCodecContext->pix_fmt == AV_PIX_FMT_YUVA422P ||
p.avCodecContext->pix_fmt == AV_PIX_FMT_YUV444P ||
p.avCodecContext->pix_fmt == AV_PIX_FMT_YUVA444P)
// If doing 8 bit conversions, rely on swscale to do the
// mapping with libswscale (-vf scale filter emulated here).
if (avCodecID != AV_CODEC_ID_PRORES)
{
msg = "Using full color matrices and color coefficients";

// Handle matrices and color space details
int in_full, out_full, brightness, contrast, saturation;
const int *inv_table, *table;
Expand All @@ -1205,14 +1347,20 @@ namespace tl
// We use the full range, and we set -color_range to 2
// ( as we set AV_COL_RANGE_JPEG )
in_full =
p.avCodecContext->color_range == AVCOL_RANGE_JPEG;
(p.avCodecContext->color_range == AVCOL_RANGE_JPEG);
out_full =
p.avCodecContext->color_range == AVCOL_RANGE_JPEG;
(p.avCodecContext->color_range == AVCOL_RANGE_JPEG);

sws_setColorspaceDetails(
p.swsContext, inv_table, in_full, table, out_full,
brightness, contrast, saturation);
}
else
{
msg = "Not using full color matrices and color "
"coefficients.";
}
LOG_INFO(msg);
}

if (p.avFormatContext->nb_streams == 0)
Expand Down

0 comments on commit d3bc740

Please sign in to comment.