[FFmpeg-cvslog] avformat/movenc: Add simplistic 'colr' tag writing support to mov container
Kevin Wheatley
git at videolan.org
Mon Jan 26 18:01:08 CET 2015
ffmpeg | branch: master | Kevin Wheatley <kevin.j.wheatley at gmail.com> | Mon Jan 26 16:39:24 2015 +0100| [7b6f4191763a5ffde02fa198101aabc3ddb5bf61] | committer: Michael Niedermayer
avformat/movenc: Add simplistic 'colr' tag writing support to mov container
Signed-off-by: Michael Niedermayer <michaelni at gmx.at>
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=7b6f4191763a5ffde02fa198101aabc3ddb5bf61
---
libavformat/movenc.c | 80 ++++++++++++++++++++++---
libavformat/movenc.h | 1 +
tests/fate/vcodec.mak | 6 +-
tests/ref/vsynth/vsynth1-dnxhd-1080i-colr | 4 ++
tests/ref/vsynth/vsynth2-dnxhd-1080i-colr | 4 ++
tests/ref/vsynth/vsynth3-dnxhd-1080i-colr | 4 ++
tests/ref/vsynth/vsynth_lena-dnxhd-1080i-colr | 4 ++
7 files changed, 94 insertions(+), 9 deletions(-)
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index e7f4eb1..d7ae5f0 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);
}
diff --git a/libavformat/movenc.h b/libavformat/movenc.h
index 79027e6..3a72937 100644
--- a/libavformat/movenc.h
+++ b/libavformat/movenc.h
@@ -201,6 +201,7 @@ typedef struct MOVMuxContext {
#define FF_MOV_FLAG_DASH (1 << 11)
#define FF_MOV_FLAG_FRAG_DISCONT (1 << 12)
#define FF_MOV_FLAG_DELAY_MOOV (1 << 13)
+#define FF_MOV_FLAG_WRITE_COLR (1 << 14)
int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt);
diff --git a/tests/fate/vcodec.mak b/tests/fate/vcodec.mak
index 807699e..a3aa11c 100644
--- a/tests/fate/vcodec.mak
+++ b/tests/fate/vcodec.mak
@@ -37,11 +37,15 @@ fate-vsynth%-dnxhd-720p-10bit: ENCOPTS = -s hd720 -b 90M \
-pix_fmt yuv422p10 -frames 5 -qmax 8
fate-vsynth%-dnxhd-720p-10bit: FMT = dnxhd
-FATE_VCODEC-$(call ENCDEC, DNXHD, MOV) += dnxhd-1080i
+FATE_VCODEC-$(call ENCDEC, DNXHD, MOV) += dnxhd-1080i dnxhd-1080i-colr
fate-vsynth%-dnxhd-1080i: ENCOPTS = -s hd1080 -b 120M -flags +ildct \
-pix_fmt yuv422p -frames 5 -qmax 8
fate-vsynth%-dnxhd-1080i: FMT = mov
+fate-vsynth%-dnxhd-1080i-colr: ENCOPTS = -s hd1080 -b 120M -flags +ildct -movflags write_colr \
+ -pix_fmt yuv422p -frames 5 -qmax 8
+fate-vsynth%-dnxhd-1080i-colr: FMT = mov
+
FATE_VCODEC-$(call ENCDEC, DVVIDEO, DV) += dv dv-411 dv-50
fate-vsynth%-dv: CODEC = dvvideo
fate-vsynth%-dv: ENCOPTS = -dct int -s pal
diff --git a/tests/ref/vsynth/vsynth1-dnxhd-1080i-colr b/tests/ref/vsynth/vsynth1-dnxhd-1080i-colr
new file mode 100644
index 0000000..87942cb
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-dnxhd-1080i-colr
@@ -0,0 +1,4 @@
+b6fbfdfe7027fde6853930abad87eaab *tests/data/fate/vsynth1-dnxhd-1080i-colr.mov
+3031929 tests/data/fate/vsynth1-dnxhd-1080i-colr.mov
+a09132c6db44f415e831dcaa630a351b *tests/data/fate/vsynth1-dnxhd-1080i-colr.out.rawvideo
+stddev: 6.29 PSNR: 32.15 MAXDIFF: 64 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth2-dnxhd-1080i-colr b/tests/ref/vsynth/vsynth2-dnxhd-1080i-colr
new file mode 100644
index 0000000..edf3c2c
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-dnxhd-1080i-colr
@@ -0,0 +1,4 @@
+d510bc0d58c7cae875e3e67023771d6f *tests/data/fate/vsynth2-dnxhd-1080i-colr.mov
+3031929 tests/data/fate/vsynth2-dnxhd-1080i-colr.mov
+099001db73036eeb9545c463cf90f0ba *tests/data/fate/vsynth2-dnxhd-1080i-colr.out.rawvideo
+stddev: 1.53 PSNR: 44.43 MAXDIFF: 31 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth3-dnxhd-1080i-colr b/tests/ref/vsynth/vsynth3-dnxhd-1080i-colr
new file mode 100644
index 0000000..c651c92
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-dnxhd-1080i-colr
@@ -0,0 +1,4 @@
+3b06d8675f9623db77b6a42916663608 *tests/data/fate/vsynth3-dnxhd-1080i-colr.mov
+3031929 tests/data/fate/vsynth3-dnxhd-1080i-colr.mov
+382fc519604abb5d87071bdce013cef9 *tests/data/fate/vsynth3-dnxhd-1080i-colr.out.rawvideo
+stddev: 7.81 PSNR: 30.28 MAXDIFF: 61 bytes: 86700/ 8670
diff --git a/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-colr b/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-colr
new file mode 100644
index 0000000..6c32bc9
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-colr
@@ -0,0 +1,4 @@
+4deae1b3d9a5c8fbd28075e8dca0034e *tests/data/fate/vsynth_lena-dnxhd-1080i-colr.mov
+3031929 tests/data/fate/vsynth_lena-dnxhd-1080i-colr.mov
+744ba46da5d4c19a28562ea31061d170 *tests/data/fate/vsynth_lena-dnxhd-1080i-colr.out.rawvideo
+stddev: 1.31 PSNR: 45.77 MAXDIFF: 23 bytes: 7603200/ 760320
More information about the ffmpeg-cvslog
mailing list