Skip to content

Commit

Permalink
colorspace: add HDR10+ metadata to pl_hdr_metadata
Browse files Browse the repository at this point in the history
Based on SMPTE ST2094, and in particular A/341 ATSC 2094-40. We should
keep track of this so we can add it to the metadata and use it for
things like ST2094-10 and ST2094-40.

We don't default these value if missing, because their presence should
indicate the availability of frame-specific metadata.
  • Loading branch information
haasn committed Feb 13, 2023
1 parent a8135f4 commit 0994b6e
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 6 deletions.
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ project('libplacebo', ['c', 'cpp'],
5,
# API version
{
'242': 'add `pl_hdr_metadata.scene_max/avg` and `pl_hdr_metadata.ootf`',
'241': 'add `pl_plane_data.swapped`',
'240': 'add `PL_COLOR_TRC_ST428`',
'239': 'add `pl_fmt.planes` and `pl_tex.planes`',
Expand Down
28 changes: 27 additions & 1 deletion src/colorspace.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,14 +287,29 @@ const struct pl_hdr_metadata pl_hdr_metadata_hdr10 ={
.max_fall = 0, // unknown
};

static inline bool pl_hdr_bezier_equal(const struct pl_hdr_bezier *a,
const struct pl_hdr_bezier *b)
{
return a->target_luma == b->target_luma &&
a->knee_x == b->knee_x &&
a->knee_y == b->knee_y &&
a->num_anchors == b->num_anchors &&
!memcmp(a->anchors, b->anchors, sizeof(a->anchors[0]) * a->num_anchors);
}

bool pl_hdr_metadata_equal(const struct pl_hdr_metadata *a,
const struct pl_hdr_metadata *b)
{
return pl_raw_primaries_equal(&a->prim, &b->prim) &&
a->min_luma == b->min_luma &&
a->max_luma == b->max_luma &&
a->max_cll == b->max_cll &&
a->max_fall == b->max_fall;
a->max_fall == b->max_fall &&
a->scene_max[0] == b->scene_max[0] &&
a->scene_max[1] == b->scene_max[1] &&
a->scene_max[2] == b->scene_max[2] &&
a->scene_avg == b->scene_avg &&
pl_hdr_bezier_equal(&a->ootf, &b->ootf);
}

void pl_hdr_metadata_merge(struct pl_hdr_metadata *orig,
Expand All @@ -309,6 +324,12 @@ void pl_hdr_metadata_merge(struct pl_hdr_metadata *orig,
orig->max_cll = update->max_cll;
if (!orig->max_fall)
orig->max_fall = update->max_fall;
if (!orig->scene_max[1])
memcpy(orig->scene_max, update->scene_max, sizeof(orig->scene_max));
if (!orig->scene_avg)
orig->scene_avg = update->scene_avg;
if (!orig->ootf.target_luma)
orig->ootf = update->ootf;
}

const struct pl_color_space pl_color_space_unknown = {0};
Expand Down Expand Up @@ -409,6 +430,10 @@ void pl_color_space_infer(struct pl_color_space *space)
space->hdr.min_luma = space->sig_floor * PL_COLOR_SDR_WHITE;
space->sig_floor = 0;
}
if (space->sig_avg) {
space->hdr.scene_avg = space->sig_avg * PL_COLOR_SDR_WHITE;
space->sig_avg = 0;
}

reinfer_peaks:
if (space->hdr.max_luma < 1 || space->hdr.max_luma > 10000) {
Expand Down Expand Up @@ -448,6 +473,7 @@ void pl_color_space_infer(struct pl_color_space *space)
if (space->sig_scale && !pl_color_transfer_is_hdr(space->transfer)) {
space->hdr.max_luma *= space->sig_scale;
space->hdr.min_luma *= space->sig_scale;
space->hdr.scene_avg *= space->sig_scale;
space->sig_scale = 0;
}

Expand Down
23 changes: 18 additions & 5 deletions src/include/libplacebo/colorspace.h
Original file line number Diff line number Diff line change
Expand Up @@ -328,17 +328,30 @@ void pl_raw_primaries_merge(struct pl_raw_primaries *orig,
// Returns the raw primaries for a given color space.
const struct pl_raw_primaries *pl_raw_primaries_get(enum pl_color_primaries prim);

// Bezier curve for HDR metadata
struct pl_hdr_bezier {
float target_luma; // target luminance (cd/m²) for this OOTF
float knee_x, knee_y; // cross-over knee point (0-1)
float anchors[15]; // intermediate bezier curve control points (0-1)
uint8_t num_anchors;
};

// Represents raw HDR metadata as defined by SMPTE 2086 / CTA 861.3, which is
// often attached to HDR sources and can be forwarded to HDR-capable displays,
// or used to guide the libplacebo built-in tone mapping.
struct pl_hdr_metadata {
// Mastering display metadata. This is used for tone-mapping.
struct pl_raw_primaries prim; // mastering display primaries
float min_luma, max_luma; // min/max luminance (in cd/m²)
struct pl_raw_primaries prim; // mastering display primaries
float min_luma, max_luma; // min/max luminance (in cd/m²)

// Content light level. This is ignored by libplacebo itself.
float max_cll; // max content light level (in cd/m²)
float max_fall; // max frame average light level (in cd/m²)
float max_cll; // max content light level (in cd/m²)
float max_fall; // max frame average light level (in cd/m²)

// HDR10+ dynamic metadata (per-scene)
float scene_max[3]; // maxSCL in cd/m² per component (RGB)
float scene_avg; // average of maxRGB in cd/m²
struct pl_hdr_bezier ootf; // reference OOTF (optional)
};

extern const struct pl_hdr_metadata pl_hdr_metadata_empty; // equal to {0}
Expand Down Expand Up @@ -389,7 +402,7 @@ struct pl_color_space {
// Deprecated fields
enum pl_color_light light PL_DEPRECATED; // ignored
float sig_peak PL_DEPRECATED; // replaced by `hdr.max_luma`
float sig_avg PL_DEPRECATED; // ignored
float sig_avg PL_DEPRECATED; // replaced by `hdr.scene_avg`
float sig_floor PL_DEPRECATED; // replaced by `hdr.min_luma`
float sig_scale PL_DEPRECATED; // merged into `hdr.max/min_luma`
};
Expand Down

0 comments on commit 0994b6e

Please sign in to comment.