📄 mlpdec.c
字号:
return -1; } memset(&m->bypassed_lsbs[s->blockpos][0], 0, s->blocksize * sizeof(m->bypassed_lsbs[0])); for (i = 0; i < s->blocksize; i++) { if (read_huff_channels(m, gbp, substr, i) < 0) return -1; } for (ch = s->min_channel; ch <= s->max_channel; ch++) { filter_channel(m, substr, ch); } s->blockpos += s->blocksize; if (s->data_check_present) { if (get_bits_count(gbp) != expected_stream_pos) av_log(m->avctx, AV_LOG_ERROR, "block data length mismatch\n"); skip_bits(gbp, 8); } return 0;}/** Data table used for TrueHD noise generation function. */static const int8_t noise_table[256] = { 30, 51, 22, 54, 3, 7, -4, 38, 14, 55, 46, 81, 22, 58, -3, 2, 52, 31, -7, 51, 15, 44, 74, 30, 85, -17, 10, 33, 18, 80, 28, 62, 10, 32, 23, 69, 72, 26, 35, 17, 73, 60, 8, 56, 2, 6, -2, -5, 51, 4, 11, 50, 66, 76, 21, 44, 33, 47, 1, 26, 64, 48, 57, 40, 38, 16, -10, -28, 92, 22, -18, 29, -10, 5, -13, 49, 19, 24, 70, 34, 61, 48, 30, 14, -6, 25, 58, 33, 42, 60, 67, 17, 54, 17, 22, 30, 67, 44, -9, 50, -11, 43, 40, 32, 59, 82, 13, 49, -14, 55, 60, 36, 48, 49, 31, 47, 15, 12, 4, 65, 1, 23, 29, 39, 45, -2, 84, 69, 0, 72, 37, 57, 27, 41, -15, -16, 35, 31, 14, 61, 24, 0, 27, 24, 16, 41, 55, 34, 53, 9, 56, 12, 25, 29, 53, 5, 20, -20, -8, 20, 13, 28, -3, 78, 38, 16, 11, 62, 46, 29, 21, 24, 46, 65, 43, -23, 89, 18, 74, 21, 38, -12, 19, 12, -19, 8, 15, 33, 4, 57, 9, -8, 36, 35, 26, 28, 7, 83, 63, 79, 75, 11, 3, 87, 37, 47, 34, 40, 39, 19, 20, 42, 27, 34, 39, 77, 13, 42, 59, 64, 45, -1, 32, 37, 45, -5, 53, -6, 7, 36, 50, 23, 6, 32, 9, -21, 18, 71, 27, 52, -25, 31, 35, 42, -1, 68, 63, 52, 26, 43, 66, 37, 41, 25, 40, 70,};/** Noise generation functions. * I'm not sure what these are for - they seem to be some kind of pseudorandom * sequence generators, used to generate noise data which is used when the * channels are rematrixed. I'm not sure if they provide a practical benefit * to compression, or just obfuscate the decoder. Are they for some kind of * dithering? *//** Generate two channels of noise, used in the matrix when * restart sync word == 0x31ea. */static void generate_2_noise_channels(MLPDecodeContext *m, unsigned int substr){ SubStream *s = &m->substream[substr]; unsigned int i; uint32_t seed = s->noisegen_seed; unsigned int maxchan = s->max_matrix_channel; for (i = 0; i < s->blockpos; i++) { uint16_t seed_shr7 = seed >> 7; m->sample_buffer[i][maxchan+1] = ((int8_t)(seed >> 15)) << s->noise_shift; m->sample_buffer[i][maxchan+2] = ((int8_t) seed_shr7) << s->noise_shift; seed = (seed << 16) ^ seed_shr7 ^ (seed_shr7 << 5); } s->noisegen_seed = seed;}/** Generate a block of noise, used when restart sync word == 0x31eb. */static void fill_noise_buffer(MLPDecodeContext *m, unsigned int substr){ SubStream *s = &m->substream[substr]; unsigned int i; uint32_t seed = s->noisegen_seed; for (i = 0; i < m->access_unit_size_pow2; i++) { uint8_t seed_shr15 = seed >> 15; m->noise_buffer[i] = noise_table[seed_shr15]; seed = (seed << 8) ^ seed_shr15 ^ (seed_shr15 << 5); } s->noisegen_seed = seed;}/** Apply the channel matrices in turn to reconstruct the original audio * samples. */static void rematrix_channels(MLPDecodeContext *m, unsigned int substr){ SubStream *s = &m->substream[substr]; unsigned int mat, src_ch, i; unsigned int maxchan; maxchan = s->max_matrix_channel; if (!s->noise_type) { generate_2_noise_channels(m, substr); maxchan += 2; } else { fill_noise_buffer(m, substr); } for (mat = 0; mat < s->num_primitive_matrices; mat++) { int matrix_noise_shift = s->matrix_noise_shift[mat]; unsigned int dest_ch = s->matrix_out_ch[mat]; int32_t mask = MSB_MASK(s->quant_step_size[dest_ch]); /* TODO: DSPContext? */ for (i = 0; i < s->blockpos; i++) { int64_t accum = 0; for (src_ch = 0; src_ch <= maxchan; src_ch++) { accum += (int64_t)m->sample_buffer[i][src_ch] * s->matrix_coeff[mat][src_ch]; } if (matrix_noise_shift) { uint32_t index = s->num_primitive_matrices - mat; index = (i * (index * 2 + 1) + index) & (m->access_unit_size_pow2 - 1); accum += m->noise_buffer[index] << (matrix_noise_shift + 7); } m->sample_buffer[i][dest_ch] = ((accum >> 14) & mask) + m->bypassed_lsbs[i][mat]; } }}/** Write the audio data into the output buffer. */static int output_data_internal(MLPDecodeContext *m, unsigned int substr, uint8_t *data, unsigned int *data_size, int is32){ SubStream *s = &m->substream[substr]; unsigned int i, ch = 0; int32_t *data_32 = (int32_t*) data; int16_t *data_16 = (int16_t*) data; if (*data_size < (s->max_channel + 1) * s->blockpos * (is32 ? 4 : 2)) return -1; for (i = 0; i < s->blockpos; i++) { for (ch = 0; ch <= s->max_channel; ch++) { int32_t sample = m->sample_buffer[i][ch] << s->output_shift[ch]; s->lossless_check_data ^= (sample & 0xffffff) << ch; if (is32) *data_32++ = sample << 8; else *data_16++ = sample >> 8; } } *data_size = i * ch * (is32 ? 4 : 2); return 0;}static int output_data(MLPDecodeContext *m, unsigned int substr, uint8_t *data, unsigned int *data_size){ if (m->avctx->sample_fmt == SAMPLE_FMT_S32) return output_data_internal(m, substr, data, data_size, 1); else return output_data_internal(m, substr, data, data_size, 0);}/** XOR together all the bytes of a buffer. * Does this belong in dspcontext? */static uint8_t calculate_parity(const uint8_t *buf, unsigned int buf_size){ uint32_t scratch = 0; const uint8_t *buf_end = buf + buf_size; for (; buf < buf_end - 3; buf += 4) scratch ^= *((const uint32_t*)buf); scratch ^= scratch >> 16; scratch ^= scratch >> 8; for (; buf < buf_end; buf++) scratch ^= *buf; return scratch;}/** Read an access unit from the stream. * Returns < 0 on error, 0 if not enough data is present in the input stream * otherwise returns the number of bytes consumed. */static int read_access_unit(AVCodecContext *avctx, void* data, int *data_size, const uint8_t *buf, int buf_size){ MLPDecodeContext *m = avctx->priv_data; GetBitContext gb; unsigned int length, substr; unsigned int substream_start; unsigned int header_size = 4; unsigned int substr_header_size = 0; uint8_t substream_parity_present[MAX_SUBSTREAMS]; uint16_t substream_data_len[MAX_SUBSTREAMS]; uint8_t parity_bits; if (buf_size < 4) return 0; length = (AV_RB16(buf) & 0xfff) * 2; if (length > buf_size) return -1; init_get_bits(&gb, (buf + 4), (length - 4) * 8); if (show_bits_long(&gb, 31) == (0xf8726fba >> 1)) { dprintf(m->avctx, "Found major sync.\n"); if (read_major_sync(m, &gb) < 0) goto error; header_size += 28; } if (!m->params_valid) { av_log(m->avctx, AV_LOG_WARNING, "Stream parameters not seen; skipping frame.\n"); *data_size = 0; return length; } substream_start = 0; for (substr = 0; substr < m->num_substreams; substr++) { int extraword_present, checkdata_present, end; extraword_present = get_bits1(&gb); skip_bits1(&gb); checkdata_present = get_bits1(&gb); skip_bits1(&gb); end = get_bits(&gb, 12) * 2; substr_header_size += 2; if (extraword_present) { skip_bits(&gb, 16); substr_header_size += 2; } if (end + header_size + substr_header_size > length) { av_log(m->avctx, AV_LOG_ERROR, "Indicated length of substream %d data goes off end of " "packet.\n", substr); end = length - header_size - substr_header_size; } if (end < substream_start) { av_log(avctx, AV_LOG_ERROR, "Indicated end offset of substream %d data " "is smaller than calculated start offset.\n", substr); goto error; } if (substr > m->max_decoded_substream) continue; substream_parity_present[substr] = checkdata_present; substream_data_len[substr] = end - substream_start; substream_start = end; } parity_bits = calculate_parity(buf, 4); parity_bits ^= calculate_parity(buf + header_size, substr_header_size); if ((((parity_bits >> 4) ^ parity_bits) & 0xF) != 0xF) { av_log(avctx, AV_LOG_ERROR, "Parity check failed.\n"); goto error; } buf += header_size + substr_header_size; for (substr = 0; substr <= m->max_decoded_substream; substr++) { SubStream *s = &m->substream[substr]; init_get_bits(&gb, buf, substream_data_len[substr] * 8); s->blockpos = 0; do { if (get_bits1(&gb)) { if (get_bits1(&gb)) { /* A restart header should be present. */ if (read_restart_header(m, &gb, buf, substr) < 0) goto next_substr; s->restart_seen = 1; } if (!s->restart_seen) { av_log(m->avctx, AV_LOG_ERROR, "No restart header present in substream %d.\n", substr); goto next_substr; } if (read_decoding_params(m, &gb, substr) < 0) goto next_substr; } if (!s->restart_seen) { av_log(m->avctx, AV_LOG_ERROR, "No restart header present in substream %d.\n", substr); goto next_substr; } if (read_block_data(m, &gb, substr) < 0) return -1; } while ((get_bits_count(&gb) < substream_data_len[substr] * 8) && get_bits1(&gb) == 0); skip_bits(&gb, (-get_bits_count(&gb)) & 15); if (substream_data_len[substr] * 8 - get_bits_count(&gb) >= 32 && (show_bits_long(&gb, 32) == 0xd234d234 || show_bits_long(&gb, 20) == 0xd234e)) { skip_bits(&gb, 18); if (substr == m->max_decoded_substream) av_log(m->avctx, AV_LOG_INFO, "End of stream indicated.\n"); if (get_bits1(&gb)) { int shorten_by = get_bits(&gb, 13); shorten_by = FFMIN(shorten_by, s->blockpos); s->blockpos -= shorten_by; } else skip_bits(&gb, 13); } if (substream_data_len[substr] * 8 - get_bits_count(&gb) >= 16 && substream_parity_present[substr]) { uint8_t parity, checksum; parity = calculate_parity(buf, substream_data_len[substr] - 2); if ((parity ^ get_bits(&gb, 8)) != 0xa9) av_log(m->avctx, AV_LOG_ERROR, "Substream %d parity check failed.\n", substr); checksum = mlp_checksum8(buf, substream_data_len[substr] - 2); if (checksum != get_bits(&gb, 8)) av_log(m->avctx, AV_LOG_ERROR, "Substream %d checksum failed.\n", substr); } if (substream_data_len[substr] * 8 != get_bits_count(&gb)) { av_log(m->avctx, AV_LOG_ERROR, "substream %d length mismatch\n", substr); return -1; }next_substr: buf += substream_data_len[substr]; } rematrix_channels(m, m->max_decoded_substream);#ifdef __CW32__ if (output_data(m, m->max_decoded_substream, data, (unsigned int*)data_size) < 0)#else if (output_data(m, m->max_decoded_substream, data, data_size) < 0)#endif return -1; return length;error: m->params_valid = 0; return -1;}AVCodec mlp_decoder = { "mlp", CODEC_TYPE_AUDIO, CODEC_ID_MLP, sizeof(MLPDecodeContext), mlp_decode_init, NULL, NULL, read_access_unit,#ifdef __CW32__ 0, 0, 0, 0, 0, NULL_IF_CONFIG_SMALL("Meridian Lossless Packing"),#else .long_name = NULL_IF_CONFIG_SMALL("Meridian Lossless Packing"),#endif};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -