avformat/movenc: Add support for writing 'gama' atom to QuickTime .mov files.

As this is depricated it should not be on by default, it is only
supported for MOV containers, depends on avpriv_get_gamma_from_trc()

Enable by:

-movflags +write_gama

This will use the color_trc to supply a gamma value, if desired an
explicit value may be supplied using the -mov_gamma option supplying
a suitable floating point value, values <=1e-6 will not be written.

Signed-off-by: Kevin Wheatley <kevin.j.wheatley@gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
Kevin Wheatley 2015-03-05 10:40:13 +00:00 committed by Michael Niedermayer
parent 86b59e6a50
commit 45555a20c6
2 changed files with 37 additions and 0 deletions

View File

@ -40,10 +40,12 @@
#include "libavutil/avstring.h" #include "libavutil/avstring.h"
#include "libavutil/intfloat.h" #include "libavutil/intfloat.h"
#include "libavutil/mathematics.h" #include "libavutil/mathematics.h"
#include "libavutil/libm.h"
#include "libavutil/opt.h" #include "libavutil/opt.h"
#include "libavutil/dict.h" #include "libavutil/dict.h"
#include "libavutil/pixdesc.h" #include "libavutil/pixdesc.h"
#include "libavutil/timecode.h" #include "libavutil/timecode.h"
#include "libavutil/color_utils.h"
#include "hevc.h" #include "hevc.h"
#include "rtpenc.h" #include "rtpenc.h"
#include "mov_chan.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" }, { "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" }, { "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 (Experimental, may be renamed or changed, do not use from scripts)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_COLR}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "write_colr", "Write colr atom (Experimental, may be renamed or changed, do not use from scripts)", 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), 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}, { "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}, { "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 }, { "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}, { "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}, { "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 }, { NULL },
}; };
@ -1519,6 +1523,31 @@ static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
return 16; return 16;
} }
static int mov_write_gama_tag(AVIOContext *pb, MOVTrack *track, double gamma)
{
uint32_t gama = 0;
if (gamma <= 0.0)
{
gamma = avpriv_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) 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 // 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) if (track->enc->field_order != AV_FIELD_UNKNOWN)
mov_write_fiel_tag(pb, track); 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 (mov->flags & FF_MOV_FLAG_WRITE_COLR) {
if (track->mode == MODE_MOV || track->mode == MODE_MP4) if (track->mode == MODE_MOV || track->mode == MODE_MP4)
mov_write_colr_tag(pb, track); mov_write_colr_tag(pb, track);

View File

@ -185,6 +185,7 @@ typedef struct MOVMuxContext {
AVFormatContext *fc; AVFormatContext *fc;
int use_editlist; int use_editlist;
float gamma;
} MOVMuxContext; } MOVMuxContext;
#define FF_MOV_FLAG_RTP_HINT (1 << 0) #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_FRAG_DISCONT (1 << 12)
#define FF_MOV_FLAG_DELAY_MOOV (1 << 13) #define FF_MOV_FLAG_DELAY_MOOV (1 << 13)
#define FF_MOV_FLAG_WRITE_COLR (1 << 14) #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); int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt);