Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/framework/chain_normalizers.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
# the second and third are applied as applicable).

# image links
color=color_transform
deinterlace=avdeinterlace,deinterlace
fieldorder=fieldorder
crop=movit.crop,crop:1
Expand Down
8 changes: 8 additions & 0 deletions src/framework/mlt.vers
Original file line number Diff line number Diff line change
Expand Up @@ -678,3 +678,11 @@ MLT_7.34.0 {
mlt_image_color_pri_name;
mlt_image_color_pri_id;
} MLT_7.32.0;

MLT_7.36.0 {
global:
mlt_image_default_colorspace;
mlt_image_default_trc;
mlt_image_default_primaries;
mlt_color_convert_trc;
} MLT_7.34.0;
38 changes: 37 additions & 1 deletion src/framework/mlt_consumer.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* \brief abstraction for all consumer services
* \see mlt_consumer_s
*
* Copyright (C) 2003-2023 Meltytech, LLC
* Copyright (C) 2003-2025 Meltytech, LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
Expand All @@ -21,6 +21,7 @@
*/

#include "mlt_consumer.h"
#include "mlt_cache.h"
#include "mlt_factory.h"
#include "mlt_frame.h"
#include "mlt_log.h"
Expand Down Expand Up @@ -309,6 +310,9 @@ static void mlt_consumer_property_changed(mlt_properties owner,
mlt_profile profile = mlt_service_profile(MLT_CONSUMER_SERVICE(self));
if (profile)
profile->colorspace = mlt_properties_get_int(properties, "colorspace");
} else if (!strcmp(name, "mlt_color_trc")) {
mlt_properties properties = MLT_CONSUMER_PROPERTIES(self);
mlt_properties_clear(properties, "_ct_filter");
}
}

Expand Down Expand Up @@ -682,12 +686,43 @@ mlt_frame mlt_consumer_get_frame(mlt_consumer self)
mlt_properties_set(frame_properties,
"consumer.color_trc",
mlt_properties_get(properties, "color_trc"));
mlt_properties_set(frame_properties,
"consumer.mlt_color_trc",
mlt_properties_get(properties, "mlt_color_trc"));
mlt_properties_set(frame_properties,
"consumer.channel_layout",
mlt_properties_get(properties, "channel_layout"));
mlt_properties_set(frame_properties,
"consumer.color_range",
mlt_properties_get(properties, "color_range"));

if (mlt_properties_get(properties, "mlt_color_trc")) {
// Add a normalize filter to convert the mlt_color_trc to color_trc
mlt_filter ct_filter = (mlt_filter) mlt_properties_get_data(properties,
"_ct_filter",
NULL);
if (!ct_filter) {
mlt_profile profile = mlt_service_profile(service);
ct_filter = mlt_factory_filter(profile, "color_transform", NULL);
if (ct_filter) {
mlt_properties cs_properties = MLT_FILTER_PROPERTIES(ct_filter);
const char *color_trc_str = mlt_properties_get(properties, "color_trc");
mlt_color_trc trc = mlt_image_color_trc_id(color_trc_str);
if (trc == mlt_color_trc_none)
trc = mlt_image_default_trc(profile->colorspace);
mlt_properties_set_int(cs_properties, "force_trc", trc);
Comment thread
ddennedy marked this conversation as resolved.
mlt_properties_set_data(properties,
"_ct_filter",
ct_filter,
0,
(mlt_destructor) mlt_filter_close,
NULL);
}
}
if (ct_filter) {
mlt_filter_process(ct_filter, frame);
}
}
}

// Return the frame
Expand Down Expand Up @@ -1716,6 +1751,7 @@ void mlt_consumer_close(mlt_consumer self)

pthread_mutex_destroy(&priv->position_mutex);

mlt_service_cache_purge(&self->parent);
mlt_service_close(&self->parent);
free(priv);
}
Expand Down
1 change: 1 addition & 0 deletions src/framework/mlt_consumer.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
* \properties \em drop_count the number of video frames not rendered since starting consumer
* \properties \em color_range the color range as tv/mpeg (limited) or pc/jpeg (full); default is unset, which implies tv/mpeg
* \properties \em color_trc the color transfer characteristic (gamma), default is unset, use mlt_color_trc string values
* \properties \em mlt_color_trc the color transfer to use for internal processing, default is unset; use mlt_color_trc string values but only "linear" is implemented
* \properties \em deinterlacer the deinterlace algorithm to pass to deinterlace filters, defaults to "yadif"
*/

Expand Down
117 changes: 117 additions & 0 deletions src/framework/mlt_image.c
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,123 @@ mlt_color_primaries mlt_image_color_pri_id(const char *name)
return mlt_color_pri_none;
}

/** Get the default colorspace for a given image format.
*
* \public \memberof mlt_image_s
* \param format the format
* \param height the image height. Pass 0 if you do not know.
* \return a colorspace
*/

mlt_colorspace mlt_image_default_colorspace(mlt_image_format format, int height)
{
mlt_colorspace colorspace = mlt_colorspace_bt709;
switch (format) {
case mlt_image_rgb:
case mlt_image_rgba:
case mlt_image_rgba64:
case mlt_image_movit:
case mlt_image_opengl_texture:
colorspace = mlt_colorspace_rgb;
break;
case mlt_image_yuv422:
case mlt_image_yuv420p:
case mlt_image_yuv422p16:
case mlt_image_yuv420p10:
case mlt_image_yuv444p10:
if (height < 576) {
// Assume NTSC
colorspace = mlt_colorspace_smpte170m;
} else if (height < 720) {
// Assume PAL
colorspace = mlt_colorspace_bt470bg;
} else {
// Assume HDTV
colorspace = mlt_colorspace_bt709;
}
break;
case mlt_image_none:
case mlt_image_invalid:
break;
}
return colorspace;
}

/** Get the default color transfer characteristics for a given colorspace.
*
* \public \memberof mlt_image_s
* \param colorspace the colorspace
* \return a color trc
*/

mlt_color_trc mlt_image_default_trc(mlt_colorspace colorspace)
{
switch (colorspace) {
case mlt_colorspace_rgb:
return mlt_color_trc_iec61966_2_1;
case mlt_colorspace_bt709:
return mlt_color_trc_bt709;
case mlt_colorspace_bt470bg:
return mlt_color_trc_gamma28;
case mlt_colorspace_smpte170m:
return mlt_color_trc_smpte170m;
case mlt_colorspace_smpte240m:
return mlt_color_trc_smpte240m;
case mlt_colorspace_bt2020_ncl:
return mlt_color_trc_bt2020_10;
case mlt_colorspace_bt2020_cl:
return mlt_color_trc_bt2020_10;
case mlt_colorspace_bt601:
return mlt_color_trc_smpte170m;
case mlt_colorspace_smpte2085:
case mlt_colorspace_fcc:
case mlt_colorspace_ycgco:
case mlt_colorspace_unspecified:
case mlt_colorspace_reserved:
case mlt_colorspace_invalid:
break;
}
return mlt_color_trc_bt709;
}

/** Get the default color primaries for a given colorspace.
*
* \public \memberof mlt_image_s
* \param colorspace the colorspace
* \param height the image height. Pass 0 if you do not know.
* \return a color primaries
*/

mlt_color_primaries mlt_image_default_primaries(mlt_colorspace colorspace, int height)
{
switch (colorspace) {
case mlt_colorspace_rgb:
case mlt_colorspace_bt709:
return mlt_color_pri_bt709;
case mlt_colorspace_bt470bg:
return mlt_color_pri_bt470bg;
case mlt_colorspace_smpte170m:
return mlt_color_pri_smpte170m;
case mlt_colorspace_smpte240m:
return mlt_color_pri_smpte170m;
case mlt_colorspace_bt2020_ncl:
return mlt_color_pri_bt2020;
case mlt_colorspace_bt2020_cl:
return mlt_color_pri_bt2020;
case mlt_colorspace_bt601:
return height >= 576 ? mlt_color_pri_bt470bg : mlt_color_pri_smpte170m;
case mlt_colorspace_fcc:
return mlt_color_pri_bt470m;
case mlt_colorspace_smpte2085:
case mlt_colorspace_ycgco:
case mlt_colorspace_unspecified:
case mlt_colorspace_reserved:
case mlt_colorspace_invalid:
break;
}
return mlt_color_pri_bt709;
}

/** Fill an image with black.
*
* \bug This does not respect full range YUV if needed.
Expand Down
3 changes: 3 additions & 0 deletions src/framework/mlt_image.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ MLT_EXPORT const char *mlt_image_colorspace_name(mlt_colorspace colorspace);
MLT_EXPORT mlt_colorspace mlt_image_colorspace_id(const char *name);
MLT_EXPORT const char *mlt_image_color_pri_name(mlt_color_primaries primaries);
MLT_EXPORT mlt_color_primaries mlt_image_color_pri_id(const char *name);
MLT_EXPORT mlt_colorspace mlt_image_default_colorspace(mlt_image_format format, int height);
MLT_EXPORT mlt_color_trc mlt_image_default_trc(mlt_colorspace colorspace);
MLT_EXPORT mlt_color_primaries mlt_image_default_primaries(mlt_colorspace colorspace, int height);
MLT_EXPORT int mlt_image_rgba_opaque(uint8_t *image, int width, int height);
MLT_EXPORT int mlt_image_full_range(const char *color_range);

Expand Down
38 changes: 37 additions & 1 deletion src/framework/mlt_types.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* \file mlt_types.c
* \brief Mlt types helper functions
*
* Copyright (C) 2023 Meltytech, LLC
* Copyright (C) 2023-2025 Meltytech, LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
Expand All @@ -21,6 +21,9 @@

#include "mlt_types.h"

#include "mlt_image.h"

#include <math.h>
#include <stdlib.h>
#include <string.h>

Expand Down Expand Up @@ -63,3 +66,36 @@ mlt_deinterlacer mlt_deinterlacer_id(const char *name)
}
return mlt_deinterlacer_invalid;
}

static uint8_t srgb_to_linear(uint8_t value)
{
// Normalize the 8-bit value to the [0.0, 1.0] range
double factor = (double) value / 255.0;
if (factor < 0.04045) {
factor *= 0.0773993808;
} else {
factor = pow(factor * 0.9478672986 + 0.0521327014, 2.4);
}
// Map back to 0-255 range
double linear_value = round((double) 255 * factor);
return (uint8_t) CLAMP(linear_value, 0.0, 255.0);
}

/** Convert a standard sRGB color value to the specified TRC (Transfer Characteristics).
*
* \param color a standard sRGB color value
* \param trc_name a string representing the TRC to convert to
* \return the converted color
*/

mlt_color mlt_color_convert_trc(mlt_color color, const char *trc_name)
{
mlt_color_trc trc = mlt_image_color_trc_id(trc_name);
// Only linear is supported for now.
if (trc == mlt_color_trc_linear) {
color.r = srgb_to_linear(color.r);
color.g = srgb_to_linear(color.g);
color.b = srgb_to_linear(color.b);
}
return color;
}
1 change: 1 addition & 0 deletions src/framework/mlt_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ MLT_EXPORT char *strptime(const char *buf, const char *fmt, struct tm *tm);

MLT_EXPORT const char *mlt_deinterlacer_name(mlt_deinterlacer method);
MLT_EXPORT mlt_deinterlacer mlt_deinterlacer_id(const char *name);
MLT_EXPORT mlt_color mlt_color_convert_trc(mlt_color color, const char *trc_name);

#ifdef __cplusplus
}
Expand Down
49 changes: 2 additions & 47 deletions src/modules/avformat/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -582,59 +582,14 @@ mlt_color_primaries av_to_mlt_color_primaries(int primaries)
return mlt_color_pri_none;
}

mlt_color_primaries mlt_color_primaries_from_colorspace(mlt_colorspace colorspace, int height)
{
switch (colorspace) {
case mlt_colorspace_rgb: // sRGB
case mlt_colorspace_bt709:
return mlt_color_pri_bt709;
case mlt_colorspace_bt470bg:
return mlt_color_pri_bt470bg;
case mlt_colorspace_smpte240m:
return mlt_color_pri_smpte170m;
case mlt_colorspace_bt601:
return height == 576 ? mlt_color_pri_bt470bg : mlt_color_pri_smpte170m;
case mlt_colorspace_smpte170m:
return mlt_color_pri_smpte170m;
case mlt_colorspace_bt2020_ncl:
return mlt_color_pri_bt2020;
case mlt_colorspace_unspecified:
case mlt_colorspace_reserved:
case mlt_colorspace_fcc:
case mlt_colorspace_ycgco:
case mlt_colorspace_bt2020_cl:
case mlt_colorspace_smpte2085:
case mlt_colorspace_invalid:
break;
}
return mlt_color_pri_none;
}

int mlt_to_av_color_range(int full_range)
{
return full_range ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
}

mlt_color_trc mlt_color_trc_from_colorspace(mlt_colorspace colorspace)
int av_to_mlt_full_range(int color_range)
{
switch (colorspace) {
case mlt_colorspace_bt709:
return mlt_color_trc_bt709;
case mlt_colorspace_bt470bg:
return mlt_color_trc_gamma28;
case mlt_colorspace_smpte240m:
return mlt_color_trc_smpte240m;
case mlt_colorspace_rgb: // sRGB
return mlt_color_trc_iec61966_2_1;
case mlt_colorspace_bt601:
case mlt_colorspace_smpte170m:
return mlt_color_trc_smpte170m;
case mlt_colorspace_bt2020_ncl:
return mlt_color_trc_bt2020_10;
default:
break;
}
return mlt_color_trc_none;
return color_range == AVCOL_RANGE_JPEG;
}

void mlt_image_to_avframe(mlt_image image, mlt_frame mltframe, AVFrame *avframe)
Expand Down
5 changes: 2 additions & 3 deletions src/modules/avformat/common.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* common.h
* Copyright (C) 2018-2024 Meltytech, LLC
* Copyright (C) 2018-2025 Meltytech, LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
Expand Down Expand Up @@ -50,9 +50,8 @@ int mlt_to_av_colorspace(mlt_colorspace colorspace, int height);
mlt_colorspace av_to_mlt_colorspace(int colorspace, int width, int height);
int mlt_to_av_color_primaries(mlt_color_primaries primaries);
mlt_color_primaries av_to_mlt_color_primaries(int primaries);
mlt_color_primaries mlt_color_primaries_from_colorspace(mlt_colorspace colorspace, int height);
mlt_color_trc mlt_color_trc_from_colorspace(mlt_colorspace colorspace);
int mlt_to_av_color_range(int full_range);
int av_to_mlt_full_range(int color_range);
void mlt_image_to_avframe(mlt_image image, mlt_frame mltframe, AVFrame *avframe);
void avframe_to_mlt_image(AVFrame *avframe, mlt_image image);

Expand Down
Loading