mirror of
https://gitlab.freedesktop.org/emersion/libdisplay-info.git
synced 2024-11-16 19:48:30 +01:00
cta: add support for Speaker Location data blocks
Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
This commit is contained in:
parent
3edb81e68d
commit
75b21671d0
3 changed files with 171 additions and 0 deletions
69
cta.c
69
cta.c
|
@ -1301,6 +1301,56 @@ parse_room_config_block(struct di_edid_cta *cta,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_speaker_location_block(struct di_edid_cta *cta,
|
||||
struct di_cta_speaker_location_block *sldb,
|
||||
const uint8_t *data, size_t size)
|
||||
{
|
||||
struct di_cta_speaker_locations speaker_loc, *slp;
|
||||
|
||||
if (size < 2) {
|
||||
add_failure(cta, "Speaker Location Data Block: Empty Data Block with length %u.",
|
||||
size);
|
||||
return false;
|
||||
}
|
||||
|
||||
while (size >= 2) {
|
||||
speaker_loc.has_coords = has_bit(data[0], 6);
|
||||
speaker_loc.is_active = has_bit(data[0], 5);
|
||||
speaker_loc.channel_index = get_bit_range(data[0], 4, 0);
|
||||
speaker_loc.speaker_id = get_bit_range(data[1], 4, 0);
|
||||
|
||||
if (has_bit(data[0], 7) || get_bit_range(data[1], 7, 5) != 0) {
|
||||
add_failure(cta, "Speaker Location Data Block: Bits F27-F25, F17 must be 0.");
|
||||
}
|
||||
|
||||
if (speaker_loc.has_coords && size >= 5) {
|
||||
speaker_loc.x = decode_coord(data[2]);
|
||||
speaker_loc.y = decode_coord(data[3]);
|
||||
speaker_loc.z = decode_coord(data[4]);
|
||||
size -= 5;
|
||||
data += 5;
|
||||
} else if (speaker_loc.has_coords) {
|
||||
add_failure(cta, "Speaker Location Data Block: COORD bit "
|
||||
"set but contains no Coordinates.");
|
||||
return false;
|
||||
} else {
|
||||
size -= 2;
|
||||
data += 2;
|
||||
}
|
||||
|
||||
slp = calloc(1, sizeof(*slp));
|
||||
if (!slp)
|
||||
return false;
|
||||
|
||||
*slp = speaker_loc;
|
||||
assert(sldb->locations_len < EDID_CTA_MAX_SPEAKER_LOCATION_BLOCK_ENTRIES);
|
||||
sldb->locations[sldb->locations_len++] = slp;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_data_block(struct di_cta_data_block *data_block)
|
||||
{
|
||||
|
@ -1308,6 +1358,7 @@ destroy_data_block(struct di_cta_data_block *data_block)
|
|||
struct di_cta_video_block *video;
|
||||
struct di_cta_audio_block *audio;
|
||||
struct di_cta_infoframe_block_priv *infoframe;
|
||||
struct di_cta_speaker_location_block *speaker_location;
|
||||
|
||||
switch (data_block->tag) {
|
||||
case DI_CTA_DATA_BLOCK_VIDEO:
|
||||
|
@ -1330,6 +1381,11 @@ destroy_data_block(struct di_cta_data_block *data_block)
|
|||
for (i = 0; i < infoframe->infoframes_len; i++)
|
||||
free(infoframe->infoframes[i]);
|
||||
break;
|
||||
case DI_CTA_DATA_BLOCK_SPEAKER_LOCATION:
|
||||
speaker_location = &data_block->speaker_location;
|
||||
for (i = 0; i < speaker_location->locations_len; i++)
|
||||
free(speaker_location->locations[i]);
|
||||
break;
|
||||
default:
|
||||
break; /* Nothing to do */
|
||||
}
|
||||
|
@ -1455,6 +1511,10 @@ parse_data_block(struct di_edid_cta *cta, uint8_t raw_tag, const uint8_t *data,
|
|||
break;
|
||||
case 20:
|
||||
tag = DI_CTA_DATA_BLOCK_SPEAKER_LOCATION;
|
||||
if (!parse_speaker_location_block(cta,
|
||||
&data_block->speaker_location,
|
||||
data, size))
|
||||
goto skip;
|
||||
break;
|
||||
case 32:
|
||||
tag = DI_CTA_DATA_BLOCK_INFOFRAME;
|
||||
|
@ -1753,6 +1813,15 @@ di_cta_data_block_get_infoframe(const struct di_cta_data_block *block)
|
|||
return &block->infoframe.block;
|
||||
}
|
||||
|
||||
const struct di_cta_speaker_locations *const *
|
||||
di_cta_data_block_get_speaker_locations(const struct di_cta_data_block *block)
|
||||
{
|
||||
if (block->tag != DI_CTA_DATA_BLOCK_SPEAKER_LOCATION) {
|
||||
return NULL;
|
||||
}
|
||||
return (const struct di_cta_speaker_locations *const *) block->speaker_location.locations;
|
||||
}
|
||||
|
||||
const struct di_edid_detailed_timing_def *const *
|
||||
di_edid_cta_get_detailed_timing_defs(const struct di_edid_cta *cta)
|
||||
{
|
||||
|
|
|
@ -57,6 +57,14 @@
|
|||
* InfoFrame Descriptor is 1 byte.
|
||||
*/
|
||||
#define EDID_CTA_INFOFRAME_BLOCK_ENTRIES 61
|
||||
/**
|
||||
* The maximum number of Speaker Location Descriptors in a Speaker Location data
|
||||
* block.
|
||||
*
|
||||
* Each data block has its size described in a 5-bit field, so its maximum size
|
||||
* is 63 bytes, and each Speaker Location Descriptors uses at least 2 byte.
|
||||
*/
|
||||
#define EDID_CTA_MAX_SPEAKER_LOCATION_BLOCK_ENTRIES 31
|
||||
|
||||
struct di_edid_cta {
|
||||
int revision;
|
||||
|
@ -128,6 +136,12 @@ struct di_cta_infoframe_block_priv {
|
|||
size_t infoframes_len;
|
||||
};
|
||||
|
||||
struct di_cta_speaker_location_block {
|
||||
/* NULL-terminated */
|
||||
struct di_cta_speaker_locations *locations[EDID_CTA_MAX_SPEAKER_LOCATION_BLOCK_ENTRIES + 1];
|
||||
size_t locations_len;
|
||||
};
|
||||
|
||||
struct di_cta_data_block {
|
||||
enum di_cta_data_block_tag tag;
|
||||
|
||||
|
@ -157,6 +171,8 @@ struct di_cta_data_block {
|
|||
struct di_cta_infoframe_block_priv infoframe;
|
||||
/* Used for DI_CTA_DATA_BLOCK_ROOM_CONFIG */
|
||||
struct di_cta_room_configuration room_config;
|
||||
/* Used for DI_CTA_DATA_BLOCK_SPEAKER_LOCATION */
|
||||
struct di_cta_speaker_location_block speaker_location;
|
||||
};
|
||||
|
||||
extern const struct di_cta_video_format _di_cta_video_formats[];
|
||||
|
|
|
@ -962,6 +962,92 @@ struct di_cta_room_configuration {
|
|||
const struct di_cta_room_configuration *
|
||||
di_cta_data_block_get_room_configuration(const struct di_cta_data_block *block);
|
||||
|
||||
enum di_cta_speaker_placement {
|
||||
/* FL - Front Left */
|
||||
DI_CTA_SPEAKER_PLACEMENT_FL = 0x00,
|
||||
/* FR - Front Right */
|
||||
DI_CTA_SPEAKER_PLACEMENT_FR = 0x01,
|
||||
/* FC - Front Center */
|
||||
DI_CTA_SPEAKER_PLACEMENT_FC = 0x02,
|
||||
/* LFE1 - Low Frequency Effects 1 */
|
||||
DI_CTA_SPEAKER_PLACEMENT_LFE1 = 0x03,
|
||||
/* BL - Back Left */
|
||||
DI_CTA_SPEAKER_PLACEMENT_BL = 0x04,
|
||||
/* BR - Back Right */
|
||||
DI_CTA_SPEAKER_PLACEMENT_BR = 0x05,
|
||||
/* FLc - Front Left of Center */
|
||||
DI_CTA_SPEAKER_PLACEMENT_FLC = 0x06,
|
||||
/* FRc - Front Right of Center */
|
||||
DI_CTA_SPEAKER_PLACEMENT_FRC = 0x07,
|
||||
/* BC - Back Center */
|
||||
DI_CTA_SPEAKER_PLACEMENT_BC = 0x08,
|
||||
/* LFE2 - Low Frequency Effects 2 */
|
||||
DI_CTA_SPEAKER_PLACEMENT_LFE2 = 0x09,
|
||||
/* SiL - Side Left */
|
||||
DI_CTA_SPEAKER_PLACEMENT_SIL = 0x0a,
|
||||
/* SiR - Side Right */
|
||||
DI_CTA_SPEAKER_PLACEMENT_SIR = 0x0b,
|
||||
/* TpFL - Top Front Left */
|
||||
DI_CTA_SPEAKER_PLACEMENT_TPFL = 0x0c,
|
||||
/* TpFR - Top Front Right */
|
||||
DI_CTA_SPEAKER_PLACEMENT_TPFR = 0x0d,
|
||||
/* TpFC - Top Front Center */
|
||||
DI_CTA_SPEAKER_PLACEMENT_TPFC = 0x0e,
|
||||
/* TpC - Top Center */
|
||||
DI_CTA_SPEAKER_PLACEMENT_TPC = 0x0f,
|
||||
/* TpBL - Top Back Left */
|
||||
DI_CTA_SPEAKER_PLACEMENT_TPBL = 0x10,
|
||||
/* TpBR - Top Back Right */
|
||||
DI_CTA_SPEAKER_PLACEMENT_TPBR = 0x11,
|
||||
/* TpSiL - Top Side Left */
|
||||
DI_CTA_SPEAKER_PLACEMENT_TPSIL = 0x12,
|
||||
/* TpSiR - Top Side Right */
|
||||
DI_CTA_SPEAKER_PLACEMENT_TPSIR = 0x13,
|
||||
/* TpBC - Top Back Center */
|
||||
DI_CTA_SPEAKER_PLACEMENT_TPBC = 0x14,
|
||||
/* BtFC - Bottom Front Center */
|
||||
DI_CTA_SPEAKER_PLACEMENT_BTFC = 0x15,
|
||||
/* BtFL - Bottom Front Left */
|
||||
DI_CTA_SPEAKER_PLACEMENT_BTFL = 0x16,
|
||||
/* BtFR - Bottom Front Right */
|
||||
DI_CTA_SPEAKER_PLACEMENT_BRFR = 0x17,
|
||||
/* FLw - Front Left Wide */
|
||||
DI_CTA_SPEAKER_PLACEMENT_FLW = 0x18,
|
||||
/* FRw - Front Right Wide */
|
||||
DI_CTA_SPEAKER_PLACEMENT_FRW = 0x19,
|
||||
/* LS - Left Surround */
|
||||
DI_CTA_SPEAKER_PLACEMENT_LS = 0x1a,
|
||||
/* RS - Right Surround */
|
||||
DI_CTA_SPEAKER_PLACEMENT_RS = 0x1b,
|
||||
};
|
||||
|
||||
/**
|
||||
* Speaker Location Data Block, defined in section 7.5.16.
|
||||
*/
|
||||
struct di_cta_speaker_locations {
|
||||
/* Index of the audio channel where the audio for the described speaker
|
||||
* is to be transmitted. */
|
||||
int channel_index;
|
||||
/* If the channel shall be rendered on a speaker by the Sink. */
|
||||
bool is_active;
|
||||
/* If the speaker has coordinates instead of a named speaker placement. */
|
||||
bool has_coords;
|
||||
/* The position of the speaker in normalized coordinates. */
|
||||
double x, y, z;
|
||||
/* The named location of the speaker. Only valid if has_coords is false. */
|
||||
enum di_cta_speaker_placement speaker_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an array of Speaker Locations.
|
||||
*
|
||||
* Returns NULL if the data block tag is not DI_CTA_DATA_BLOCK_SPEAKER_LOCATION.
|
||||
*
|
||||
* The returned array is NULL-terminated.
|
||||
*/
|
||||
const struct di_cta_speaker_locations *const *
|
||||
di_cta_data_block_get_speaker_locations(const struct di_cta_data_block *block);
|
||||
|
||||
/**
|
||||
* Get a list of EDID detailed timing definitions.
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue