DCADEC_API int dcadec_frame_parse_header(const uint8_t *data, size_t *size) { struct bitstream bits; uint8_t header[DCADEC_FRAME_HEADER_SIZE]; size_t header_size, frame_size; int ret; if (!data || !size) return -DCADEC_EINVAL; if ((ret = dcadec_frame_convert_bitstream(header, &header_size, data, DCADEC_FRAME_HEADER_SIZE)) < 0) return ret; bits_init(&bits, header, header_size); switch (bits_get(&bits, 32)) { case SYNC_WORD_CORE: { bool normal_frame = bits_get1(&bits); int deficit_samples = bits_get(&bits, 5) + 1; int npcmblocks; if (normal_frame && deficit_samples != 32) return -DCADEC_ENOSYNC; bits_skip1(&bits); npcmblocks = bits_get(&bits, 7) + 1; if ((npcmblocks & 7) && (npcmblocks < 6 || normal_frame)) return -DCADEC_ENOSYNC; frame_size = bits_get(&bits, 14) + 1; if (frame_size < 96) return -DCADEC_ENOSYNC; if (ret & DCADEC_BITSTREAM_BE14) *size = frame_size * 8 / 14 * 2; else *size = frame_size; return DCADEC_FRAME_TYPE_CORE; } case SYNC_WORD_EXSS: { bool wide_hdr; bits_skip(&bits, 10); wide_hdr = bits_get1(&bits); header_size = bits_get(&bits, 8 + 4 * wide_hdr) + 1; if ((header_size & 3) || header_size < DCADEC_FRAME_HEADER_SIZE) return -DCADEC_ENOSYNC; frame_size = bits_get(&bits, 16 + 4 * wide_hdr) + 1; if ((frame_size & 3) || frame_size < header_size) return -DCADEC_ENOSYNC; *size = frame_size; return DCADEC_FRAME_TYPE_EXSS; } default: return -DCADEC_ENOSYNC; } }
static void parse_lbr_parameters(struct exss_asset *asset) { struct exss_parser *exss = asset->parser; // Size of LBR component in extension substream asset->lbr_size = bits_get(&exss->bits, 14) + 1; // LBR sync word present flag if (bits_get1(&exss->bits)) // LBR sync distance bits_skip(&exss->bits, 2); }
static void parse_xll_parameters(struct exss_asset *asset) { struct exss_parser *exss = asset->parser; // Size of XLL data in extension substream asset->xll_size = bits_get(&exss->bits, exss->exss_size_nbits) + 1; // XLL sync word present flag asset->xll_sync_present = bits_get1(&exss->bits); if (asset->xll_sync_present) { // Peak bit rate smoothing buffer size bits_skip(&exss->bits, 4); // Number of bits for XLL decoding delay int xll_delay_nbits = bits_get(&exss->bits, 5) + 1; // Initial XLL decoding delay in frames asset->xll_delay_nframes = bits_get(&exss->bits, xll_delay_nbits); // Number of bytes offset to XLL sync asset->xll_sync_offset = bits_get(&exss->bits, exss->exss_size_nbits); } else { asset->xll_delay_nframes = 0; asset->xll_sync_offset = 0; } }
static int parse_descriptor(struct exss_asset *asset) { struct exss_parser *exss = asset->parser; int i, j, ret, descr_pos = exss->bits.index; // Size of audio asset descriptor in bytes int descr_size = bits_get(&exss->bits, 9) + 1; // Audio asset identifier asset->asset_index = bits_get(&exss->bits, 3); // // Per stream static metadata // if (exss->static_fields_present) { // Asset type descriptor presence if (bits_get1(&exss->bits)) // Asset type descriptor bits_skip(&exss->bits, 4); // Language descriptor presence if (bits_get1(&exss->bits)) // Language descriptor bits_skip(&exss->bits, 24); // Additional textual information presence if (bits_get1(&exss->bits)) { // Byte size of additional text info int text_size = bits_get(&exss->bits, 10) + 1; // Additional textual information string bits_skip(&exss->bits, text_size * 8); } // PCM bit resolution asset->pcm_bit_res = bits_get(&exss->bits, 5) + 1; // Maximum sample rate asset->max_sample_rate = exss_sample_rates[bits_get(&exss->bits, 4)]; // Total number of channels asset->nchannels_total = bits_get(&exss->bits, 8) + 1; // One to one map channel to speakers asset->one_to_one_map_ch_to_spkr = bits_get1(&exss->bits); if (asset->one_to_one_map_ch_to_spkr) { // Embedded stereo flag if (asset->nchannels_total > 2) asset->embedded_stereo = bits_get1(&exss->bits); // Embedded 6 channels flag if (asset->nchannels_total > 6) asset->embedded_6ch = bits_get1(&exss->bits); // Speaker mask enabled flag asset->spkr_mask_enabled = bits_get1(&exss->bits); int spkr_mask_nbits = 0; if (asset->spkr_mask_enabled) { // Number of bits for speaker activity mask spkr_mask_nbits = (bits_get(&exss->bits, 2) + 1) << 2; // Loudspeaker activity mask asset->spkr_mask = bits_get(&exss->bits, spkr_mask_nbits); } // Number of speaker remapping sets int spkr_remap_nsets = bits_get(&exss->bits, 3); if (spkr_remap_nsets && !spkr_mask_nbits) { exss_err("Speaker mask disabled yet there are remapping sets"); return -DCADEC_EBADDATA; } // Standard loudspeaker layout mask int nspeakers[8]; for (i = 0; i < spkr_remap_nsets; i++) nspeakers[i] = count_chs_for_mask(bits_get(&exss->bits, spkr_mask_nbits)); for (i = 0; i < spkr_remap_nsets; i++) { // Number of channels to be decoded for speaker remapping int nch_for_remaps = bits_get(&exss->bits, 5) + 1; for (j = 0; j < nspeakers[i]; j++) { // Decoded channels to output speaker mapping mask int remap_ch_mask = bits_get(&exss->bits, nch_for_remaps); // Loudspeaker remapping codes int ncodes = dca_popcount(remap_ch_mask); bits_skip(&exss->bits, ncodes * 5); } } } else { asset->embedded_stereo = false; asset->embedded_6ch = false; asset->spkr_mask_enabled = false; asset->spkr_mask = 0; // Representation type asset->representation_type = bits_get(&exss->bits, 3); } } // // DRC, DNC and mixing metadata // // Dynamic range coefficient presence flag bool drc_present = bits_get1(&exss->bits); // Code for dynamic range coefficient if (drc_present) bits_skip(&exss->bits, 8); // Dialog normalization presence flag if (bits_get1(&exss->bits)) // Dialog normalization code bits_skip(&exss->bits, 5); // DRC for stereo downmix if (drc_present && asset->embedded_stereo) bits_skip(&exss->bits, 8); // Mixing metadata presence flag if (exss->mix_metadata_enabled && bits_get1(&exss->bits)) { // External mixing flag bits_skip1(&exss->bits); // Post mixing / replacement gain adjustment bits_skip(&exss->bits, 6); // DRC prior to mixing if (bits_get(&exss->bits, 2) == 3) // Custom code for mixing DRC bits_skip(&exss->bits, 8); else // Limit for mixing DRC bits_skip(&exss->bits, 3); // Scaling type for channels of main audio // Scaling parameters of main audio if (bits_get1(&exss->bits)) for (i = 0; i < exss->nmixoutconfigs; i++) bits_skip(&exss->bits, 6 * exss->nmixoutchs[i]); else bits_skip(&exss->bits, 6 * exss->nmixoutconfigs); int nchannels_dmix = asset->nchannels_total; if (asset->embedded_6ch) nchannels_dmix += 6; if (asset->embedded_stereo) nchannels_dmix += 2; for (i = 0; i < exss->nmixoutconfigs; i++) { for (j = 0; j < nchannels_dmix; j++) { if (!exss->nmixoutchs[i]) { exss_err("Invalid speaker layout mask for mixing configuration"); return -DCADEC_EBADDATA; } // Mix output mask int mix_map_mask = bits_get(&exss->bits, exss->nmixoutchs[i]); // Mixing coefficients int nmixcoefs = dca_popcount(mix_map_mask); bits_skip(&exss->bits, 6 * nmixcoefs); } } } // // Decoder navigation data // // Coding mode for the asset asset->coding_mode = bits_get(&exss->bits, 2); // Coding components used in asset switch (asset->coding_mode) { case 0: // Coding mode that may contain multiple coding components asset->extension_mask = bits_get(&exss->bits, 12); if (asset->extension_mask & EXSS_CORE) { // Size of core component in extension substream asset->core_size = bits_get(&exss->bits, 14) + 1; // Core sync word present flag if (bits_get1(&exss->bits)) // Core sync distance bits_skip(&exss->bits, 2); } if (asset->extension_mask & EXSS_XBR) // Size of XBR extension in extension substream asset->xbr_size = bits_get(&exss->bits, 14) + 1; if (asset->extension_mask & EXSS_XXCH) // Size of XXCH extension in extension substream asset->xxch_size = bits_get(&exss->bits, 14) + 1; if (asset->extension_mask & EXSS_X96) // Size of X96 extension in extension substream asset->x96_size = bits_get(&exss->bits, 12) + 1; if (asset->extension_mask & EXSS_LBR) parse_lbr_parameters(asset); if (asset->extension_mask & EXSS_XLL) parse_xll_parameters(asset); if (asset->extension_mask & EXSS_RSV1) bits_skip(&exss->bits, 16); if (asset->extension_mask & EXSS_RSV2) bits_skip(&exss->bits, 16); break; case 1: // Loss-less coding mode without CBR component asset->extension_mask = EXSS_XLL; parse_xll_parameters(asset); break; case 2: // Low bit rate mode asset->extension_mask = EXSS_LBR; parse_lbr_parameters(asset); break; case 3: // Auxiliary coding mode asset->extension_mask = 0; // Size of auxiliary coded data bits_skip(&exss->bits, 14); // Auxiliary codec identification bits_skip(&exss->bits, 8); // Aux sync word present flag if (bits_get1(&exss->bits)) // Aux sync distance bits_skip(&exss->bits, 3); break; } if (asset->extension_mask & EXSS_XLL) // DTS-HD stream ID asset->hd_stream_id = bits_get(&exss->bits, 3); // One to one mixing flag // Per channel main audio scaling flag // Main audio scaling codes // Decode asset in secondary decoder flag // Revision 2 DRC metadata // Reserved // Zero pad if ((ret = bits_seek(&exss->bits, descr_pos + descr_size * 8)) < 0) exss_err("Read past end of asset descriptor"); return ret; }
int exss_parse(struct exss_parser *exss, uint8_t *data, int size) { int i, j, ret; bits_init(&exss->bits, data, size); // Extension substream sync word bits_skip(&exss->bits, 32); // User defined bits bits_skip(&exss->bits, 8); // Extension substream index exss->exss_index = bits_get(&exss->bits, 2); // Flag indicating short or long header size bool wide_hdr = bits_get1(&exss->bits); // Extension substream header length int header_size = bits_get(&exss->bits, 8 + 4 * wide_hdr) + 1; // Check CRC if ((ret = bits_check_crc(&exss->bits, 32 + 8, header_size * 8)) < 0) { exss_err("Invalid EXSS header checksum"); return ret; } exss->exss_size_nbits = 16 + 4 * wide_hdr; // Number of bytes of extension substream exss->exss_size = bits_get(&exss->bits, exss->exss_size_nbits) + 1; if (exss->exss_size > size) { exss_err("Packet too short for EXSS frame"); return -DCADEC_EBADDATA; } // Per stream static fields presence flag exss->static_fields_present = bits_get1(&exss->bits); if (exss->static_fields_present) { // Reference clock code bits_skip(&exss->bits, 2); // Extension substream frame duration bits_skip(&exss->bits, 3); // Timecode presence flag if (bits_get1(&exss->bits)) { // Timecode data bits_skip(&exss->bits, 32); bits_skip(&exss->bits, 4); } // Number of defined audio presentations exss->npresents = bits_get(&exss->bits, 3) + 1; // Number of audio assets in extension substream exss->nassets = bits_get(&exss->bits, 3) + 1; // Reject unsupported features for now if (exss->npresents > 1 || exss->nassets > 1) { exss_err_once("Multiple audio presentations " "and/or assets are not supported"); return -DCADEC_ENOSUP; } // Active extension substream mask for audio presentation int active_exss_mask[8]; for (i = 0; i < exss->npresents; i++) active_exss_mask[i] = bits_get(&exss->bits, exss->exss_index + 1); // Active audio asset mask for (i = 0; i < exss->npresents; i++) for (j = 0; j <= exss->exss_index; j++) if (active_exss_mask[i] & (1 << j)) bits_skip(&exss->bits, 8); // Mixing metadata enable flag exss->mix_metadata_enabled = bits_get1(&exss->bits); if (exss->mix_metadata_enabled) { // Mixing metadata adjustment level bits_skip(&exss->bits, 2); // Number of bits for mixer output speaker activity mask int spkr_mask_nbits = (bits_get(&exss->bits, 2) + 1) << 2; // Number of mixing configurations exss->nmixoutconfigs = bits_get(&exss->bits, 2) + 1; // Speaker layout mask for mixer output channels for (i = 0; i < exss->nmixoutconfigs; i++) exss->nmixoutchs[i] = count_chs_for_mask(bits_get(&exss->bits, spkr_mask_nbits)); } } else { exss->npresents = 1; exss->nassets = 1; } // Reallocate assets if (ta_zalloc_fast(exss, &exss->assets, exss->nassets, sizeof(struct exss_asset)) < 0) return -DCADEC_ENOMEM; // Size of encoded asset data in bytes int offset = header_size; for (i = 0; i < exss->nassets; i++) { exss->assets[i].asset_offset = offset; exss->assets[i].asset_size = bits_get(&exss->bits, exss->exss_size_nbits) + 1; offset += exss->assets[i].asset_size; if (offset > exss->exss_size) { exss_err("Asset out of bounds"); return -DCADEC_EBADDATA; } } // Audio asset descriptor for (i = 0; i < exss->nassets; i++) { exss->assets[i].parser = exss; if ((ret = parse_descriptor(&exss->assets[i])) < 0) return ret; if ((ret = set_exss_offsets(&exss->assets[i])) < 0) { exss_err("Invalid extension size in asset descriptor"); return ret; } } // Backward compatible core present // Backward compatible core substream index // Backward compatible core asset index // Reserved // Byte align // CRC16 of extension substream header if ((ret = bits_seek(&exss->bits, header_size * 8)) < 0) exss_err("Read past end of EXSS header"); return ret; }