From 896b83627e3b600a5f11435889401ad252bfabd3 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 6 Sep 2022 19:21:50 +0200 Subject: [PATCH] cta: parse short audio descriptors Signed-off-by: Simon Ser --- cta.c | 257 +++++++++++++++++++++++++++++ di-edid-decode.c | 133 +++++++++++++++ include/cta.h | 22 +++ include/libdisplay-info/cta.h | 118 +++++++++++++ test/data/msi-mag321curv-dp.diff | 14 +- test/data/samsung-s27a950d-dp.diff | 11 +- test/data/viewsonic-vp2768-dp.diff | 12 +- 7 files changed, 546 insertions(+), 21 deletions(-) diff --git a/cta.c b/cta.c index 5714671..48de1ef 100644 --- a/cta.c +++ b/cta.c @@ -18,6 +18,10 @@ * Exclusive upper bound for the detailed timing definitions in the CTA block. */ #define CTA_DTD_END 127 +/** + * Number of bytes in a CTA short audio descriptor. + */ +#define CTA_SAD_SIZE 3 static void add_failure(struct di_edid_cta *cta, const char fmt[], ...) @@ -85,6 +89,242 @@ parse_video_block(struct di_edid_cta *cta, struct di_cta_video_block *video, return true; } +static bool +parse_sad_format(struct di_edid_cta *cta, const uint8_t data[static CTA_SAD_SIZE], + enum di_cta_audio_format *format) +{ + uint8_t code, code_ext; + + code = get_bit_range(data[0], 6, 3); + switch (code) { + case 0x0: + add_failure_until(cta, 3, + "Audio Data Block: Audio Format Code 0x00 is reserved."); + return false; + case 0x1: + *format = DI_CTA_AUDIO_FORMAT_LPCM; + break; + case 0x2: + *format = DI_CTA_AUDIO_FORMAT_AC3; + break; + case 0x3: + *format = DI_CTA_AUDIO_FORMAT_MPEG1; + break; + case 0x4: + *format = DI_CTA_AUDIO_FORMAT_MP3; + break; + case 0x5: + *format = DI_CTA_AUDIO_FORMAT_MPEG2; + break; + case 0x6: + *format = DI_CTA_AUDIO_FORMAT_AAC_LC; + break; + case 0x7: + *format = DI_CTA_AUDIO_FORMAT_DTS; + break; + case 0x8: + *format = DI_CTA_AUDIO_FORMAT_ATRAC; + break; + case 0x9: + *format = DI_CTA_AUDIO_FORMAT_ONE_BIT_AUDIO; + break; + case 0xA: + *format = DI_CTA_AUDIO_FORMAT_ENHANCED_AC3; + break; + case 0xB: + *format = DI_CTA_AUDIO_FORMAT_DTS_HD; + break; + case 0xC: + *format = DI_CTA_AUDIO_FORMAT_MAT; + break; + case 0xD: + *format = DI_CTA_AUDIO_FORMAT_DST; + break; + case 0xE: + *format = DI_CTA_AUDIO_FORMAT_WMA_PRO; + break; + case 0xF: + code_ext = get_bit_range(data[2], 7, 3); + switch (code_ext) { + case 0x04: + *format = DI_CTA_AUDIO_FORMAT_MPEG4_HE_AAC; + break; + case 0x05: + *format = DI_CTA_AUDIO_FORMAT_MPEG4_HE_AAC_V2; + break; + case 0x06: + *format = DI_CTA_AUDIO_FORMAT_MPEG4_AAC_LC; + break; + case 0x07: + *format = DI_CTA_AUDIO_FORMAT_DRA; + break; + case 0x08: + *format = DI_CTA_AUDIO_FORMAT_MPEG4_HE_AAC_MPEG_SURROUND; + break; + case 0x0A: + *format = DI_CTA_AUDIO_FORMAT_MPEG4_AAC_LC_MPEG_SURROUND; + break; + case 0x0B: + *format = DI_CTA_AUDIO_FORMAT_MPEGH_3D; + break; + case 0x0C: + *format = DI_CTA_AUDIO_FORMAT_AC4; + break; + case 0x0D: + *format = DI_CTA_AUDIO_FORMAT_LPCM_3D; + break; + default: + add_failure_until(cta, 3, + "Audio Data Block: Unknown Audio Ext Format 0x%02x.", + code_ext); + return false; + } + break; + default: + add_failure_until(cta, 3, + "Audio Data Block: Unknown Audio Format 0x%02x.", + code); + return false; + } + + return true; +} + +static bool +parse_sad(struct di_edid_cta *cta, struct di_cta_audio_block *audio, + const uint8_t data[static CTA_SAD_SIZE]) +{ + enum di_cta_audio_format format; + struct di_cta_sad *sad; + struct di_cta_sad_priv *priv; + uint8_t max_channels_lo, mpegh_3d_level; + + if (!parse_sad_format(cta, data, &format)) + return true; + + priv = calloc(1, sizeof(*priv)); + if (!priv) + return false; + + sad = &priv->base; + sad->format = format; + + /* Parse byte 1 */ + switch (format) { + case DI_CTA_AUDIO_FORMAT_LPCM_3D: + max_channels_lo = (uint8_t) (get_bit_range(data[0], 2, 0) | + (get_bit_range(data[0], 7, 7) << 3)); + break; + case DI_CTA_AUDIO_FORMAT_MPEGH_3D: + sad->mpegh_3d = &priv->mpegh_3d; + + mpegh_3d_level = get_bit_range(data[0], 2, 0); + switch (mpegh_3d_level) { + case DI_CTA_SAD_MPEGH_3D_LEVEL_UNSPECIFIED: + case DI_CTA_SAD_MPEGH_3D_LEVEL_1: + case DI_CTA_SAD_MPEGH_3D_LEVEL_2: + case DI_CTA_SAD_MPEGH_3D_LEVEL_3: + case DI_CTA_SAD_MPEGH_3D_LEVEL_4: + case DI_CTA_SAD_MPEGH_3D_LEVEL_5: + priv->mpegh_3d.level = mpegh_3d_level; + break; + default: + add_failure_until(cta, 3, + "Unknown MPEG-H 3D Audio Level 0x%02x.", + mpegh_3d_level); + break; + } + break; + case DI_CTA_AUDIO_FORMAT_AC4: + if (get_bit_range(data[0], 2, 0) != 0) + add_failure_until(cta, 3, "Bits F10-F12 must be 0."); + break; + default: + sad->max_channels = get_bit_range(data[0], 2, 0) + 1; + break; + } + if (format != DI_CTA_AUDIO_FORMAT_LPCM_3D && has_bit(data[0], 7)) + add_failure_until(cta, 3, "Audio Data Block: Bit F17 must be 0."); + + /* Parse byte 2 */ + priv->supported_sample_rates.has_192_khz = has_bit(data[1], 6); + priv->supported_sample_rates.has_176_4_khz = has_bit(data[1], 5); + priv->supported_sample_rates.has_96_khz = has_bit(data[1], 4); + priv->supported_sample_rates.has_88_2_khz = has_bit(data[1], 3); + priv->supported_sample_rates.has_48_khz = has_bit(data[1], 2); + priv->supported_sample_rates.has_44_1_khz = has_bit(data[1], 1); + priv->supported_sample_rates.has_32_khz = has_bit(data[1], 0); + sad->supported_sample_rates = &priv->supported_sample_rates; + if (format == DI_CTA_AUDIO_FORMAT_LPCM_3D) + sad->max_channels = max_channels_lo + | (get_bit_range(data[1], 7, 7) << 4); + else if (has_bit(data[1], 7)) + add_failure_until(cta, 3, "Audio Data Block: Bit F27 must be 0."); + /* TODO: some sample rates are forbidden with some formats */ + + /* Parse byte 3 */ + switch (format) { + case DI_CTA_AUDIO_FORMAT_LPCM: + case DI_CTA_AUDIO_FORMAT_LPCM_3D: + priv->supported_sample_sizes.has_24_bits = has_bit(data[2], 2); + priv->supported_sample_sizes.has_20_bits = has_bit(data[2], 1); + priv->supported_sample_sizes.has_16_bits = has_bit(data[2], 0); + sad->supported_sample_sizes = &priv->supported_sample_sizes; + break; + case DI_CTA_AUDIO_FORMAT_AC3: + case DI_CTA_AUDIO_FORMAT_MPEG1: + case DI_CTA_AUDIO_FORMAT_MP3: + case DI_CTA_AUDIO_FORMAT_MPEG2: + case DI_CTA_AUDIO_FORMAT_AAC_LC: + case DI_CTA_AUDIO_FORMAT_DTS: + case DI_CTA_AUDIO_FORMAT_ATRAC: + sad->max_bitrate_kbs = data[2] * 8; + break; + case DI_CTA_AUDIO_FORMAT_MPEGH_3D: + priv->mpegh_3d.low_complexity_profile = has_bit(data[2], 0); + priv->mpegh_3d.baseline_profile = has_bit(data[2], 1); + break; + case DI_CTA_AUDIO_FORMAT_ONE_BIT_AUDIO: + case DI_CTA_AUDIO_FORMAT_ENHANCED_AC3: + case DI_CTA_AUDIO_FORMAT_DTS_HD: + case DI_CTA_AUDIO_FORMAT_MAT: + case DI_CTA_AUDIO_FORMAT_DST: + case DI_CTA_AUDIO_FORMAT_WMA_PRO: + case DI_CTA_AUDIO_FORMAT_MPEG4_HE_AAC: + case DI_CTA_AUDIO_FORMAT_MPEG4_HE_AAC_V2: + case DI_CTA_AUDIO_FORMAT_MPEG4_AAC_LC: + case DI_CTA_AUDIO_FORMAT_DRA: + case DI_CTA_AUDIO_FORMAT_MPEG4_HE_AAC_MPEG_SURROUND: + case DI_CTA_AUDIO_FORMAT_MPEG4_AAC_LC_MPEG_SURROUND: + case DI_CTA_AUDIO_FORMAT_AC4: + break; /* TODO */ + } + if ((format == DI_CTA_AUDIO_FORMAT_LPCM || format == DI_CTA_AUDIO_FORMAT_WMA_PRO) && + get_bit_range(data[2], 7, 3) != 0) + add_failure_until(cta, 3, "Audio Data Block: Bits F33-F37 must be 0."); + + assert(audio->sads_len < EDID_CTA_MAX_AUDIO_BLOCK_ENTRIES); + audio->sads[audio->sads_len++] = priv; + return true; +} + +static bool +parse_audio_block(struct di_edid_cta *cta, struct di_cta_audio_block *audio, + const uint8_t *data, size_t size) +{ + size_t i; + + if (size % 3 != 0) + add_failure(cta, "Broken CTA-861 audio block length %d.", size); + + for (i = 0; i + 3 <= size; i += 3) { + if (!parse_sad(cta, audio, &data[i])) + return false; + } + + return true; +} + static bool parse_video_cap_block(struct di_edid_cta *cta, struct di_cta_video_cap_block *video_cap, @@ -219,6 +459,7 @@ destroy_data_block(struct di_cta_data_block *data_block) { size_t i; struct di_cta_video_block *video; + struct di_cta_audio_block *audio; switch (data_block->tag) { case DI_CTA_DATA_BLOCK_VIDEO: @@ -226,6 +467,11 @@ destroy_data_block(struct di_cta_data_block *data_block) for (i = 0; i < video->svds_len; i++) free(video->svds[i]); break; + case DI_CTA_DATA_BLOCK_AUDIO: + audio = &data_block->audio; + for (i = 0; i < audio->sads_len; i++) + free(audio->sads[i]); + break; default: break; /* Nothing to do */ } @@ -248,6 +494,8 @@ parse_data_block(struct di_edid_cta *cta, uint8_t raw_tag, const uint8_t *data, switch (raw_tag) { case 1: tag = DI_CTA_DATA_BLOCK_AUDIO; + if (!parse_audio_block(cta, &data_block->audio, data, size)) + goto error; break; case 2: tag = DI_CTA_DATA_BLOCK_VIDEO; @@ -504,6 +752,15 @@ di_cta_data_block_get_svds(const struct di_cta_data_block *block) return (const struct di_cta_svd *const *) block->video.svds; } +const struct di_cta_sad *const * +di_cta_data_block_get_sads(const struct di_cta_data_block *block) +{ + if (block->tag != DI_CTA_DATA_BLOCK_AUDIO) { + return NULL; + } + return (const struct di_cta_sad *const *) block->audio.sads; +} + const struct di_cta_colorimetry_block * di_cta_data_block_get_colorimetry(const struct di_cta_data_block *block) { diff --git a/di-edid-decode.c b/di-edid-decode.c index cc1db3d..445f135 100644 --- a/di-edid-decode.c +++ b/di-edid-decode.c @@ -574,6 +574,134 @@ printf_cta_svds(const struct di_cta_svd *const *svds) } } +static const char * +cta_audio_format_name(enum di_cta_audio_format format) +{ + switch (format) { + case DI_CTA_AUDIO_FORMAT_LPCM: + return "Linear PCM"; + case DI_CTA_AUDIO_FORMAT_AC3: + return "AC-3"; + case DI_CTA_AUDIO_FORMAT_MPEG1: + return "MPEG 1 (Layers 1 & 2)"; + case DI_CTA_AUDIO_FORMAT_MP3: + return "MPEG 1 Layer 3 (MP3)"; + case DI_CTA_AUDIO_FORMAT_MPEG2: + return "MPEG2 (multichannel)"; + case DI_CTA_AUDIO_FORMAT_AAC_LC: + return "AAC LC"; + case DI_CTA_AUDIO_FORMAT_DTS: + return "DTS"; + case DI_CTA_AUDIO_FORMAT_ATRAC: + return "ATRAC"; + case DI_CTA_AUDIO_FORMAT_ONE_BIT_AUDIO: + return "One Bit Audio"; + case DI_CTA_AUDIO_FORMAT_ENHANCED_AC3: + return "Enhanced AC-3 (DD+)"; + case DI_CTA_AUDIO_FORMAT_DTS_HD: + return "DTS-HD"; + case DI_CTA_AUDIO_FORMAT_MAT: + return "MAT (MLP)"; + case DI_CTA_AUDIO_FORMAT_DST: + return "DST"; + case DI_CTA_AUDIO_FORMAT_WMA_PRO: + return "WMA Pro"; + case DI_CTA_AUDIO_FORMAT_MPEG4_HE_AAC: + return "MPEG-4 HE AAC"; + case DI_CTA_AUDIO_FORMAT_MPEG4_HE_AAC_V2: + return "MPEG-4 HE AAC v2"; + case DI_CTA_AUDIO_FORMAT_MPEG4_AAC_LC: + return "MPEG-4 AAC LC"; + case DI_CTA_AUDIO_FORMAT_DRA: + return "DRA"; + case DI_CTA_AUDIO_FORMAT_MPEG4_HE_AAC_MPEG_SURROUND: + return "MPEG-4 HE AAC + MPEG Surround"; + case DI_CTA_AUDIO_FORMAT_MPEG4_AAC_LC_MPEG_SURROUND: + return "MPEG-4 AAC LC + MPEG Surround"; + case DI_CTA_AUDIO_FORMAT_MPEGH_3D: + return "MPEG-H 3D Audio"; + case DI_CTA_AUDIO_FORMAT_AC4: + return "AC-4"; + case DI_CTA_AUDIO_FORMAT_LPCM_3D: + return "L-PCM 3D Audio"; + } + abort(); +} + +static const char * +cta_sad_mpegh_3d_level_name(enum di_cta_sad_mpegh_3d_level level) +{ + switch (level) { + case DI_CTA_SAD_MPEGH_3D_LEVEL_UNSPECIFIED: + return "Unspecified"; + case DI_CTA_SAD_MPEGH_3D_LEVEL_1: + return "Level 1"; + case DI_CTA_SAD_MPEGH_3D_LEVEL_2: + return "Level 2"; + case DI_CTA_SAD_MPEGH_3D_LEVEL_3: + return "Level 3"; + case DI_CTA_SAD_MPEGH_3D_LEVEL_4: + return "Level 4"; + case DI_CTA_SAD_MPEGH_3D_LEVEL_5: + return "Level 5"; + } + abort(); +} + +static void +print_cta_sads(const struct di_cta_sad *const *sads) +{ + size_t i; + const struct di_cta_sad *sad; + + for (i = 0; sads[i] != NULL; i++) { + sad = sads[i]; + + printf(" %s:\n", cta_audio_format_name(sad->format)); + if (sad->max_channels != 0) + printf(" Max channels: %d\n", sad->max_channels); + + if (sad->mpegh_3d) + printf(" MPEG-H 3D Audio Level: %s\n", + cta_sad_mpegh_3d_level_name(sad->mpegh_3d->level)); + + printf(" Supported sample rates (kHz):"); + if (sad->supported_sample_rates->has_192_khz) + printf(" 192"); + if (sad->supported_sample_rates->has_176_4_khz) + printf(" 176.4"); + if (sad->supported_sample_rates->has_96_khz) + printf(" 96"); + if (sad->supported_sample_rates->has_88_2_khz) + printf(" 88.2"); + if (sad->supported_sample_rates->has_48_khz) + printf(" 48"); + if (sad->supported_sample_rates->has_44_1_khz) + printf(" 44.1"); + if (sad->supported_sample_rates->has_32_khz) + printf(" 32"); + printf("\n"); + + if (sad->supported_sample_sizes) { + printf(" Supported sample sizes (bits):"); + if (sad->supported_sample_sizes->has_24_bits) + printf(" 24"); + if (sad->supported_sample_sizes->has_20_bits) + printf(" 20"); + if (sad->supported_sample_sizes->has_16_bits) + printf(" 16"); + printf("\n"); + } + + if (sad->max_bitrate_kbs != 0) + printf(" Maximum bit rate: %d kb/s\n", sad->max_bitrate_kbs); + if (sad->mpegh_3d && sad->mpegh_3d->low_complexity_profile) + printf(" Supports MPEG-H 3D Audio Low Complexity Profile\n"); + if (sad->mpegh_3d && sad->mpegh_3d->baseline_profile) + printf(" Supports MPEG-H 3D Audio Baseline Profile\n"); + } +} + static uint8_t encode_max_luminance(float max) { @@ -698,6 +826,7 @@ print_cta(const struct di_edid_cta *cta) const struct di_cta_data_block *data_block; enum di_cta_data_block_tag data_block_tag; const struct di_cta_svd *const *svds; + const struct di_cta_sad *const *sads; const struct di_cta_video_cap_block *video_cap; const struct di_cta_colorimetry_block *colorimetry; const struct di_cta_hdr_static_metadata_block *hdr_static_metadata; @@ -733,6 +862,10 @@ print_cta(const struct di_edid_cta *cta) svds = di_cta_data_block_get_svds(data_block); printf_cta_svds(svds); break; + case DI_CTA_DATA_BLOCK_AUDIO: + sads = di_cta_data_block_get_sads(data_block); + print_cta_sads(sads); + break; case DI_CTA_DATA_BLOCK_VIDEO_CAP: video_cap = di_cta_data_block_get_video_cap(data_block); printf(" YCbCr quantization: %s\n", diff --git a/include/cta.h b/include/cta.h index 30d3ef0..e3fbe69 100644 --- a/include/cta.h +++ b/include/cta.h @@ -33,6 +33,13 @@ * is 63 bytes, and each SVD uses 1 byte. */ #define EDID_CTA_MAX_VIDEO_BLOCK_ENTRIES 63 +/** + * The maximum number of SAD entries in an audio data block. + * + * Each data block has its size described in a 5-bit field, so its maximum size + * is 63 bytes, and each SAD uses 3 bytes. + */ +#define EDID_CTA_MAX_AUDIO_BLOCK_ENTRIES 21 struct di_edid_cta { int revision; @@ -61,11 +68,26 @@ struct di_cta_video_block { size_t svds_len; }; +struct di_cta_sad_priv { + struct di_cta_sad base; + struct di_cta_sad_sample_rates supported_sample_rates; + struct di_cta_sad_sample_sizes supported_sample_sizes; + struct di_cta_sad_mpegh_3d mpegh_3d; +}; + +struct di_cta_audio_block { + /* NULL-terminated */ + struct di_cta_sad_priv *sads[EDID_CTA_MAX_AUDIO_BLOCK_ENTRIES + 1]; + size_t sads_len; +}; + struct di_cta_data_block { enum di_cta_data_block_tag tag; /* Used for DI_CTA_DATA_BLOCK_VIDEO */ struct di_cta_video_block video; + /* used for DI_CTA_DATA_BLOCK_AUDIO */ + struct di_cta_audio_block audio; /* Used for DI_CTA_DATA_BLOCK_VIDEO_CAP */ struct di_cta_video_cap_block video_cap; /* Used for DI_CTA_DATA_BLOCK_COLORIMETRY */ diff --git a/include/libdisplay-info/cta.h b/include/libdisplay-info/cta.h index 2e3f1e2..42bf3b4 100644 --- a/include/libdisplay-info/cta.h +++ b/include/libdisplay-info/cta.h @@ -117,6 +117,124 @@ enum di_cta_data_block_tag { enum di_cta_data_block_tag di_cta_data_block_get_tag(const struct di_cta_data_block *block); +/** + * Audio formats, defined in tables 37 and 39. + * + * Note, the enum values don't match the specification. + */ +enum di_cta_audio_format { + /* L-PCM */ + DI_CTA_AUDIO_FORMAT_LPCM = 1, + /* AC-3 */ + DI_CTA_AUDIO_FORMAT_AC3, + /* MPEG-1 (layers 1 & 2) */ + DI_CTA_AUDIO_FORMAT_MPEG1, + /* MP3 */ + DI_CTA_AUDIO_FORMAT_MP3, + /* MPEG-2 */ + DI_CTA_AUDIO_FORMAT_MPEG2, + /* AAC LC */ + DI_CTA_AUDIO_FORMAT_AAC_LC, + /* DTS */ + DI_CTA_AUDIO_FORMAT_DTS, + /* ATRAC */ + DI_CTA_AUDIO_FORMAT_ATRAC, + /* One Bit Audio */ + DI_CTA_AUDIO_FORMAT_ONE_BIT_AUDIO, + /* Enhanced AC-3 */ + DI_CTA_AUDIO_FORMAT_ENHANCED_AC3, + /* DTS-HD and DTS-UHD */ + DI_CTA_AUDIO_FORMAT_DTS_HD, + /* MAT */ + DI_CTA_AUDIO_FORMAT_MAT, + /* DST */ + DI_CTA_AUDIO_FORMAT_DST, + /* WMA Pro */ + DI_CTA_AUDIO_FORMAT_WMA_PRO, + + /* MPEG-4 HE AAC */ + DI_CTA_AUDIO_FORMAT_MPEG4_HE_AAC, + /* MPEG-4 HE AAC v2 */ + DI_CTA_AUDIO_FORMAT_MPEG4_HE_AAC_V2, + /* MPEG-4 AAC LC */ + DI_CTA_AUDIO_FORMAT_MPEG4_AAC_LC, + /* DRA */ + DI_CTA_AUDIO_FORMAT_DRA, + /* MPEG-4 HE AAC + MPEG Surround */ + DI_CTA_AUDIO_FORMAT_MPEG4_HE_AAC_MPEG_SURROUND, + /* MPEG-4 AAC LC + MPEG Surround */ + DI_CTA_AUDIO_FORMAT_MPEG4_AAC_LC_MPEG_SURROUND, + /* MPEG-H 3D Audio */ + DI_CTA_AUDIO_FORMAT_MPEGH_3D, + /* AC-4 */ + DI_CTA_AUDIO_FORMAT_AC4, + /* L-PCM 3D Audio */ + DI_CTA_AUDIO_FORMAT_LPCM_3D, +}; + +struct di_cta_sad_sample_rates { + bool has_192_khz; /* 192 kHz */ + bool has_176_4_khz; /* 176.4 kHz */ + bool has_96_khz; /* 96 kHz */ + bool has_88_2_khz; /* 88.2 kHz */ + bool has_48_khz; /* 48 kHz */ + bool has_44_1_khz; /* 44.1 kHz */ + bool has_32_khz; /* 32 kHz */ +}; + +struct di_cta_sad_sample_sizes { + bool has_24_bits; /* 24 bits */ + bool has_20_bits; /* 20 bits */ + bool has_16_bits; /* 16 bits */ +}; + +enum di_cta_sad_mpegh_3d_level { + DI_CTA_SAD_MPEGH_3D_LEVEL_UNSPECIFIED = 0, + DI_CTA_SAD_MPEGH_3D_LEVEL_1 = 1, + DI_CTA_SAD_MPEGH_3D_LEVEL_2 = 2, + DI_CTA_SAD_MPEGH_3D_LEVEL_3 = 3, + DI_CTA_SAD_MPEGH_3D_LEVEL_4 = 4, + DI_CTA_SAD_MPEGH_3D_LEVEL_5 = 5, +}; + +struct di_cta_sad_mpegh_3d { + /* Maximum supported MPEG-H 3D level, zero if unspecified */ + enum di_cta_sad_mpegh_3d_level level; + /* True if MPEG-H 3D Audio Low Complexity Profile is supported */ + bool low_complexity_profile; + /* True if MPEG-H 3D Audio Baseline Profile is supported */ + bool baseline_profile; +}; + +/** + * A CTA short audio descriptor (SAD), defined in section 7.5.2. + */ +struct di_cta_sad { + /* Format */ + enum di_cta_audio_format format; + /* Maximum number of channels, zero if unset */ + int32_t max_channels; + /* Supported sample rates */ + const struct di_cta_sad_sample_rates *supported_sample_rates; + /* Supported sample sizes, NULL if unset */ + const struct di_cta_sad_sample_sizes *supported_sample_sizes; + /* Maximum bitrate (kb/s), zero if unset */ + int32_t max_bitrate_kbs; + /* Additional metadata for MPEG-H 3D Audio, NULL unless format is + * DI_CTA_AUDIO_FORMAT_MPEGH_3D */ + const struct di_cta_sad_mpegh_3d *mpegh_3d; +}; + +/** + * Get an array of short audio descriptors from a CTA data block. + * + * Returns NULL if the data block tag is not DI_CTA_DATA_BLOCK_AUDIO. + * + * The returned array is NULL-terminated. + */ +const struct di_cta_sad *const * +di_cta_data_block_get_sads(const struct di_cta_data_block *data_block); + /** * Over- and underscan capability. */ diff --git a/test/data/msi-mag321curv-dp.diff b/test/data/msi-mag321curv-dp.diff index 6f7af20..6bf1130 100644 --- a/test/data/msi-mag321curv-dp.diff +++ b/test/data/msi-mag321curv-dp.diff @@ -23,7 +23,7 @@ Detailed Timing Descriptors: DTD 1: 3840x2160 59.996625 Hz 16:9 133.312 kHz 533.250000 MHz (700 mm x 390 mm) Hfront 48 Hsync 32 Hback 80 Hpol P -@@ -73,57 +73,32 @@ +@@ -73,57 +73,36 @@ Supports YCbCr 4:2:2 Native detailed modes: 1 Video Data Block: @@ -62,10 +62,10 @@ + VIC 97 + VIC 96 Audio Data Block: -- Linear PCM: -- Max channels: 2 -- Supported sample rates (kHz): 96 48 44.1 32 -- Supported sample sizes (bits): 24 20 16 + Linear PCM: + Max channels: 2 + Supported sample rates (kHz): 96 48 44.1 32 + Supported sample sizes (bits): 24 20 16 Speaker Allocation Data Block: - FL/FR - Front Left/Right - Vendor-Specific Data Block (HDMI), OUI 00-0C-03: @@ -98,7 +98,7 @@ HDR Static Metadata Data Block: Electro optical transfer functions: Traditional gamma - SDR luminance range -@@ -133,7 +108,6 @@ +@@ -133,7 +112,6 @@ Static metadata type 1 Desired content max luminance: 92 (366.802 cd/m^2) Desired content max frame-average luminance: 92 (366.802 cd/m^2) @@ -106,7 +106,7 @@ Detailed Timing Descriptors: DTD 2: 2560x1440 59.950550 Hz 16:9 88.787 kHz 241.500000 MHz (700 mm x 390 mm) Hfront 48 Hsync 32 Hback 80 Hpol P -@@ -144,29 +118,12 @@ +@@ -144,29 +122,12 @@ DTD 4: 1280x768 59.870228 Hz 5:3 47.776 kHz 79.500000 MHz (700 mm x 390 mm) Hfront 64 Hsync 128 Hback 192 Hpol N Vfront 3 Vsync 7 Vback 20 Vpol P diff --git a/test/data/samsung-s27a950d-dp.diff b/test/data/samsung-s27a950d-dp.diff index a863e01..203d14c 100644 --- a/test/data/samsung-s27a950d-dp.diff +++ b/test/data/samsung-s27a950d-dp.diff @@ -9,14 +9,9 @@ Display Product Name: 'S27A950D' Extension blocks: 1 Checksum: 0x1b -@@ -41,29 +39,13 @@ - Basic audio support - Native detailed modes: 0 - Audio Data Block: -- Linear PCM: -- Max channels: 2 -- Supported sample rates (kHz): 48 44.1 32 -- Supported sample sizes (bits): 24 20 16 +@@ -46,24 +44,12 @@ + Supported sample rates (kHz): 48 44.1 32 + Supported sample sizes (bits): 24 20 16 Speaker Allocation Data Block: - FL/FR - Front Left/Right -Checksum: 0x71 Unused space in Extension Block: 115 bytes diff --git a/test/data/viewsonic-vp2768-dp.diff b/test/data/viewsonic-vp2768-dp.diff index cee7ed9..d59c4fe 100644 --- a/test/data/viewsonic-vp2768-dp.diff +++ b/test/data/viewsonic-vp2768-dp.diff @@ -23,7 +23,7 @@ Detailed Timing Descriptors: DTD 1: 2560x1440 59.950550 Hz 16:9 88.787 kHz 241.500000 MHz (597 mm x 336 mm) Hfront 48 Hsync 32 Hback 80 Hpol P -@@ -79,35 +79,29 @@ +@@ -79,35 +79,33 @@ Supports YCbCr 4:2:2 Native detailed modes: 1 Video Data Block: @@ -56,10 +56,10 @@ + VIC 34 + VIC 1 Audio Data Block: -- Linear PCM: -- Max channels: 2 -- Supported sample rates (kHz): 192 176.4 96 88.2 48 44.1 32 -- Supported sample sizes (bits): 24 20 16 + Linear PCM: + Max channels: 2 + Supported sample rates (kHz): 192 176.4 96 88.2 48 44.1 32 + Supported sample sizes (bits): 24 20 16 Speaker Allocation Data Block: - FL/FR - Front Left/Right Detailed Timing Descriptors: @@ -75,7 +75,7 @@ DTD 4: 1280x720 60.000000 Hz 16:9 45.000 kHz 74.250000 MHz (597 mm x 336 mm) Hfront 110 Hsync 40 Hback 220 Hpol P Vfront 5 Vsync 5 Vback 20 Vpol P -@@ -117,28 +111,14 @@ +@@ -117,28 +115,14 @@ DTD 6: 1920x1080 50.000000 Hz 16:9 56.250 kHz 148.500000 MHz (597 mm x 336 mm) Hfront 528 Hsync 44 Hback 148 Hpol P Vfront 4 Vsync 5 Vback 36 Vpol P