Commit 45555a20 authored by Kevin Wheatley's avatar Kevin Wheatley Committed by Michael Niedermayer

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: 's avatarKevin Wheatley <kevin.j.wheatley@gmail.com>
Signed-off-by: 's avatarMichael Niedermayer <michaelni@gmx.at>
parent 86b59e6a
...@@ -40,10 +40,12 @@ ...@@ -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[] = { ...@@ -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[] = { ...@@ -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) ...@@ -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 ...@@ -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);
......
...@@ -185,6 +185,7 @@ typedef struct MOVMuxContext { ...@@ -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 { ...@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment