From 483c5b0b2ff7b5d00144e008d8356b3bab41e584 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Fri, 1 May 2020 23:41:44 +0200 Subject: [PATCH] Add support for parsing (and dumping) Static Metadata extension (extension 3.5) --- src/devtools/mpls_dump.c | 42 +++++++++++++++++- src/libbluray/bdnav/mpls_data.h | 23 ++++++++++ src/libbluray/bdnav/mpls_parse.c | 75 ++++++++++++++++++++++++++++++-- 3 files changed, 135 insertions(+), 5 deletions(-) diff --git a/src/devtools/mpls_dump.c b/src/devtools/mpls_dump.c index 424818ef..1e3a6e63 100644 --- a/src/devtools/mpls_dump.c +++ b/src/devtools/mpls_dump.c @@ -372,6 +372,35 @@ _show_pip_metadata(MPLS_PL *pl, int level) } } +static void +_show_static_metadata_entry(MPLS_STATIC_METADATA *entry, int level) +{ + indent_printf(level, "Dynamic Range Type: %d", entry->dynamic_range_type); + indent_printf(level, "Mastering Display Primary R (X, Y): (%f, %f)", (float)entry->display_primaries_x[primary_red]/50000L, (float)entry->display_primaries_y[primary_red]/50000L); + indent_printf(level, "Mastering Display Primary G (X, Y): (%f, %f)", (float)entry->display_primaries_x[primary_green]/50000L, (float)entry->display_primaries_y[primary_green]/50000L); + indent_printf(level, "Mastering Display Primary B (X, Y): (%f, %f)", (float)entry->display_primaries_x[primary_blue]/50000L, (float)entry->display_primaries_y[primary_blue]/50000L); + indent_printf(level, "White Point (X, Y): (%f, %f)", (float)entry->white_point_x/50000L, (float)entry->white_point_y/50000L); + indent_printf(level, "Display Mastering Luminance (min, max): (%.4f, %.4f)", (float)entry->min_display_mastering_luminance/10000L, (float)entry->max_display_mastering_luminance); + indent_printf(level, "Maximum Frame Average Light Level (MaxFALL): %d", entry->max_CLL); + indent_printf(level, "Maximum Content Light Level (MaxCLL): %d", entry->max_FALL); +} + +static void +_show_static_metadata(MPLS_PL *pl, int level) +{ + int ii; + + for (ii = 0; ii < pl->ext_static_metadata_count; ii++) { + MPLS_STATIC_METADATA *data; + + data = &pl->ext_static_metadata[ii]; + + indent_printf(level, "Static metadata entry %d:", ii); + _show_static_metadata_entry(data, level+1); + } + printf("\n"); +} + static void _show_sub_paths(MPLS_PL *pl, int level) { @@ -400,6 +429,7 @@ _show_sub_paths_ss(MPLS_PL *pl, int level) indent_printf(level, "Extension Sub Path %d:", ss); _show_sub_path(sub, level+1); } + printf("\n"); } static uint32_t @@ -490,7 +520,7 @@ _filter_repeats(MPLS_PL *pl, int repeats) return 1; } -static int clip_list = 0, playlist_info = 0, chapter_marks = 0, sub_paths = 0, pip_metadata = 0; +static int clip_list = 0, playlist_info = 0, chapter_marks = 0, sub_paths = 0, pip_metadata = 0, static_metadata = 0; static int repeats = 0, seconds = 0, dups = 0; static MPLS_PL* @@ -551,6 +581,9 @@ _process_file(char *name, MPLS_PL *pl_list[], int pl_count) _show_sub_paths(pl, 1); _show_sub_paths_ss(pl, 1); } + if (static_metadata) { + _show_static_metadata(pl, 1); + } return pl; } @@ -567,6 +600,7 @@ _usage(char *cmd) " c - Show chapter marks\n" " p - Show sub paths\n" " P - Show picture-in-picture metadata\n" +" S - Show static metadata\n" " r - Filter out titles that have >N repeating clips\n" " d - Filter out duplicate titles\n" " s - Filter out short titles\n" @@ -576,7 +610,7 @@ _usage(char *cmd) exit(EXIT_FAILURE); } -#define OPTS "vlicpPfr:ds:" +#define OPTS "vlicpPSfr:ds:" static int _qsort_str_cmp(const void *a, const void *b) @@ -628,6 +662,10 @@ main(int argc, char *argv[]) pip_metadata = 1; break; + case 'S': + static_metadata = 1; + break; + case 'd': dups = 1; break; diff --git a/src/libbluray/bdnav/mpls_data.h b/src/libbluray/bdnav/mpls_data.h index 1529f079..f5511f1d 100644 --- a/src/libbluray/bdnav/mpls_data.h +++ b/src/libbluray/bdnav/mpls_data.h @@ -173,6 +173,25 @@ typedef struct { MPLS_PIP_DATA *data; } MPLS_PIP_METADATA; +typedef enum { + primary_green, + primary_blue, + primary_red +} mpls_static_primaries; /* They are stored as GBR, we would like to show them as RGB */ + +typedef struct mpls_static_metadata +{ + uint8_t dynamic_range_type; + uint16_t display_primaries_x[3]; + uint16_t display_primaries_y[3]; + uint16_t white_point_x; + uint16_t white_point_y; + uint16_t max_display_mastering_luminance; + uint16_t min_display_mastering_luminance; + uint16_t max_CLL; + uint16_t max_FALL; +} MPLS_STATIC_METADATA; + typedef struct mpls_pl { uint32_t type_indicator; /* 'MPLS' */ @@ -196,6 +215,10 @@ typedef struct mpls_pl uint16_t ext_pip_data_count; MPLS_PIP_METADATA *ext_pip_data; // pip metadata extension + // extension data (Static Metadata) + uint8_t ext_static_metadata_count; + MPLS_STATIC_METADATA *ext_static_metadata; + } MPLS_PL; #endif // BLURAY_MPLS_DATA_H_ diff --git a/src/libbluray/bdnav/mpls_parse.c b/src/libbluray/bdnav/mpls_parse.c index bff8fc72..79552384 100644 --- a/src/libbluray/bdnav/mpls_parse.c +++ b/src/libbluray/bdnav/mpls_parse.c @@ -960,6 +960,77 @@ _parse_subpath_extension(BITSTREAM *bits, MPLS_PL *pl) return 0; } +static int +_parse_static_metadata(BITSTREAM *bits, MPLS_STATIC_METADATA *data) +{ + int ii; + + if (bs_avail(bits) < 28 * 8) { + BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_static_metadata: unexpected end of file\n"); + return 0; + } + + data->dynamic_range_type = bs_read(bits, 4); + bs_skip(bits,4); + bs_skip(bits,24); + for(ii = 0; ii < 3; ii++){ + data->display_primaries_x[ii] = bs_read(bits, 16); + data->display_primaries_y[ii] = bs_read(bits, 16); + } + data->white_point_x = bs_read(bits, 16); + data->white_point_y = bs_read(bits, 16); + data->max_display_mastering_luminance = bs_read(bits, 16); + data->min_display_mastering_luminance = bs_read(bits, 16); + data->max_CLL = bs_read(bits, 16); + data->max_FALL = bs_read(bits, 16); + + return 1; +} + +static int +_parse_static_metadata_extension(BITSTREAM *bits, MPLS_PL *pl) +{ + MPLS_STATIC_METADATA *static_metadata; + uint32_t len; + int ii; + + len = bs_read(bits, 32); + if (len < 32) { // At least one static metadata entry + return 0; + } + if (bs_avail(bits) < len * 8) { + BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_static_metadata_extension: unexpected end of file\n"); + return 0; + } + + uint8_t sm_count = bs_read(bits, 8); + if (sm_count < 1) { + return 0; + } + bs_skip(bits, 24); + + static_metadata = calloc(sm_count, sizeof(MPLS_STATIC_METADATA)); + if (!static_metadata) { + BD_DEBUG(DBG_CRIT, "out of memory\n"); + return 0; + } + + for (ii = 0; ii < sm_count; ii++) { + if (!_parse_static_metadata(bits, &static_metadata[ii])) { + goto error; + } + } + pl->ext_static_metadata = static_metadata; + pl->ext_static_metadata_count = sm_count; + + return 1; + + error: + BD_DEBUG(DBG_NAV | DBG_CRIT, "error parsing static metadata extension\n"); + X_FREE(static_metadata); + return 0; +} + static int _parse_mpls_extension(BITSTREAM *bits, int id1, int id2, void *handle) { @@ -984,9 +1055,7 @@ _parse_mpls_extension(BITSTREAM *bits, int id1, int id2, void *handle) if (id1 == 3) { if (id2 == 5) { - // UHD extension - BD_DEBUG(DBG_NAV, "_parse_mpls_extension(): unhandled extension %d.%d\n", id1, id2); - return 0; + return _parse_static_metadata_extension(bits, pl); } }