[FFmpeg-devel] [PATCH] optionally write QuickTime gama atom (was Re: Gamma function)

wm4 nfxjfg at googlemail.com
Tue Mar 3 14:05:51 CET 2015


On Tue, 3 Mar 2015 11:10:54 +0000
Kevin Wheatley <kevin.j.wheatley at gmail.com> wrote:

> From 794c8c3cf1e8506393fbcb4ddf1360042b0fc82f Mon Sep 17 00:00:00 2001
> From: Kevin Wheatley <kevin.j.wheatley at gmail.com>
> Date: Mon, 2 Mar 2015 12:50:53 +0000
> Subject: [PATCH] Add 'gama' atom for .mov only, reuses pngenc.c gamma values by sharing
>  function in new color_utils.[ch] file.
> 
> Use lrint() instead of round()
> 
> Signed-off-by: Kevin Wheatley <kevin.j.wheatley at gmail.com>
> ---
>  libavcodec/pngenc.c     |   29 +++----------------------
>  libavformat/movenc.c    |   35 +++++++++++++++++++++++++++++++
>  libavformat/movenc.h    |    2 +
>  libavutil/Makefile      |    2 +
>  libavutil/color_utils.c |   52 +++++++++++++++++++++++++++++++++++++++++++++++
>  libavutil/color_utils.h |   29 ++++++++++++++++++++++++++
>  6 files changed, 124 insertions(+), 25 deletions(-)
>  create mode 100644 libavutil/color_utils.c
>  create mode 100644 libavutil/color_utils.h
> 
> diff --git a/libavcodec/pngenc.c b/libavcodec/pngenc.c
> index 4e67ce2..fddcca4 100644
> --- a/libavcodec/pngenc.c
> +++ b/libavcodec/pngenc.c
> @@ -28,6 +28,7 @@
>  #include "libavutil/avassert.h"
>  #include "libavutil/libm.h"
>  #include "libavutil/opt.h"
> +#include "libavutil/color_utils.h"
>  
>  #include <zlib.h>
>  
> @@ -277,31 +278,9 @@ static int png_get_chrm(enum AVColorPrimaries prim,  uint8_t *buf)
>  
>  static int png_get_gama(enum AVColorTransferCharacteristic trc, uint8_t *buf)
>  {
> -    double gamma;
> -    switch (trc) {
> -        case AVCOL_TRC_BT709:
> -        case AVCOL_TRC_SMPTE170M:
> -        case AVCOL_TRC_SMPTE240M:
> -        case AVCOL_TRC_BT1361_ECG:
> -        case AVCOL_TRC_BT2020_10:
> -        case AVCOL_TRC_BT2020_12:
> -            /* these share a segmented TRC, but gamma 1.961 is a close
> -              approximation, and also more correct for decoding content */
> -            gamma = 1.961;
> -            break;
> -        case AVCOL_TRC_GAMMA22:
> -        case AVCOL_TRC_IEC61966_2_1:
> -            gamma = 2.2;
> -            break;
> -        case AVCOL_TRC_GAMMA28:
> -            gamma = 2.8;
> -            break;
> -        case AVCOL_TRC_LINEAR:
> -            gamma = 1.0;
> -            break;
> -        default:
> -            return 0;
> -    }
> +    double gamma = get_gamma_from_trc(trc);
> +    if (gamma <= 1e-6)
> +        return 0;
>  
>      AV_WB32_PNG(buf, 1.0 / gamma);
>      return 1;
> diff --git a/libavformat/movenc.c b/libavformat/movenc.c
> index e496ba4..7c10d0e 100644
> --- a/libavformat/movenc.c
> +++ b/libavformat/movenc.c
> @@ -40,10 +40,12 @@
>  #include "libavutil/avstring.h"
>  #include "libavutil/intfloat.h"
>  #include "libavutil/mathematics.h"
> +#include "libavutil/libm.h"
>  #include "libavutil/opt.h"
>  #include "libavutil/dict.h"
>  #include "libavutil/pixdesc.h"
>  #include "libavutil/timecode.h"
> +#include "libavutil/color_utils.h"
>  #include "hevc.h"
>  #include "rtpenc.h"
>  #include "mov_chan.h"
> @@ -65,6 +67,7 @@ static const AVOption options[] = {
>      { "frag_discont", "Signal that the next fragment is discontinuous from earlier ones", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_DISCONT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
>      { "delay_moov", "Delay writing the initial moov until the first fragment is cut, or until the first fragment flush", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DELAY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
>      { "write_colr", "Write colr atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_COLR}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
> +    { "write_gama", "Write deprecated gama atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_GAMA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
>      FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags),
>      { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
>      { "iods_audio_profile", "iods audio profile atom.", offsetof(MOVMuxContext, iods_audio_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM},
> @@ -77,6 +80,7 @@ static const AVOption options[] = {
>      { "brand",    "Override major brand", offsetof(MOVMuxContext, major_brand),   AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
>      { "use_editlist", "use edit list", offsetof(MOVMuxContext, use_editlist), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
>      { "fragment_index", "Fragment number of the next fragment", offsetof(MOVMuxContext, fragments), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
> +    { "mov_gamma", "gamma value for gama atom", offsetof(MOVMuxContext, gamma), AV_OPT_TYPE_FLOAT, {.dbl = 0.0 }, 0.0, 10, AV_OPT_FLAG_ENCODING_PARAM},
>      { NULL },
>  };
>  
> @@ -1519,6 +1523,31 @@ static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
>      return 16;
>  }
>  
> +static int mov_write_gama_tag(AVIOContext *pb, MOVTrack *track, double gamma)
> +{
> +    uint32_t gama = 0;
> +    if (gamma <= 0.0)
> +    {
> +        gamma = get_gamma_from_trc(track->enc->color_trc);
> +    }
> +    av_log(pb, AV_LOG_DEBUG, "gamma value %g\n", gamma);
> +
> +    if (gamma > 1e-6) {
> +        gama = (uint32_t)lrint((double)(1<<16) * gamma);
> +        av_log(pb, AV_LOG_DEBUG, "writing gama value %d\n", gama);
> +        
> +        av_assert0(track->mode == MODE_MOV);
> +        avio_wb32(pb, 12);
> +        ffio_wfourcc(pb, "gama");
> +        avio_wb32(pb, gama);
> +        return 12;
> +    }
> +    else {
> +        av_log(pb, AV_LOG_WARNING, "gamma value unknown, unable to write gama atom\n");
> +    }
> +    return 0;
> +}
> +
>  static int mov_write_colr_tag(AVIOContext *pb, MOVTrack *track)
>  {
>      // Ref (MOV): https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
> @@ -1700,6 +1729,12 @@ static int mov_write_video_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *tr
>          if (track->enc->field_order != AV_FIELD_UNKNOWN)
>              mov_write_fiel_tag(pb, track);
>  
> +    if (mov->flags & FF_MOV_FLAG_WRITE_GAMA) {
> +        if (track->mode == MODE_MOV)
> +            mov_write_gama_tag(pb, track, mov->gamma);
> +        else
> +            av_log(mov->fc, AV_LOG_WARNING, "Not writing 'gama' atom. Format is not MOV.\n");
> +    }
>      if (mov->flags & FF_MOV_FLAG_WRITE_COLR) {
>          if (track->mode == MODE_MOV || track->mode == MODE_MP4)
>              mov_write_colr_tag(pb, track);
> diff --git a/libavformat/movenc.h b/libavformat/movenc.h
> index 3a72937..21d0ee7 100644
> --- a/libavformat/movenc.h
> +++ b/libavformat/movenc.h
> @@ -185,6 +185,7 @@ typedef struct MOVMuxContext {
>      AVFormatContext *fc;
>  
>      int use_editlist;
> +    float gamma;
>  } MOVMuxContext;
>  
>  #define FF_MOV_FLAG_RTP_HINT              (1 <<  0)
> @@ -202,6 +203,7 @@ typedef struct MOVMuxContext {
>  #define FF_MOV_FLAG_FRAG_DISCONT          (1 << 12)
>  #define FF_MOV_FLAG_DELAY_MOOV            (1 << 13)
>  #define FF_MOV_FLAG_WRITE_COLR            (1 << 14)
> +#define FF_MOV_FLAG_WRITE_GAMA            (1 << 15)
>  
>  int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt);
>  
> diff --git a/libavutil/Makefile b/libavutil/Makefile
> index 6caf896..ca20539 100644
> --- a/libavutil/Makefile
> +++ b/libavutil/Makefile
> @@ -18,6 +18,7 @@ HEADERS = adler32.h                                                     \
>            cast5.h                                                       \
>            camellia.h                                                    \
>            channel_layout.h                                              \
> +          color_utils.h                                                 \
>            common.h                                                      \

IMO this header shouldn't be public, at least not yet. And I think
adding them to HEADERS will install the header. (Not sure about how
this works.)

>            cpu.h                                                         \
>            crc.h                                                         \
> @@ -88,6 +89,7 @@ OBJS = adler32.o                                                        \
>         cast5.o                                                          \
>         camellia.o                                                       \
>         channel_layout.o                                                 \
> +       color_utils.o                                                    \
>         cpu.o                                                            \
>         crc.o                                                            \
>         des.o                                                            \
> diff --git a/libavutil/color_utils.c b/libavutil/color_utils.c
> new file mode 100644
> index 0000000..a4d75a5
> --- /dev/null
> +++ b/libavutil/color_utils.c
> @@ -0,0 +1,52 @@
> +/*
> + * Copyright (c) 2015 Kevin Wheatley <kevin.j.wheatley at gmail.com>
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include "libavutil/color_utils.h"
> +#include "libavutil/pixfmt.h"
> +
> +double get_gamma_from_trc(enum AVColorTransferCharacteristic trc)

Public API functions must start with "av_". API functions which are
private to FFmpeg, but are used across the sub-libs (e.g. libavcodec
using a private libavutil function) must start with "avpriv_".

> +{
> +    double gamma;
> +    switch (trc) {
> +        case AVCOL_TRC_BT709:
> +        case AVCOL_TRC_SMPTE170M:
> +        case AVCOL_TRC_SMPTE240M:
> +        case AVCOL_TRC_BT1361_ECG:
> +        case AVCOL_TRC_BT2020_10:
> +        case AVCOL_TRC_BT2020_12:
> +            /* these share a segmented TRC, but gamma 1.961 is a close
> +              approximation, and also more correct for decoding content */
> +            gamma = 1.961;
> +            break;
> +        case AVCOL_TRC_GAMMA22:
> +        case AVCOL_TRC_IEC61966_2_1:
> +            gamma = 2.2;
> +            break;
> +        case AVCOL_TRC_GAMMA28:
> +            gamma = 2.8;
> +            break;
> +        case AVCOL_TRC_LINEAR:
> +            gamma = 1.0;
> +            break;
> +        default:
> +            gamma = 0.0;

Is this really a sane default? Or is it some placeholder value (i.e.
"not valid")?

> +    }
> +    return gamma;
> +}
> diff --git a/libavutil/color_utils.h b/libavutil/color_utils.h
> new file mode 100644
> index 0000000..f70d906
> --- /dev/null
> +++ b/libavutil/color_utils.h
> @@ -0,0 +1,29 @@
> +/*
> + * Copyright (c) 2015 Kevin Wheatley <kevin.j.wheatley at gmail.com>
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#ifndef AVUTIL_COLOR_UTILS_H
> +#define AVUTIL_COLOR_UTILS_H
> +
> +
> +#include "libavutil/pixfmt.h"
> +
> +double get_gamma_from_trc(enum AVColorTransferCharacteristic trc);

Lacks doxygen documentation.

> +
> +#endif



More information about the ffmpeg-devel mailing list