summaryrefslogtreecommitdiff
path: root/libavformat/movenc.c
diff options
context:
space:
mode:
authorKevin Wheatley <kevin.j.wheatley@gmail.com>2015-01-26 16:39:24 +0100
committerMichael Niedermayer <michaelni@gmx.at>2015-01-26 17:49:50 +0100
commit7b6f4191763a5ffde02fa198101aabc3ddb5bf61 (patch)
tree8b9bc8e1e8428233cb0206672a9add7065db2438 /libavformat/movenc.c
parentb8f3b0703c32b1502ad25af8bb1168c74a1fe2a3 (diff)
avformat/movenc: Add simplistic 'colr' tag writing support to mov container
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavformat/movenc.c')
-rw-r--r--libavformat/movenc.c80
1 files changed, 72 insertions, 8 deletions
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index e7f4eb1d90..d7ae5f0e90 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -67,6 +67,7 @@ static const AVOption options[] = {
{ "dash", "Write DASH compatible fragmented MP4", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DASH}, 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" },
+ { "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" },
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},
@@ -1499,6 +1500,66 @@ static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
return 16;
}
+static int mov_write_colr_tag(AVIOContext *pb, MOVTrack *track)
+{
+ // Ref: https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
+
+ if (track->enc->color_primaries == AVCOL_PRI_UNSPECIFIED &&
+ track->enc->color_trc == AVCOL_TRC_UNSPECIFIED &&
+ track->enc->colorspace == AVCOL_SPC_UNSPECIFIED) {
+ if ((track->enc->width >= 1920 && track->enc->height >= 1080)
+ || (track->enc->width == 1280 && track->enc->height == 720)) {
+ av_log(NULL, AV_LOG_WARNING, "color primaries unspecified, assuming bt709\n");
+ track->enc->color_primaries = AVCOL_PRI_BT709;
+ } else if (track->enc->width == 720 && track->height == 576) {
+ av_log(NULL, AV_LOG_WARNING, "color primaries unspecified, assuming bt470bg\n");
+ track->enc->color_primaries = AVCOL_PRI_BT470BG;
+ } else if (track->enc->width == 720 &&
+ (track->height == 486 || track->height == 480)) {
+ av_log(NULL, AV_LOG_WARNING, "color primaries unspecified, assuming smpte170\n");
+ track->enc->color_primaries = AVCOL_PRI_SMPTE170M;
+ } else {
+ av_log(NULL, AV_LOG_WARNING, "color primaries unspecified, unable to assume anything\n");
+ }
+ switch (track->enc->color_primaries) {
+ case AVCOL_PRI_BT709:
+ track->enc->color_trc = AVCOL_TRC_BT709;
+ track->enc->colorspace = AVCOL_SPC_BT709;
+ break;
+ case AVCOL_PRI_SMPTE170M:
+ case AVCOL_PRI_BT470BG:
+ track->enc->color_trc = AVCOL_TRC_BT709;
+ track->enc->colorspace = AVCOL_SPC_SMPTE170M;
+ break;
+ }
+ }
+
+ avio_wb32(pb, 18);
+ ffio_wfourcc(pb, "colr");
+ ffio_wfourcc(pb, "nclc");
+ switch (track->enc->color_primaries) {
+ case AVCOL_PRI_BT709: avio_wb16(pb, 1); break;
+ case AVCOL_PRI_SMPTE170M:
+ case AVCOL_PRI_SMPTE240M: avio_wb16(pb, 6); break;
+ case AVCOL_PRI_BT470BG: avio_wb16(pb, 5); break;
+ default: avio_wb16(pb, 2);
+ }
+ switch (track->enc->color_trc) {
+ case AVCOL_TRC_BT709: avio_wb16(pb, 1); break;
+ case AVCOL_TRC_SMPTE170M: avio_wb16(pb, 1); break; // remapped
+ case AVCOL_TRC_SMPTE240M: avio_wb16(pb, 7); break;
+ default: avio_wb16(pb, 2);
+ }
+ switch (track->enc->colorspace) {
+ case AVCOL_TRC_BT709: avio_wb16(pb, 1); break;
+ case AVCOL_PRI_SMPTE170M: avio_wb16(pb, 6); break;
+ case AVCOL_PRI_SMPTE240M: avio_wb16(pb, 7); break;
+ default: avio_wb16(pb, 2);
+ }
+
+ return 18;
+}
+
static void find_compressor(char * compressor_name, int len, MOVTrack *track)
{
AVDictionaryEntry *encoder;
@@ -1527,7 +1588,7 @@ static void find_compressor(char * compressor_name, int len, MOVTrack *track)
}
}
-static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track)
+static int mov_write_video_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
{
int64_t pos = avio_tell(pb);
char compressor_name[32] = { 0 };
@@ -1605,6 +1666,9 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track)
if (track->enc->field_order != AV_FIELD_UNKNOWN)
mov_write_fiel_tag(pb, track);
+ if (mov->flags & FF_MOV_FLAG_WRITE_COLR)
+ mov_write_colr_tag(pb, track);
+
if (track->enc->sample_aspect_ratio.den && track->enc->sample_aspect_ratio.num &&
track->enc->sample_aspect_ratio.den != track->enc->sample_aspect_ratio.num) {
mov_write_pasp_tag(pb, track);
@@ -1695,7 +1759,7 @@ static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
return update_size(pb, pos);
}
-static int mov_write_stsd_tag(AVIOContext *pb, MOVTrack *track)
+static int mov_write_stsd_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
{
int64_t pos = avio_tell(pb);
avio_wb32(pb, 0); /* size */
@@ -1703,7 +1767,7 @@ static int mov_write_stsd_tag(AVIOContext *pb, MOVTrack *track)
avio_wb32(pb, 0); /* version & flags */
avio_wb32(pb, 1); /* entry count */
if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO)
- mov_write_video_tag(pb, track);
+ mov_write_video_tag(pb, mov, track);
else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
mov_write_audio_tag(pb, track);
else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)
@@ -1807,14 +1871,14 @@ static int mov_write_dref_tag(AVIOContext *pb)
return 28;
}
-static int mov_write_stbl_tag(AVIOContext *pb, MOVTrack *track)
+static int mov_write_stbl_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
{
int64_t pos = avio_tell(pb);
int ret;
avio_wb32(pb, 0); /* size */
ffio_wfourcc(pb, "stbl");
- mov_write_stsd_tag(pb, track);
+ mov_write_stsd_tag(pb, mov, track);
mov_write_stts_tag(pb, track);
if ((track->enc->codec_type == AVMEDIA_TYPE_VIDEO ||
track->enc->codec_tag == MKTAG('r','t','p',' ')) &&
@@ -2032,7 +2096,7 @@ static int mov_write_hmhd_tag(AVIOContext *pb)
return 28;
}
-static int mov_write_minf_tag(AVIOContext *pb, MOVTrack *track)
+static int mov_write_minf_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
{
int64_t pos = avio_tell(pb);
int ret;
@@ -2057,7 +2121,7 @@ static int mov_write_minf_tag(AVIOContext *pb, MOVTrack *track)
if (track->mode == MODE_MOV) /* FIXME: Why do it for MODE_MOV only ? */
mov_write_hdlr_tag(pb, NULL);
mov_write_dinf_tag(pb);
- if ((ret = mov_write_stbl_tag(pb, track)) < 0)
+ if ((ret = mov_write_stbl_tag(pb, mov, track)) < 0)
return ret;
return update_size(pb, pos);
}
@@ -2111,7 +2175,7 @@ static int mov_write_mdia_tag(AVIOContext *pb, MOVMuxContext *mov,
ffio_wfourcc(pb, "mdia");
mov_write_mdhd_tag(pb, mov, track);
mov_write_hdlr_tag(pb, track);
- if ((ret = mov_write_minf_tag(pb, track)) < 0)
+ if ((ret = mov_write_minf_tag(pb, mov, track)) < 0)
return ret;
return update_size(pb, pos);
}