avformat/movenc: Add simplistic 'colr' tag writing support to mov container

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
Kevin Wheatley 2015-01-26 16:39:24 +01:00 committed by Michael Niedermayer
parent b8f3b0703c
commit 7b6f419176
7 changed files with 94 additions and 9 deletions

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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