diff mbox

[FFmpeg-devel,3/4] vf_tonemap_opencl: Move update_metadata() to a shared file

Message ID 20180725154640.89762-3-vittorio.giovara@gmail.com
State Accepted
Commit 572ef567a5288d36b8bc2531309710a0e891d35c
Headers show

Commit Message

Vittorio Giovara July 25, 2018, 3:46 p.m. UTC
---
 libavfilter/colorspace.c        | 17 +++++++++++++++++
 libavfilter/colorspace.h        |  1 +
 libavfilter/vf_tonemap_opencl.c | 19 +------------------
 3 files changed, 19 insertions(+), 18 deletions(-)

Comments

James Almer Aug. 6, 2018, 7:21 p.m. UTC | #1
On 7/25/2018 12:46 PM, Vittorio Giovara wrote:
> ---
>  libavfilter/colorspace.c        | 17 +++++++++++++++++
>  libavfilter/colorspace.h        |  1 +
>  libavfilter/vf_tonemap_opencl.c | 19 +------------------
>  3 files changed, 19 insertions(+), 18 deletions(-)
> 
> diff --git a/libavfilter/colorspace.c b/libavfilter/colorspace.c
> index d6f6055401..c6682216d6 100644
> --- a/libavfilter/colorspace.c
> +++ b/libavfilter/colorspace.c
> @@ -118,3 +118,20 @@ double ff_determine_signal_peak(AVFrame *in)
>  
>      return peak;
>  }
> +
> +void ff_update_hdr_metadata(AVFrame *in, double peak)
> +{
> +    AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL);
> +
> +    if (sd) {
> +        AVContentLightMetadata *clm = (AVContentLightMetadata *)sd->data;
> +        clm->MaxCLL = (unsigned)(peak * REFERENCE_WHITE);
> +    }
> +
> +    sd = av_frame_get_side_data(in, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA);
> +    if (sd) {
> +        AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data;
> +        if (metadata->has_luminance)
> +            metadata->max_luminance = av_d2q(peak * REFERENCE_WHITE, 10000);
> +    }
Frame side data is refcounted, so this is not correct. I'm not sure if a
side data element is ever modified in-place long after being created to
being with, aside from this function here.

Easiest option is to call av_buffer_make_writable() on sd->buf and
updating the sd->data pointer before modifying the fields in question,
but such manual handling of side data seems improper and fragile.
I guess another option is av_mastering_display_metadata_alloc(), copy
the values, av_frame_remove_side_data(), av_buffer_create(), then
av_frame_new_side_data_from_buf().

Honestly, i think we may have to add a make_writable() function for side
data for this.
Mark Thompson Aug. 6, 2018, 7:52 p.m. UTC | #2
On 06/08/18 20:21, James Almer wrote:
> On 7/25/2018 12:46 PM, Vittorio Giovara wrote:
>> ---
>>  libavfilter/colorspace.c        | 17 +++++++++++++++++
>>  libavfilter/colorspace.h        |  1 +
>>  libavfilter/vf_tonemap_opencl.c | 19 +------------------
>>  3 files changed, 19 insertions(+), 18 deletions(-)
>>
>> diff --git a/libavfilter/colorspace.c b/libavfilter/colorspace.c
>> index d6f6055401..c6682216d6 100644
>> --- a/libavfilter/colorspace.c
>> +++ b/libavfilter/colorspace.c
>> @@ -118,3 +118,20 @@ double ff_determine_signal_peak(AVFrame *in)
>>  
>>      return peak;
>>  }
>> +
>> +void ff_update_hdr_metadata(AVFrame *in, double peak)
>> +{
>> +    AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL);
>> +
>> +    if (sd) {
>> +        AVContentLightMetadata *clm = (AVContentLightMetadata *)sd->data;
>> +        clm->MaxCLL = (unsigned)(peak * REFERENCE_WHITE);
>> +    }
>> +
>> +    sd = av_frame_get_side_data(in, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA);
>> +    if (sd) {
>> +        AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data;
>> +        if (metadata->has_luminance)
>> +            metadata->max_luminance = av_d2q(peak * REFERENCE_WHITE, 10000);
>> +    }
> Frame side data is refcounted, so this is not correct. I'm not sure if a
> side data element is ever modified in-place long after being created to
> being with, aside from this function here.
> 
> Easiest option is to call av_buffer_make_writable() on sd->buf and
> updating the sd->data pointer before modifying the fields in question,
> but such manual handling of side data seems improper and fragile.
> I guess another option is av_mastering_display_metadata_alloc(), copy
> the values, av_frame_remove_side_data(), av_buffer_create(), then
> av_frame_new_side_data_from_buf().
> 
> Honestly, i think we may have to add a make_writable() function for side
> data for this.

The frame side-data was already copied for the output frame by av_frame_copy_props(), so modifying it here is fine.  (I had exactly the same thought when this code appeared in tonemap_opencl.)

- Mark
James Almer Aug. 6, 2018, 8:15 p.m. UTC | #3
On 8/6/2018 4:52 PM, Mark Thompson wrote:
> On 06/08/18 20:21, James Almer wrote:
>> On 7/25/2018 12:46 PM, Vittorio Giovara wrote:
>>> ---
>>>  libavfilter/colorspace.c        | 17 +++++++++++++++++
>>>  libavfilter/colorspace.h        |  1 +
>>>  libavfilter/vf_tonemap_opencl.c | 19 +------------------
>>>  3 files changed, 19 insertions(+), 18 deletions(-)
>>>
>>> diff --git a/libavfilter/colorspace.c b/libavfilter/colorspace.c
>>> index d6f6055401..c6682216d6 100644
>>> --- a/libavfilter/colorspace.c
>>> +++ b/libavfilter/colorspace.c
>>> @@ -118,3 +118,20 @@ double ff_determine_signal_peak(AVFrame *in)
>>>  
>>>      return peak;
>>>  }
>>> +
>>> +void ff_update_hdr_metadata(AVFrame *in, double peak)
>>> +{
>>> +    AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL);
>>> +
>>> +    if (sd) {
>>> +        AVContentLightMetadata *clm = (AVContentLightMetadata *)sd->data;
>>> +        clm->MaxCLL = (unsigned)(peak * REFERENCE_WHITE);
>>> +    }
>>> +
>>> +    sd = av_frame_get_side_data(in, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA);
>>> +    if (sd) {
>>> +        AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data;
>>> +        if (metadata->has_luminance)
>>> +            metadata->max_luminance = av_d2q(peak * REFERENCE_WHITE, 10000);
>>> +    }
>> Frame side data is refcounted, so this is not correct. I'm not sure if a
>> side data element is ever modified in-place long after being created to
>> being with, aside from this function here.
>>
>> Easiest option is to call av_buffer_make_writable() on sd->buf and
>> updating the sd->data pointer before modifying the fields in question,
>> but such manual handling of side data seems improper and fragile.
>> I guess another option is av_mastering_display_metadata_alloc(), copy
>> the values, av_frame_remove_side_data(), av_buffer_create(), then
>> av_frame_new_side_data_from_buf().
>>
>> Honestly, i think we may have to add a make_writable() function for side
>> data for this.
> 
> The frame side-data was already copied for the output frame by av_frame_copy_props(), so modifying it here is fine.  (I had exactly the same thought when this code appeared in tonemap_opencl.)
> 
> - Mark

Ah, good. I guess the ff_update_hdr_metadata() doxy should in any case
point that the frame or at least its side data must be writable to
prevent other uses in the future where this may not be taken into
account, now that it's shared.

And an actual, generic solution like a make_writable function is imo
still a good idea, unless the user is expected to use
av_frame_make_writable() if they want to do *any* kind of in-place
change to the frame.
diff mbox

Patch

diff --git a/libavfilter/colorspace.c b/libavfilter/colorspace.c
index d6f6055401..c6682216d6 100644
--- a/libavfilter/colorspace.c
+++ b/libavfilter/colorspace.c
@@ -118,3 +118,20 @@  double ff_determine_signal_peak(AVFrame *in)
 
     return peak;
 }
+
+void ff_update_hdr_metadata(AVFrame *in, double peak)
+{
+    AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL);
+
+    if (sd) {
+        AVContentLightMetadata *clm = (AVContentLightMetadata *)sd->data;
+        clm->MaxCLL = (unsigned)(peak * REFERENCE_WHITE);
+    }
+
+    sd = av_frame_get_side_data(in, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA);
+    if (sd) {
+        AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data;
+        if (metadata->has_luminance)
+            metadata->max_luminance = av_d2q(peak * REFERENCE_WHITE, 10000);
+    }
+}
diff --git a/libavfilter/colorspace.h b/libavfilter/colorspace.h
index 75705ecfc7..936681815a 100644
--- a/libavfilter/colorspace.h
+++ b/libavfilter/colorspace.h
@@ -45,5 +45,6 @@  void ff_fill_rgb2xyz_table(const struct PrimaryCoefficients *coeffs,
                            double rgb2xyz[3][3]);
 
 double ff_determine_signal_peak(AVFrame *in);
+void ff_update_hdr_metadata(AVFrame *in, double peak);
 
 #endif
diff --git a/libavfilter/vf_tonemap_opencl.c b/libavfilter/vf_tonemap_opencl.c
index 7455ebb9fb..5da2333169 100644
--- a/libavfilter/vf_tonemap_opencl.c
+++ b/libavfilter/vf_tonemap_opencl.c
@@ -21,7 +21,6 @@ 
 #include "libavutil/bprint.h"
 #include "libavutil/common.h"
 #include "libavutil/imgutils.h"
-#include "libavutil/mastering_display_metadata.h"
 #include "libavutil/mem.h"
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
@@ -342,22 +341,6 @@  fail:
     return err;
 }
 
-static void update_metadata(AVFrame *in, double peak) {
-    AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL);
-
-    if (sd) {
-        AVContentLightMetadata *clm = (AVContentLightMetadata *)sd->data;
-        clm->MaxCLL = (unsigned)(peak * REFERENCE_WHITE);
-    }
-
-    sd = av_frame_get_side_data(in, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA);
-    if (sd) {
-        AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data;
-        if (metadata->has_luminance)
-            metadata->max_luminance =av_d2q(peak * REFERENCE_WHITE, 10000);
-    }
-}
-
 static int tonemap_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input)
 {
     AVFilterContext    *avctx = inlink->dst;
@@ -444,7 +427,7 @@  static int tonemap_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input)
 
     av_frame_free(&input);
 
-    update_metadata(output, ctx->target_peak);
+    ff_update_hdr_metadata(output, ctx->target_peak);
 
     av_log(ctx, AV_LOG_DEBUG, "Tone-mapping output: %s, %ux%u (%"PRId64").\n",
            av_get_pix_fmt_name(output->format),