mirror of
https://mirror.skon.top/https://github.com/FFmpeg/FFmpeg
synced 2026-04-20 21:00:41 +08:00
fftools/ffmpeg_demux: add options to override mastering display and content light level metadata
Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
@@ -1569,6 +1569,27 @@ Set whether on display the image should be vertically flipped.
|
|||||||
|
|
||||||
See the @code{-display_rotation} option for more details.
|
See the @code{-display_rotation} option for more details.
|
||||||
|
|
||||||
|
@item -mastering_display[:@var{stream_specifier}] @var{G(%u,%u)B(%u,%u)R(%u,%u)WP(%u,%u)L(%u,%u)} (@emph{input,per-stream})
|
||||||
|
Set video mastering display metadata.
|
||||||
|
|
||||||
|
@var{G(%u,%u)B(%u,%u)R(%u,%u)WP(%u,%u)L(%u,%u)} is a string specifying
|
||||||
|
X,Y display primaries for GBR channels and white point (WP) in units of
|
||||||
|
0.00002, and max-min luminance (L) values in units of 0.0001 candela per
|
||||||
|
meter square. The values are unsigned integers representing the numerator
|
||||||
|
of a rational with an implicit denominator of 50000 for GBR and (WP), and
|
||||||
|
implicit denominator 10000 for (L).
|
||||||
|
|
||||||
|
This option overrides the mastering display metadata stored in the file,
|
||||||
|
if any.
|
||||||
|
|
||||||
|
@item -content_light[:@var{stream_specifier}] @var{%u,%u} (@emph{input,per-stream})
|
||||||
|
Set video content light metadata.
|
||||||
|
|
||||||
|
@var{%u,%u} is a string specifying max content light level and maximum picture
|
||||||
|
average light level.
|
||||||
|
|
||||||
|
This option overrides the content light metadata stored in the file, if any.
|
||||||
|
|
||||||
@item -vn (@emph{input/output})
|
@item -vn (@emph{input/output})
|
||||||
As an input option, blocks all video streams of a file from being filtered or
|
As an input option, blocks all video streams of a file from being filtered or
|
||||||
being automatically selected or mapped for any output. See @code{-discard}
|
being automatically selected or mapped for any output. See @code{-discard}
|
||||||
|
|||||||
@@ -218,6 +218,8 @@ typedef struct OptionsContext {
|
|||||||
SpecifierOptList display_rotations;
|
SpecifierOptList display_rotations;
|
||||||
SpecifierOptList display_hflips;
|
SpecifierOptList display_hflips;
|
||||||
SpecifierOptList display_vflips;
|
SpecifierOptList display_vflips;
|
||||||
|
SpecifierOptList mastering_displays;
|
||||||
|
SpecifierOptList content_lights;
|
||||||
SpecifierOptList rc_overrides;
|
SpecifierOptList rc_overrides;
|
||||||
SpecifierOptList intra_matrices;
|
SpecifierOptList intra_matrices;
|
||||||
SpecifierOptList inter_matrices;
|
SpecifierOptList inter_matrices;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include "libavutil/display.h"
|
#include "libavutil/display.h"
|
||||||
#include "libavutil/error.h"
|
#include "libavutil/error.h"
|
||||||
#include "libavutil/intreadwrite.h"
|
#include "libavutil/intreadwrite.h"
|
||||||
|
#include "libavutil/mastering_display_metadata.h"
|
||||||
#include "libavutil/mem.h"
|
#include "libavutil/mem.h"
|
||||||
#include "libavutil/opt.h"
|
#include "libavutil/opt.h"
|
||||||
#include "libavutil/parseutils.h"
|
#include "libavutil/parseutils.h"
|
||||||
@@ -68,6 +69,8 @@ typedef struct DemuxStream {
|
|||||||
int autorotate;
|
int autorotate;
|
||||||
int apply_cropping;
|
int apply_cropping;
|
||||||
int force_display_matrix;
|
int force_display_matrix;
|
||||||
|
int force_mastering_display;
|
||||||
|
int force_content_light;
|
||||||
int drop_changed;
|
int drop_changed;
|
||||||
|
|
||||||
|
|
||||||
@@ -1248,6 +1251,125 @@ static int add_display_matrix_to_stream(const OptionsContext *o,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int add_mastering_display_to_stream(const OptionsContext *o,
|
||||||
|
AVFormatContext *ctx, InputStream *ist)
|
||||||
|
{
|
||||||
|
AVStream *st = ist->st;
|
||||||
|
DemuxStream *ds = ds_from_ist(ist);
|
||||||
|
AVMasteringDisplayMetadata *master_display;
|
||||||
|
AVPacketSideData *sd;
|
||||||
|
const char *p = NULL;
|
||||||
|
const int chroma_den = 50000;
|
||||||
|
const int luma_den = 10000;
|
||||||
|
size_t size;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
opt_match_per_stream_str(ist, &o->mastering_displays, ctx, st, &p);
|
||||||
|
|
||||||
|
if (!p)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
master_display = av_mastering_display_metadata_alloc_size(&size);
|
||||||
|
if (!master_display)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
|
ret = sscanf(p,
|
||||||
|
"G(%u,%u)B(%u,%u)R(%u,%u)WP(%u,%u)L(%u,%u)",
|
||||||
|
(unsigned*)&master_display->display_primaries[1][0].num,
|
||||||
|
(unsigned*)&master_display->display_primaries[1][1].num,
|
||||||
|
(unsigned*)&master_display->display_primaries[2][0].num,
|
||||||
|
(unsigned*)&master_display->display_primaries[2][1].num,
|
||||||
|
(unsigned*)&master_display->display_primaries[0][0].num,
|
||||||
|
(unsigned*)&master_display->display_primaries[0][1].num,
|
||||||
|
(unsigned*)&master_display->white_point[0].num,
|
||||||
|
(unsigned*)&master_display->white_point[1].num,
|
||||||
|
(unsigned*)&master_display->max_luminance.num,
|
||||||
|
(unsigned*)&master_display->min_luminance.num);
|
||||||
|
|
||||||
|
if (ret != 10 ||
|
||||||
|
(unsigned)(master_display->display_primaries[1][0].num | master_display->display_primaries[1][1].num |
|
||||||
|
master_display->display_primaries[2][0].num | master_display->display_primaries[2][1].num |
|
||||||
|
master_display->display_primaries[0][0].num | master_display->display_primaries[0][1].num |
|
||||||
|
master_display->white_point[0].num | master_display->white_point[1].num) > UINT16_MAX ||
|
||||||
|
(unsigned)(master_display->max_luminance.num | master_display->min_luminance.num) > INT_MAX ||
|
||||||
|
master_display->min_luminance.num > master_display->max_luminance.num) {
|
||||||
|
av_freep(&master_display);
|
||||||
|
av_log(ist, AV_LOG_ERROR, "Failed to parse mastering display option\n");
|
||||||
|
return AVERROR(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
master_display->display_primaries[1][0].den = chroma_den;
|
||||||
|
master_display->display_primaries[1][1].den = chroma_den;
|
||||||
|
master_display->display_primaries[2][0].den = chroma_den;
|
||||||
|
master_display->display_primaries[2][1].den = chroma_den;
|
||||||
|
master_display->display_primaries[0][0].den = chroma_den;
|
||||||
|
master_display->display_primaries[0][1].den = chroma_den;
|
||||||
|
master_display->white_point[0].den = chroma_den;
|
||||||
|
master_display->white_point[1].den = chroma_den;
|
||||||
|
master_display->max_luminance.den = luma_den;
|
||||||
|
master_display->min_luminance.den = luma_den;
|
||||||
|
|
||||||
|
master_display->has_primaries = 1;
|
||||||
|
master_display->has_luminance = 1;
|
||||||
|
|
||||||
|
sd = av_packet_side_data_add(&st->codecpar->coded_side_data,
|
||||||
|
&st->codecpar->nb_coded_side_data,
|
||||||
|
AV_PKT_DATA_MASTERING_DISPLAY_METADATA,
|
||||||
|
(uint8_t *)master_display, size, 0);
|
||||||
|
if (!sd) {
|
||||||
|
av_freep(&master_display);
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
ds->force_mastering_display = 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_content_light_to_stream(const OptionsContext *o,
|
||||||
|
AVFormatContext *ctx, InputStream *ist)
|
||||||
|
{
|
||||||
|
AVStream *st = ist->st;
|
||||||
|
DemuxStream *ds = ds_from_ist(ist);
|
||||||
|
AVContentLightMetadata *cll;
|
||||||
|
AVPacketSideData *sd;
|
||||||
|
const char *p = NULL;
|
||||||
|
size_t size;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
opt_match_per_stream_str(ist, &o->content_lights, ctx, st, &p);
|
||||||
|
|
||||||
|
if (!p)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
cll = av_content_light_metadata_alloc(&size);
|
||||||
|
if (!cll)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
|
ret = sscanf(p, "%u,%u",
|
||||||
|
(unsigned*)&cll->MaxCLL,
|
||||||
|
(unsigned*)&cll->MaxFALL);
|
||||||
|
|
||||||
|
if (ret != 2 || (unsigned)(cll->MaxCLL | cll->MaxFALL) > UINT16_MAX) {
|
||||||
|
av_freep(&cll);
|
||||||
|
av_log(ist, AV_LOG_ERROR, "Failed to parse content light option\n");
|
||||||
|
return AVERROR(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
sd = av_packet_side_data_add(&st->codecpar->coded_side_data,
|
||||||
|
&st->codecpar->nb_coded_side_data,
|
||||||
|
AV_PKT_DATA_CONTENT_LIGHT_LEVEL,
|
||||||
|
(uint8_t *)cll, size, 0);
|
||||||
|
if (!sd) {
|
||||||
|
av_freep(&cll);
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
ds->force_content_light = 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const char *input_stream_item_name(void *obj)
|
static const char *input_stream_item_name(void *obj)
|
||||||
{
|
{
|
||||||
const DemuxStream *ds = obj;
|
const DemuxStream *ds = obj;
|
||||||
@@ -1301,6 +1423,7 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
|
|||||||
const char *bsfs = NULL;
|
const char *bsfs = NULL;
|
||||||
char *next;
|
char *next;
|
||||||
const char *discard_str = NULL;
|
const char *discard_str = NULL;
|
||||||
|
AVBPrint bp;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ds = demux_stream_alloc(d, st);
|
ds = demux_stream_alloc(d, st);
|
||||||
@@ -1366,6 +1489,14 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
ret = add_mastering_display_to_stream(o, ic, ist);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = add_content_light_to_stream(o, ic, ist);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
opt_match_per_stream_str(ist, &o->hwaccels, ic, st, &hwaccel);
|
opt_match_per_stream_str(ist, &o->hwaccels, ic, st, &hwaccel);
|
||||||
opt_match_per_stream_str(ist, &o->hwaccel_output_formats, ic, st,
|
opt_match_per_stream_str(ist, &o->hwaccel_output_formats, ic, st,
|
||||||
&hwaccel_output_format);
|
&hwaccel_output_format);
|
||||||
@@ -1483,15 +1614,27 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
|
|||||||
av_dict_set_int(&ds->decoder_opts, "apply_cropping",
|
av_dict_set_int(&ds->decoder_opts, "apply_cropping",
|
||||||
ds->apply_cropping && ds->apply_cropping != CROP_CONTAINER, 0);
|
ds->apply_cropping && ds->apply_cropping != CROP_CONTAINER, 0);
|
||||||
|
|
||||||
|
av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
|
||||||
if (ds->force_display_matrix) {
|
if (ds->force_display_matrix) {
|
||||||
char buf[32];
|
|
||||||
if (av_dict_get(ds->decoder_opts, "side_data_prefer_packet", NULL, 0))
|
if (av_dict_get(ds->decoder_opts, "side_data_prefer_packet", NULL, 0))
|
||||||
buf[0] = ',';
|
av_bprintf(&bp, ",");
|
||||||
else
|
av_bprintf(&bp, "displaymatrix");
|
||||||
buf[0] = '\0';
|
|
||||||
av_strlcat(buf, "displaymatrix", sizeof(buf));
|
|
||||||
av_dict_set(&ds->decoder_opts, "side_data_prefer_packet", buf, AV_DICT_APPEND);
|
|
||||||
}
|
}
|
||||||
|
if (ds->force_mastering_display) {
|
||||||
|
if (bp.len || av_dict_get(ds->decoder_opts, "side_data_prefer_packet", NULL, 0))
|
||||||
|
av_bprintf(&bp, ",");
|
||||||
|
av_bprintf(&bp, "mastering_display_metadata");
|
||||||
|
}
|
||||||
|
if (ds->force_content_light) {
|
||||||
|
if (bp.len || av_dict_get(ds->decoder_opts, "side_data_prefer_packet", NULL, 0))
|
||||||
|
av_bprintf(&bp, ",");
|
||||||
|
av_bprintf(&bp, "content_light_level");
|
||||||
|
}
|
||||||
|
if (bp.len) {
|
||||||
|
av_bprint_finalize(&bp, NULL);
|
||||||
|
av_dict_set(&ds->decoder_opts, "side_data_prefer_packet", bp.str, AV_DICT_APPEND);
|
||||||
|
}
|
||||||
|
|
||||||
/* Attached pics are sparse, therefore we would not want to delay their decoding
|
/* Attached pics are sparse, therefore we would not want to delay their decoding
|
||||||
* till EOF. */
|
* till EOF. */
|
||||||
if (ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC)
|
if (ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC)
|
||||||
|
|||||||
@@ -1940,6 +1940,12 @@ const OptionDef options[] = {
|
|||||||
{ .off = OFFSET(display_vflips) },
|
{ .off = OFFSET(display_vflips) },
|
||||||
"set display vertical flip for stream(s) "
|
"set display vertical flip for stream(s) "
|
||||||
"(overrides any display rotation if it is not set)"},
|
"(overrides any display rotation if it is not set)"},
|
||||||
|
{ "mastering_display", OPT_TYPE_STRING, OPT_VIDEO | OPT_PERSTREAM | OPT_INPUT | OPT_EXPERT,
|
||||||
|
{ .off = OFFSET(mastering_displays) },
|
||||||
|
"set SMPTE2084 mastering display color volume info" },
|
||||||
|
{ "content_light", OPT_TYPE_STRING, OPT_VIDEO | OPT_PERSTREAM | OPT_INPUT | OPT_EXPERT,
|
||||||
|
{ .off = OFFSET(content_lights) },
|
||||||
|
"set SMPTE2084 Max CLL and Max FALL values" },
|
||||||
{ "vn", OPT_TYPE_BOOL, OPT_VIDEO | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT,
|
{ "vn", OPT_TYPE_BOOL, OPT_VIDEO | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT,
|
||||||
{ .off = OFFSET(video_disable) },
|
{ .off = OFFSET(video_disable) },
|
||||||
"disable video" },
|
"disable video" },
|
||||||
|
|||||||
Reference in New Issue
Block a user