Message ID | 20170518004941.5140-3-jamrial@gmail.com |
---|---|
State | Accepted |
Headers | show |
On Wed, May 17, 2017 at 09:49:40PM -0300, James Almer wrote: > As defined in "VP Codec ISO Media File Format Binding v1.0" > https://github.com/webmproject/vp9-dash/blob/master/VPCodecISOMediaFileFormatBinding.md > > Partially based on Matroska decoder code. > > Signed-off-by: James Almer <jamrial@gmail.com> > --- > libavformat/isom.h | 2 ++ > libavformat/mov.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 67 insertions(+) > > diff --git a/libavformat/isom.h b/libavformat/isom.h > index d9956cf63a..426f732247 100644 > --- a/libavformat/isom.h > +++ b/libavformat/isom.h > @@ -27,6 +27,7 @@ > #include <stddef.h> > #include <stdint.h> > > +#include "libavutil/mastering_display_metadata.h" > #include "libavutil/spherical.h" > #include "libavutil/stereo3d.h" > > @@ -194,6 +195,7 @@ typedef struct MOVStreamContext { > AVStereo3D *stereo3d; > AVSphericalMapping *spherical; > size_t spherical_size; > + AVMasteringDisplayMetadata *mastering; > > uint32_t format; > > diff --git a/libavformat/mov.c b/libavformat/mov.c > index afef53b79a..0b5fd849f3 100644 > --- a/libavformat/mov.c > +++ b/libavformat/mov.c > @@ -4612,6 +4612,60 @@ static int mov_read_tmcd(MOVContext *c, AVIOContext *pb, MOVAtom atom) > return 0; > } > > +static int mov_read_smdm(MOVContext *c, AVIOContext *pb, MOVAtom atom) > +{ > + MOVStreamContext *sc; > + const int chroma_den = 50000; > + const int luma_den = 10000; > + int version; > + > + if (c->fc->nb_streams < 1) > + return AVERROR_INVALIDDATA; > + > + sc = c->fc->streams[c->fc->nb_streams - 1]->priv_data; > + > + if (atom.size < 5) { > + av_log(c->fc, AV_LOG_ERROR, "Empty Mastering Display Metadata box\n"); > + return AVERROR_INVALIDDATA; > + } > + > + version = avio_r8(pb); > + if (version) { > + av_log(c->fc, AV_LOG_WARNING, "Unsupported Mastering Display Metadata box version %d\n", version); > + return 0; > + } > + avio_skip(pb, 3); /* flags */ > + > + sc->mastering = av_mastering_display_metadata_alloc(); > + if (!sc->mastering) > + return AVERROR(ENOMEM); > + > + sc->mastering->display_primaries[0][0] = > + av_make_q(lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den); this is not optimal, precission wise av_d2q() should produce closer rationals alternativly av_reduce() can be used directly but iam not sure why a fixed chroma_den and luma_den is fixed maybe iam missing something [...]
On 5/26/2017 8:05 PM, Michael Niedermayer wrote: > On Wed, May 17, 2017 at 09:49:40PM -0300, James Almer wrote: >> As defined in "VP Codec ISO Media File Format Binding v1.0" >> https://github.com/webmproject/vp9-dash/blob/master/VPCodecISOMediaFileFormatBinding.md >> >> Partially based on Matroska decoder code. >> >> Signed-off-by: James Almer <jamrial@gmail.com> >> --- >> libavformat/isom.h | 2 ++ >> libavformat/mov.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ >> 2 files changed, 67 insertions(+) >> >> diff --git a/libavformat/isom.h b/libavformat/isom.h >> index d9956cf63a..426f732247 100644 >> --- a/libavformat/isom.h >> +++ b/libavformat/isom.h >> @@ -27,6 +27,7 @@ >> #include <stddef.h> >> #include <stdint.h> >> >> +#include "libavutil/mastering_display_metadata.h" >> #include "libavutil/spherical.h" >> #include "libavutil/stereo3d.h" >> >> @@ -194,6 +195,7 @@ typedef struct MOVStreamContext { >> AVStereo3D *stereo3d; >> AVSphericalMapping *spherical; >> size_t spherical_size; >> + AVMasteringDisplayMetadata *mastering; >> >> uint32_t format; >> >> diff --git a/libavformat/mov.c b/libavformat/mov.c >> index afef53b79a..0b5fd849f3 100644 >> --- a/libavformat/mov.c >> +++ b/libavformat/mov.c >> @@ -4612,6 +4612,60 @@ static int mov_read_tmcd(MOVContext *c, AVIOContext *pb, MOVAtom atom) >> return 0; >> } >> >> +static int mov_read_smdm(MOVContext *c, AVIOContext *pb, MOVAtom atom) >> +{ >> + MOVStreamContext *sc; >> + const int chroma_den = 50000; >> + const int luma_den = 10000; >> + int version; >> + >> + if (c->fc->nb_streams < 1) >> + return AVERROR_INVALIDDATA; >> + >> + sc = c->fc->streams[c->fc->nb_streams - 1]->priv_data; >> + >> + if (atom.size < 5) { >> + av_log(c->fc, AV_LOG_ERROR, "Empty Mastering Display Metadata box\n"); >> + return AVERROR_INVALIDDATA; >> + } >> + >> + version = avio_r8(pb); >> + if (version) { >> + av_log(c->fc, AV_LOG_WARNING, "Unsupported Mastering Display Metadata box version %d\n", version); >> + return 0; >> + } >> + avio_skip(pb, 3); /* flags */ >> + >> + sc->mastering = av_mastering_display_metadata_alloc(); >> + if (!sc->mastering) >> + return AVERROR(ENOMEM); >> + > >> + sc->mastering->display_primaries[0][0] = >> + av_make_q(lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den); > > this is not optimal, precission wise > av_d2q() should produce closer rationals > alternativly av_reduce() can be used directly > > but iam not sure why a fixed chroma_den and luma_den is fixed > maybe iam missing something I took the constants from hevcdec.c and matroskadec.c and basically copied how they handled these values. At least based on what lavf's dump.c and mkvtoolnix's mkvinfo reported, this implementation is the most precise i tried. Using av_d2q() directly was worse.
On 5/26/2017 8:55 PM, James Almer wrote: > On 5/26/2017 8:05 PM, Michael Niedermayer wrote: >> On Wed, May 17, 2017 at 09:49:40PM -0300, James Almer wrote: >>> As defined in "VP Codec ISO Media File Format Binding v1.0" >>> https://github.com/webmproject/vp9-dash/blob/master/VPCodecISOMediaFileFormatBinding.md >>> >>> Partially based on Matroska decoder code. >>> >>> Signed-off-by: James Almer <jamrial@gmail.com> >>> --- >>> libavformat/isom.h | 2 ++ >>> libavformat/mov.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ >>> 2 files changed, 67 insertions(+) >>> >>> diff --git a/libavformat/isom.h b/libavformat/isom.h >>> index d9956cf63a..426f732247 100644 >>> --- a/libavformat/isom.h >>> +++ b/libavformat/isom.h >>> @@ -27,6 +27,7 @@ >>> #include <stddef.h> >>> #include <stdint.h> >>> >>> +#include "libavutil/mastering_display_metadata.h" >>> #include "libavutil/spherical.h" >>> #include "libavutil/stereo3d.h" >>> >>> @@ -194,6 +195,7 @@ typedef struct MOVStreamContext { >>> AVStereo3D *stereo3d; >>> AVSphericalMapping *spherical; >>> size_t spherical_size; >>> + AVMasteringDisplayMetadata *mastering; >>> >>> uint32_t format; >>> >>> diff --git a/libavformat/mov.c b/libavformat/mov.c >>> index afef53b79a..0b5fd849f3 100644 >>> --- a/libavformat/mov.c >>> +++ b/libavformat/mov.c >>> @@ -4612,6 +4612,60 @@ static int mov_read_tmcd(MOVContext *c, AVIOContext *pb, MOVAtom atom) >>> return 0; >>> } >>> >>> +static int mov_read_smdm(MOVContext *c, AVIOContext *pb, MOVAtom atom) >>> +{ >>> + MOVStreamContext *sc; >>> + const int chroma_den = 50000; >>> + const int luma_den = 10000; >>> + int version; >>> + >>> + if (c->fc->nb_streams < 1) >>> + return AVERROR_INVALIDDATA; >>> + >>> + sc = c->fc->streams[c->fc->nb_streams - 1]->priv_data; >>> + >>> + if (atom.size < 5) { >>> + av_log(c->fc, AV_LOG_ERROR, "Empty Mastering Display Metadata box\n"); >>> + return AVERROR_INVALIDDATA; >>> + } >>> + >>> + version = avio_r8(pb); >>> + if (version) { >>> + av_log(c->fc, AV_LOG_WARNING, "Unsupported Mastering Display Metadata box version %d\n", version); >>> + return 0; >>> + } >>> + avio_skip(pb, 3); /* flags */ >>> + >>> + sc->mastering = av_mastering_display_metadata_alloc(); >>> + if (!sc->mastering) >>> + return AVERROR(ENOMEM); >>> + >> >>> + sc->mastering->display_primaries[0][0] = >>> + av_make_q(lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den); >> >> this is not optimal, precission wise >> av_d2q() should produce closer rationals >> alternativly av_reduce() can be used directly >> >> but iam not sure why a fixed chroma_den and luma_den is fixed >> maybe iam missing something > > I took the constants from hevcdec.c and matroskadec.c and basically > copied how they handled these values. > At least based on what lavf's dump.c and mkvtoolnix's mkvinfo reported, > this implementation is the most precise i tried. Using av_d2q() directly > was worse. By dump.c i mean i remuxed an mkv file with mastering metadata using the muxer implementation of this same patchset then compared the reported values. By mkvinfo i mean mkv -> mov (using my muxer implementation) -> mkv roundtrip then compared the double precision values stored in the original mkv and the new mkv.
On 5/26/2017 8:05 PM, Michael Niedermayer wrote: > On Wed, May 17, 2017 at 09:49:40PM -0300, James Almer wrote: >> As defined in "VP Codec ISO Media File Format Binding v1.0" >> https://github.com/webmproject/vp9-dash/blob/master/VPCodecISOMediaFileFormatBinding.md >> >> Partially based on Matroska decoder code. >> >> Signed-off-by: James Almer <jamrial@gmail.com> >> --- >> libavformat/isom.h | 2 ++ >> libavformat/mov.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ >> 2 files changed, 67 insertions(+) >> >> diff --git a/libavformat/isom.h b/libavformat/isom.h >> index d9956cf63a..426f732247 100644 >> --- a/libavformat/isom.h >> +++ b/libavformat/isom.h >> @@ -27,6 +27,7 @@ >> #include <stddef.h> >> #include <stdint.h> >> >> +#include "libavutil/mastering_display_metadata.h" >> #include "libavutil/spherical.h" >> #include "libavutil/stereo3d.h" >> >> @@ -194,6 +195,7 @@ typedef struct MOVStreamContext { >> AVStereo3D *stereo3d; >> AVSphericalMapping *spherical; >> size_t spherical_size; >> + AVMasteringDisplayMetadata *mastering; >> >> uint32_t format; >> >> diff --git a/libavformat/mov.c b/libavformat/mov.c >> index afef53b79a..0b5fd849f3 100644 >> --- a/libavformat/mov.c >> +++ b/libavformat/mov.c >> @@ -4612,6 +4612,60 @@ static int mov_read_tmcd(MOVContext *c, AVIOContext *pb, MOVAtom atom) >> return 0; >> } >> >> +static int mov_read_smdm(MOVContext *c, AVIOContext *pb, MOVAtom atom) >> +{ >> + MOVStreamContext *sc; >> + const int chroma_den = 50000; >> + const int luma_den = 10000; >> + int version; >> + >> + if (c->fc->nb_streams < 1) >> + return AVERROR_INVALIDDATA; >> + >> + sc = c->fc->streams[c->fc->nb_streams - 1]->priv_data; >> + >> + if (atom.size < 5) { >> + av_log(c->fc, AV_LOG_ERROR, "Empty Mastering Display Metadata box\n"); >> + return AVERROR_INVALIDDATA; >> + } >> + >> + version = avio_r8(pb); >> + if (version) { >> + av_log(c->fc, AV_LOG_WARNING, "Unsupported Mastering Display Metadata box version %d\n", version); >> + return 0; >> + } >> + avio_skip(pb, 3); /* flags */ >> + >> + sc->mastering = av_mastering_display_metadata_alloc(); >> + if (!sc->mastering) >> + return AVERROR(ENOMEM); >> + > >> + sc->mastering->display_primaries[0][0] = >> + av_make_q(lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den); > > this is not optimal, precission wise > av_d2q() should produce closer rationals > alternativly av_reduce() can be used directly > > but iam not sure why a fixed chroma_den and luma_den is fixed > maybe iam missing something Does for (i = 0; i < 3; i++) for (j = 0; j < 2; j++) av_reduce(&sc->mastering->display_primaries[i][j].num, &sc->mastering->display_primaries[i][j].den, lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den, chroma_den); for (i = 0; i < 2; i++) av_reduce(&sc->mastering->white_point[i].num, &sc->mastering->white_point[i].den, lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den, chroma_den); av_reduce(&sc->mastering->max_luminance.num, &sc->mastering->max_luminance.den, lrint(((double)avio_rb32(pb) / (1 << 8)) * luma_den), luma_den, INT_MAX); av_reduce(&sc->mastering->min_luminance.num, &sc->mastering->min_luminance.den, lrint(((double)avio_rb32(pb) / (1 << 14)) * luma_den), luma_den, INT_MAX); Look better?
On Sat, May 27, 2017 at 01:54:18AM -0300, James Almer wrote: > On 5/26/2017 8:05 PM, Michael Niedermayer wrote: > > On Wed, May 17, 2017 at 09:49:40PM -0300, James Almer wrote: > >> As defined in "VP Codec ISO Media File Format Binding v1.0" > >> https://github.com/webmproject/vp9-dash/blob/master/VPCodecISOMediaFileFormatBinding.md > >> > >> Partially based on Matroska decoder code. > >> > >> Signed-off-by: James Almer <jamrial@gmail.com> > >> --- > >> libavformat/isom.h | 2 ++ > >> libavformat/mov.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > >> 2 files changed, 67 insertions(+) > >> > >> diff --git a/libavformat/isom.h b/libavformat/isom.h > >> index d9956cf63a..426f732247 100644 > >> --- a/libavformat/isom.h > >> +++ b/libavformat/isom.h > >> @@ -27,6 +27,7 @@ > >> #include <stddef.h> > >> #include <stdint.h> > >> > >> +#include "libavutil/mastering_display_metadata.h" > >> #include "libavutil/spherical.h" > >> #include "libavutil/stereo3d.h" > >> > >> @@ -194,6 +195,7 @@ typedef struct MOVStreamContext { > >> AVStereo3D *stereo3d; > >> AVSphericalMapping *spherical; > >> size_t spherical_size; > >> + AVMasteringDisplayMetadata *mastering; > >> > >> uint32_t format; > >> > >> diff --git a/libavformat/mov.c b/libavformat/mov.c > >> index afef53b79a..0b5fd849f3 100644 > >> --- a/libavformat/mov.c > >> +++ b/libavformat/mov.c > >> @@ -4612,6 +4612,60 @@ static int mov_read_tmcd(MOVContext *c, AVIOContext *pb, MOVAtom atom) > >> return 0; > >> } > >> > >> +static int mov_read_smdm(MOVContext *c, AVIOContext *pb, MOVAtom atom) > >> +{ > >> + MOVStreamContext *sc; > >> + const int chroma_den = 50000; > >> + const int luma_den = 10000; > >> + int version; > >> + > >> + if (c->fc->nb_streams < 1) > >> + return AVERROR_INVALIDDATA; > >> + > >> + sc = c->fc->streams[c->fc->nb_streams - 1]->priv_data; > >> + > >> + if (atom.size < 5) { > >> + av_log(c->fc, AV_LOG_ERROR, "Empty Mastering Display Metadata box\n"); > >> + return AVERROR_INVALIDDATA; > >> + } > >> + > >> + version = avio_r8(pb); > >> + if (version) { > >> + av_log(c->fc, AV_LOG_WARNING, "Unsupported Mastering Display Metadata box version %d\n", version); > >> + return 0; > >> + } > >> + avio_skip(pb, 3); /* flags */ > >> + > >> + sc->mastering = av_mastering_display_metadata_alloc(); > >> + if (!sc->mastering) > >> + return AVERROR(ENOMEM); > >> + > > > >> + sc->mastering->display_primaries[0][0] = > >> + av_make_q(lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den); > > > > this is not optimal, precission wise > > av_d2q() should produce closer rationals > > alternativly av_reduce() can be used directly > > > > but iam not sure why a fixed chroma_den and luma_den is fixed > > maybe iam missing something > > Does > > for (i = 0; i < 3; i++) > for (j = 0; j < 2; j++) > av_reduce(&sc->mastering->display_primaries[i][j].num, > &sc->mastering->display_primaries[i][j].den, > lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), > chroma_den, chroma_den); Why do you use lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den and chroma_den instead of avio_rb16(pb) and 1 << 16 ? Is the intend to guess the value prior to muxing instead of using the value actually stored in the mov file ? [...]
On 5/27/2017 11:05 AM, Michael Niedermayer wrote: > On Sat, May 27, 2017 at 01:54:18AM -0300, James Almer wrote: >> On 5/26/2017 8:05 PM, Michael Niedermayer wrote: >>> On Wed, May 17, 2017 at 09:49:40PM -0300, James Almer wrote: >>>> As defined in "VP Codec ISO Media File Format Binding v1.0" >>>> https://github.com/webmproject/vp9-dash/blob/master/VPCodecISOMediaFileFormatBinding.md >>>> >>>> Partially based on Matroska decoder code. >>>> >>>> Signed-off-by: James Almer <jamrial@gmail.com> >>>> --- >>>> libavformat/isom.h | 2 ++ >>>> libavformat/mov.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ >>>> 2 files changed, 67 insertions(+) >>>> >>>> diff --git a/libavformat/isom.h b/libavformat/isom.h >>>> index d9956cf63a..426f732247 100644 >>>> --- a/libavformat/isom.h >>>> +++ b/libavformat/isom.h >>>> @@ -27,6 +27,7 @@ >>>> #include <stddef.h> >>>> #include <stdint.h> >>>> >>>> +#include "libavutil/mastering_display_metadata.h" >>>> #include "libavutil/spherical.h" >>>> #include "libavutil/stereo3d.h" >>>> >>>> @@ -194,6 +195,7 @@ typedef struct MOVStreamContext { >>>> AVStereo3D *stereo3d; >>>> AVSphericalMapping *spherical; >>>> size_t spherical_size; >>>> + AVMasteringDisplayMetadata *mastering; >>>> >>>> uint32_t format; >>>> >>>> diff --git a/libavformat/mov.c b/libavformat/mov.c >>>> index afef53b79a..0b5fd849f3 100644 >>>> --- a/libavformat/mov.c >>>> +++ b/libavformat/mov.c >>>> @@ -4612,6 +4612,60 @@ static int mov_read_tmcd(MOVContext *c, AVIOContext *pb, MOVAtom atom) >>>> return 0; >>>> } >>>> >>>> +static int mov_read_smdm(MOVContext *c, AVIOContext *pb, MOVAtom atom) >>>> +{ >>>> + MOVStreamContext *sc; >>>> + const int chroma_den = 50000; >>>> + const int luma_den = 10000; >>>> + int version; >>>> + >>>> + if (c->fc->nb_streams < 1) >>>> + return AVERROR_INVALIDDATA; >>>> + >>>> + sc = c->fc->streams[c->fc->nb_streams - 1]->priv_data; >>>> + >>>> + if (atom.size < 5) { >>>> + av_log(c->fc, AV_LOG_ERROR, "Empty Mastering Display Metadata box\n"); >>>> + return AVERROR_INVALIDDATA; >>>> + } >>>> + >>>> + version = avio_r8(pb); >>>> + if (version) { >>>> + av_log(c->fc, AV_LOG_WARNING, "Unsupported Mastering Display Metadata box version %d\n", version); >>>> + return 0; >>>> + } >>>> + avio_skip(pb, 3); /* flags */ >>>> + >>>> + sc->mastering = av_mastering_display_metadata_alloc(); >>>> + if (!sc->mastering) >>>> + return AVERROR(ENOMEM); >>>> + >>> >>>> + sc->mastering->display_primaries[0][0] = >>>> + av_make_q(lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den); >>> >>> this is not optimal, precission wise >>> av_d2q() should produce closer rationals >>> alternativly av_reduce() can be used directly >>> >>> but iam not sure why a fixed chroma_den and luma_den is fixed >>> maybe iam missing something >> >> Does >> >> for (i = 0; i < 3; i++) >> for (j = 0; j < 2; j++) >> av_reduce(&sc->mastering->display_primaries[i][j].num, >> &sc->mastering->display_primaries[i][j].den, >> lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), >> chroma_den, chroma_den); > > Why do you use > lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den > and > chroma_den > > instead of > avio_rb16(pb) > and > 1 << 16 > > ? > To follow the origin spec the vp9 in mp4 spec and the AVMasteringDisplayMetadata API quote and are based on. --------------- display_primaries_x[ c ] and display_primaries_y[ c ] specify the normalized x and y chromaticity coordinates, respectively, of the colour primary component c of the mastering display in increments of 0.00002, according to the CIE 1931 definition of x and y as specified in ISO 11664-1 (see also ISO 11664-3 and CIE 15). For describing mastering displays that use red, green and blue colour primaries, it is suggested that index value c equal to 0 should correspond to the green primary, c equal to 1 should correspond to the blue primary and c equal to 2 should correspond to the red colour primary (see also Annex E and Table E.3). The values of display_primaries_x[ c ] and display_primaries_y[ c ] shall be in the range of 0 to 50 000, inclusive. white_point_x and white_point_y specify the normalized x and y chromaticity coordinates, respectively, of the white point of the mastering display in normalized increments of 0.00002, according to the CIE 1931 definition of x and y as specified in ISO 11664-1 (see also ISO 11664-3 and CIE 15). The values of white_point_x and white_point_y shall be in the range of 0 to 50 000. max_display_mastering_luminance and min_display_mastering_luminance specify the nominal maximum and minimum display luminance, respectively, of the mastering display in units of 0.0001 candelas per square metre. ------------ $ ./ffmpeg -i The\ World\ in\ HDR-tO01J-M3g0U.webm Side data: Mastering Display Metadata, has_primaries:1 has_luminance:1 r(0.6800,0.3200) g(0.2649,0.6900) b(0.1500 0.0600) wp(0.3127, 0.3290) min_luminance=0.001000, max_luminance=1000.000000 $ mkvinfo The\ World\ in\ HDR-tO01J-M3g0U.webm | + Video colour mastering metadata | + Max luminance: 1000 | + Min luminance: 0.001 | + Red colour coordinate x: 0.68 | + Red colour coordinate y: 0.31996 | + Green colour coordinate x: 0.26494 | + Green colour coordinate y: 0.68996 | + Blue colour coordinate x: 0.15 | + Blue colour coordinate y: 0.05998 | + White colour coordinate x: 0.3127 | + White colour coordinate y: 0.32896 $ ./ffmpeg -i The\ World\ in\ HDR-tO01J-M3g0U.webm -c:v copy mastering.mp4 ------ Without chroma/luma_den rounding in demuxer $ ./ffmpeg -i mastering.mp4 Side data: Mastering Display Metadata, has_primaries:1 has_luminance:1 r(0.6800,0.3200) g(0.2649,0.6900) b(0.1500 0.0600) wp(0.3127, 0.3290) min_luminance=0.000977, max_luminance=1000.000000 $ ./ffmpeg -i mastering.mp4 -c:v copy without_den.mkv $ mkvinfo without_den.mkv | + Video colour mastering metadata | + Red colour coordinate x: 0.679993 | + Red colour coordinate y: 0.319962 | + Green colour coordinate x: 0.264938 | + Green colour coordinate y: 0.689957 | + Blue colour coordinate x: 0.149994 | + Blue colour coordinate y: 0.0599823 | + White colour coordinate x: 0.312698 | + White colour coordinate y: 0.328964 | + Max luminance: 1000 | + Min luminance: 0.000976562 ------ With chroma/luma_den rounding in demuxer $ ./ffmpeg -i mastering.mp4 Side data: Mastering Display Metadata, has_primaries:1 has_luminance:1 r(0.6800,0.3200) g(0.2649,0.6900) b(0.1500 0.0600) wp(0.3127, 0.3290) min_luminance=0.001000, max_luminance=1000.000000 $ ./ffmpeg -i mastering.mp4 -c:v copy with_den.mkv $ mkvinfo with_den.mkv | + Red colour coordinate x: 0.68 | + Red colour coordinate y: 0.31996 | + Green colour coordinate x: 0.26494 | + Green colour coordinate y: 0.68996 | + Blue colour coordinate x: 0.15 | + Blue colour coordinate y: 0.05998 | + White colour coordinate x: 0.3127 | + White colour coordinate y: 0.32896 | + Max luminance: 1000 | + Min luminance: 0.001 ------ Notice how all values break the increments of 0.00002 (50000 denominator) and 0.0001 (10000 denominator) constrains when i just take the 0.16, 24.8 and 18.14 fixed point values stored in mp4 and dump them into AVMasteringDisplayMetadata as is, like you suggest.
On Sat, May 27, 2017 at 11:58:05AM -0300, James Almer wrote: > On 5/27/2017 11:05 AM, Michael Niedermayer wrote: > > On Sat, May 27, 2017 at 01:54:18AM -0300, James Almer wrote: > >> On 5/26/2017 8:05 PM, Michael Niedermayer wrote: > >>> On Wed, May 17, 2017 at 09:49:40PM -0300, James Almer wrote: > >>>> As defined in "VP Codec ISO Media File Format Binding v1.0" > >>>> https://github.com/webmproject/vp9-dash/blob/master/VPCodecISOMediaFileFormatBinding.md > >>>> > >>>> Partially based on Matroska decoder code. > >>>> > >>>> Signed-off-by: James Almer <jamrial@gmail.com> > >>>> --- > >>>> libavformat/isom.h | 2 ++ > >>>> libavformat/mov.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > >>>> 2 files changed, 67 insertions(+) > >>>> > >>>> diff --git a/libavformat/isom.h b/libavformat/isom.h > >>>> index d9956cf63a..426f732247 100644 > >>>> --- a/libavformat/isom.h > >>>> +++ b/libavformat/isom.h > >>>> @@ -27,6 +27,7 @@ > >>>> #include <stddef.h> > >>>> #include <stdint.h> > >>>> > >>>> +#include "libavutil/mastering_display_metadata.h" > >>>> #include "libavutil/spherical.h" > >>>> #include "libavutil/stereo3d.h" > >>>> > >>>> @@ -194,6 +195,7 @@ typedef struct MOVStreamContext { > >>>> AVStereo3D *stereo3d; > >>>> AVSphericalMapping *spherical; > >>>> size_t spherical_size; > >>>> + AVMasteringDisplayMetadata *mastering; > >>>> > >>>> uint32_t format; > >>>> > >>>> diff --git a/libavformat/mov.c b/libavformat/mov.c > >>>> index afef53b79a..0b5fd849f3 100644 > >>>> --- a/libavformat/mov.c > >>>> +++ b/libavformat/mov.c > >>>> @@ -4612,6 +4612,60 @@ static int mov_read_tmcd(MOVContext *c, AVIOContext *pb, MOVAtom atom) > >>>> return 0; > >>>> } > >>>> > >>>> +static int mov_read_smdm(MOVContext *c, AVIOContext *pb, MOVAtom atom) > >>>> +{ > >>>> + MOVStreamContext *sc; > >>>> + const int chroma_den = 50000; > >>>> + const int luma_den = 10000; > >>>> + int version; > >>>> + > >>>> + if (c->fc->nb_streams < 1) > >>>> + return AVERROR_INVALIDDATA; > >>>> + > >>>> + sc = c->fc->streams[c->fc->nb_streams - 1]->priv_data; > >>>> + > >>>> + if (atom.size < 5) { > >>>> + av_log(c->fc, AV_LOG_ERROR, "Empty Mastering Display Metadata box\n"); > >>>> + return AVERROR_INVALIDDATA; > >>>> + } > >>>> + > >>>> + version = avio_r8(pb); > >>>> + if (version) { > >>>> + av_log(c->fc, AV_LOG_WARNING, "Unsupported Mastering Display Metadata box version %d\n", version); > >>>> + return 0; > >>>> + } > >>>> + avio_skip(pb, 3); /* flags */ > >>>> + > >>>> + sc->mastering = av_mastering_display_metadata_alloc(); > >>>> + if (!sc->mastering) > >>>> + return AVERROR(ENOMEM); > >>>> + > >>> > >>>> + sc->mastering->display_primaries[0][0] = > >>>> + av_make_q(lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den); > >>> > >>> this is not optimal, precission wise > >>> av_d2q() should produce closer rationals > >>> alternativly av_reduce() can be used directly > >>> > >>> but iam not sure why a fixed chroma_den and luma_den is fixed > >>> maybe iam missing something > >> > >> Does > >> > >> for (i = 0; i < 3; i++) > >> for (j = 0; j < 2; j++) > >> av_reduce(&sc->mastering->display_primaries[i][j].num, > >> &sc->mastering->display_primaries[i][j].den, > >> lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), > >> chroma_den, chroma_den); > > > > Why do you use > > lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den > > and > > chroma_den > > > > instead of > > avio_rb16(pb) > > and > > 1 << 16 > > > > ? > > > > To follow the origin spec the vp9 in mp4 spec and the > AVMasteringDisplayMetadata API quote and are based on. > > --------------- > display_primaries_x[ c ] and display_primaries_y[ c ] specify the > normalized x and y chromaticity coordinates, respectively, of the colour > primary component c of the mastering display in increments of 0.00002, > according to the CIE 1931 definition of x and y as specified in ISO > 11664-1 (see also ISO 11664-3 and CIE 15). For describing mastering > displays that use red, green and blue colour primaries, it is suggested > that index value c equal to 0 should correspond to the green primary, c > equal to 1 should correspond to the blue primary and c equal to 2 should > correspond to the red colour primary (see also Annex E and Table E.3). > The values of display_primaries_x[ c ] and display_primaries_y[ c ] > shall be in the range of 0 to 50 000, inclusive. > > white_point_x and white_point_y specify the normalized x and y > chromaticity coordinates, respectively, of the white point of the > mastering display in normalized increments of 0.00002, according to the > CIE 1931 definition of x and y as specified in ISO 11664-1 (see also ISO > 11664-3 and CIE 15). The values of white_point_x and white_point_y shall > be in the range of 0 to 50 000. > > max_display_mastering_luminance and min_display_mastering_luminance > specify the nominal maximum and minimum display luminance, respectively, > of the mastering display in units of 0.0001 candelas per square metre. [...] > Notice how all values break the increments of 0.00002 (50000 > denominator) and 0.0001 (10000 denominator) constrains when i just take > the 0.16, 24.8 and 18.14 fixed point values stored in mp4 and dump them > into AVMasteringDisplayMetadata as is, like you suggest. ok, i mistakely assumed the specifications where consistent or at least one a superset of others. Please ignore my comment about the patch [...]
On 5/27/2017 1:12 PM, Michael Niedermayer wrote: > ok, i mistakely assumed the specifications where consistent or at > least one a superset of others. > > Please ignore my comment about the patch Pushed then. Thanks.
diff --git a/libavformat/isom.h b/libavformat/isom.h index d9956cf63a..426f732247 100644 --- a/libavformat/isom.h +++ b/libavformat/isom.h @@ -27,6 +27,7 @@ #include <stddef.h> #include <stdint.h> +#include "libavutil/mastering_display_metadata.h" #include "libavutil/spherical.h" #include "libavutil/stereo3d.h" @@ -194,6 +195,7 @@ typedef struct MOVStreamContext { AVStereo3D *stereo3d; AVSphericalMapping *spherical; size_t spherical_size; + AVMasteringDisplayMetadata *mastering; uint32_t format; diff --git a/libavformat/mov.c b/libavformat/mov.c index afef53b79a..0b5fd849f3 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -4612,6 +4612,60 @@ static int mov_read_tmcd(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +static int mov_read_smdm(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + MOVStreamContext *sc; + const int chroma_den = 50000; + const int luma_den = 10000; + int version; + + if (c->fc->nb_streams < 1) + return AVERROR_INVALIDDATA; + + sc = c->fc->streams[c->fc->nb_streams - 1]->priv_data; + + if (atom.size < 5) { + av_log(c->fc, AV_LOG_ERROR, "Empty Mastering Display Metadata box\n"); + return AVERROR_INVALIDDATA; + } + + version = avio_r8(pb); + if (version) { + av_log(c->fc, AV_LOG_WARNING, "Unsupported Mastering Display Metadata box version %d\n", version); + return 0; + } + avio_skip(pb, 3); /* flags */ + + sc->mastering = av_mastering_display_metadata_alloc(); + if (!sc->mastering) + return AVERROR(ENOMEM); + + sc->mastering->display_primaries[0][0] = + av_make_q(lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den); + sc->mastering->display_primaries[0][1] = + av_make_q(lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den); + sc->mastering->display_primaries[1][0] = + av_make_q(lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den); + sc->mastering->display_primaries[1][1] = + av_make_q(lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den); + sc->mastering->display_primaries[2][0] = + av_make_q(lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den); + sc->mastering->display_primaries[2][1] = + av_make_q(lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den); + sc->mastering->white_point[0] = + av_make_q(lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den); + sc->mastering->white_point[1] = + av_make_q(lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den); + sc->mastering->max_luminance = + av_make_q(lrint(((double)avio_rb32(pb) / (1 << 8)) * luma_den), luma_den); + sc->mastering->min_luminance = + av_make_q(lrint(((double)avio_rb32(pb) / (1 << 14)) * luma_den), luma_den); + sc->mastering->has_primaries = 1; + sc->mastering->has_luminance = 1; + + return 0; +} + static int mov_read_st3d(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; @@ -5398,6 +5452,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('s','t','3','d'), mov_read_st3d }, /* stereoscopic 3D video box */ { MKTAG('s','v','3','d'), mov_read_sv3d }, /* spherical video box */ { MKTAG('d','O','p','s'), mov_read_dops }, +{ MKTAG('S','m','D','m'), mov_read_smdm }, { 0, NULL } }; @@ -5822,6 +5877,7 @@ static int mov_read_close(AVFormatContext *s) av_freep(&sc->stereo3d); av_freep(&sc->spherical); + av_freep(&sc->mastering); } if (mov->dv_demux) { @@ -6172,6 +6228,15 @@ static int mov_read_header(AVFormatContext *s) sc->spherical = NULL; } + if (sc->mastering) { + err = av_stream_add_side_data(st, AV_PKT_DATA_MASTERING_DISPLAY_METADATA, + (uint8_t *)sc->mastering, + sizeof(*sc->mastering)); + if (err < 0) + return err; + + sc->mastering = NULL; + } break; } }
As defined in "VP Codec ISO Media File Format Binding v1.0" https://github.com/webmproject/vp9-dash/blob/master/VPCodecISOMediaFileFormatBinding.md Partially based on Matroska decoder code. Signed-off-by: James Almer <jamrial@gmail.com> --- libavformat/isom.h | 2 ++ libavformat/mov.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+)