avformat/mov: add support for 'amve' ambient viewing environment box

As defined in ISOBMFF (ISO/IEC 14496-12) document.

Co-Authored-By: Cosmin Stejerean <cosmin@cosmin.at>
This commit is contained in:
Damiano Galassi 2024-02-04 15:14:12 +00:00 committed by James Almer
parent dda4b25e2d
commit 112d3618ca
4 changed files with 81 additions and 0 deletions

View File

@ -28,6 +28,7 @@
#include "libavutil/intreadwrite.h"
#include "libavutil/log.h"
#include "libavutil/mastering_display_metadata.h"
#include "libavutil/ambient_viewing_environment.h"
#include "libavutil/dovi_meta.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
@ -379,6 +380,17 @@ static void dump_content_light_metadata(void *ctx, const AVPacketSideData *sd,
metadata->MaxCLL, metadata->MaxFALL);
}
static void dump_ambient_viewing_environment_metadata(void *ctx, const AVPacketSideData *sd)
{
const AVAmbientViewingEnvironment *ambient =
(const AVAmbientViewingEnvironment *)sd->data;
av_log(ctx, AV_LOG_INFO, "Ambient Viewing Environment, "
"ambient_illuminance=%f, ambient_light_x=%f, ambient_light_y=%f",
av_q2d(ambient->ambient_illuminance),
av_q2d(ambient->ambient_light_x),
av_q2d(ambient->ambient_light_y));
}
static void dump_spherical(void *ctx, const AVCodecParameters *par,
const AVPacketSideData *sd, int log_level)
{
@ -513,6 +525,9 @@ static void dump_sidedata(void *ctx, const AVStream *st, const char *indent,
av_log(ctx, log_level, "SMPTE ST 12-1:2014: ");
dump_s12m_timecode(ctx, st, sd, log_level);
break;
case AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT:
dump_ambient_viewing_environment_metadata(ctx, sd);
break;
default:
av_log(ctx, log_level, "unknown side data type %d "
"(%"SIZE_SPECIFIER" bytes)", sd->type, sd->size);

View File

@ -29,6 +29,7 @@
#include "libavutil/encryption_info.h"
#include "libavutil/mastering_display_metadata.h"
#include "libavutil/ambient_viewing_environment.h"
#include "libavutil/spherical.h"
#include "libavutil/stereo3d.h"
@ -249,6 +250,8 @@ typedef struct MOVStreamContext {
AVMasteringDisplayMetadata *mastering;
AVContentLightMetadata *coll;
size_t coll_size;
AVAmbientViewingEnvironment *ambient;
size_t ambient_size;
uint32_t format;

View File

@ -6039,6 +6039,31 @@ static int mov_read_clli(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
}
static int mov_read_amve(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
MOVStreamContext *sc;
const int illuminance_den = 10000;
const int ambient_den = 50000;
if (c->fc->nb_streams < 1)
return AVERROR_INVALIDDATA;
sc = c->fc->streams[c->fc->nb_streams - 1]->priv_data;
if (atom.size < 6) {
av_log(c->fc, AV_LOG_ERROR, "Empty Ambient Viewing Environment Info box\n");
return AVERROR_INVALIDDATA;
}
if (sc->ambient){
av_log(c->fc, AV_LOG_WARNING, "Ignoring duplicate AMVE\n");
return 0;
}
sc->ambient = av_ambient_viewing_environment_alloc(&sc->ambient_size);
if (!sc->ambient)
return AVERROR(ENOMEM);
sc->ambient->ambient_illuminance = av_make_q(avio_rb32(pb), illuminance_den);
sc->ambient->ambient_light_x = av_make_q(avio_rb16(pb), ambient_den);
sc->ambient->ambient_light_y = av_make_q(avio_rb16(pb), ambient_den);
return 0;
}
static int mov_read_st3d(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
AVStream *st;
@ -8215,6 +8240,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('i','s','p','e'), mov_read_ispe },
{ MKTAG('i','p','r','p'), mov_read_iprp },
{ MKTAG('i','i','n','f'), mov_read_iinf },
{ MKTAG('a','m','v','e'), mov_read_amve }, /* ambient viewing environment box */
{ 0, NULL }
};
@ -8680,6 +8706,7 @@ static void mov_free_stream_context(AVFormatContext *s, AVStream *st)
av_freep(&sc->spherical);
av_freep(&sc->mastering);
av_freep(&sc->coll);
av_freep(&sc->ambient);
}
static int mov_read_close(AVFormatContext *s)
@ -9072,6 +9099,14 @@ static int mov_read_header(AVFormatContext *s)
sc->coll = NULL;
}
if (sc->ambient) {
if (!av_packet_side_data_add(&st->codecpar->coded_side_data, &st->codecpar->nb_coded_side_data,
AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT,
(uint8_t *) sc->ambient, sc->ambient_size, 0))
return AVERROR(ENOMEM);
sc->ambient = NULL;
}
break;
}
}

View File

@ -2244,6 +2244,33 @@ static int mov_write_mdcv_tag(AVIOContext *pb, MOVTrack *track)
return 32;
}
static int mov_write_amve_tag(AVIOContext *pb, MOVTrack *track)
{
const int illuminance_den = 10000;
const int ambient_den = 50000;
const AVPacketSideData *side_data;
const AVAmbientViewingEnvironment *ambient;
side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
track->st->codecpar->nb_coded_side_data,
AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT);
if (!side_data)
return 0;
ambient = (const AVAmbientViewingEnvironment*)side_data->data;
if (!ambient || !ambient->ambient_illuminance.num)
return 0;
avio_wb32(pb, 16); // size
ffio_wfourcc(pb, "amve");
avio_wb32(pb, rescale_rational(ambient->ambient_illuminance, illuminance_den));
avio_wb16(pb, rescale_rational(ambient->ambient_light_x, ambient_den));
avio_wb16(pb, rescale_rational(ambient->ambient_light_y, ambient_den));
return 16;
}
static void find_compressor(char * compressor_name, int len, MOVTrack *track)
{
AVDictionaryEntry *encoder;
@ -2457,6 +2484,7 @@ static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex
if (track->mode == MODE_MOV || track->mode == MODE_MP4) {
mov_write_clli_tag(pb, track);
mov_write_mdcv_tag(pb, track);
mov_write_amve_tag(pb, track);
}
if (track->mode == MODE_MP4 && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {