Improve HCA key testing

This commit is contained in:
bnnm 2018-10-13 19:50:42 +02:00
parent 0c53449df1
commit ec0043bf6b
3 changed files with 61 additions and 32 deletions

View File

@ -27,7 +27,7 @@ void clHCA_delete(clHCA *);
* the header length with clHCA_isOurFile, then read data and call this.
* May be called multiple times to reset decoder state.
* Returns 0 on success, <0 on failure. */
int clHCA_DecodeHeader(clHCA *, void *data, unsigned int size);
int clHCA_DecodeHeader(clHCA *, const void *data, unsigned int size);
typedef struct clHCA_stInfo {
unsigned int version;
@ -61,6 +61,7 @@ int clHCA_getInfo(clHCA *, clHCA_stInfo *out);
/* Decodes a single frame, from data after headerSize. Should be called after
* clHCA_DecodeHeader and size must be at least blockSize long.
* Data may be modified if encrypted.
* Returns 0 on success, <0 on failure. */
int clHCA_DecodeBlock(clHCA *, void *data, unsigned int size);
@ -81,6 +82,10 @@ void clHCA_SetKey(clHCA *, unsigned long long keycode);
* and select the key with scores closer to 1. */
int clHCA_TestBlock(clHCA *hca, void *data, unsigned int size);
/* Resets the internal decode state, used when restarting to decode the file from the beginning.
* Without it there are minor differences, mainly useful when testing a new key. */
void clHCA_DecodeReset(clHCA * hca);
#ifdef __cplusplus
}
#endif

View File

@ -293,10 +293,10 @@ void clHCA_ReadSamples16(clHCA *hca, signed short *samples) {
for (k = 0; k < hca->channels; k++) {
f = hca->channel[k].wave[i][j];
//f = f * hca->rva_volume; /* rare, won't apply for now */
if (f > 1) {
f = 1;
} else if (f < -1) {
f = -1;
if (f > 1.0f) {
f = 1.0f;
} else if (f < -1.0f) {
f = -1.0f;
}
s = (signed int) (f * scale);
if ((unsigned) (s + 0x8000) & 0xFFFF0000)
@ -575,7 +575,7 @@ static unsigned int header_ceil2(unsigned int a, unsigned int b) {
return (b > 0) ? (a / b + ((a % b) ? 1 : 0)) : 0;
}
int clHCA_DecodeHeader(clHCA *hca, void *data, unsigned int size) {
int clHCA_DecodeHeader(clHCA *hca, const void *data, unsigned int size) {
clData br;
int res;
@ -929,43 +929,62 @@ int clHCA_TestBlock(clHCA *hca, void *data, unsigned int size) {
unsigned int ch, sf, s;
int status;
int clips = 0, blanks = 0;
float fsample;
signed int psample;
/* return if decode fails (happens sometimes with wrong keys) */
/* first blocks can be empty/silent, check all bytes but sync/crc */
{
int i;
int is_empty = 1;
const unsigned char *buf = data;
for (i = 2; i < size - 0x02; i++) {
if (buf[i] != 0) {
is_empty = 0;
break;
}
}
if (is_empty) {
return 0;
}
}
/* return if decode fails (happens often with wrong keys due to bad bitstream values) */
status = clHCA_DecodeBlock(hca, data, size);
if (status < 0)
return -1;
/* check decode results */
/* check decode results as bad keys may still get here */
for (ch = 0; ch < hca->channels; ch++) {
for (sf = 0; sf < HCA_SUBFRAMES_PER_FRAME; sf++) {
for (s = 0; s < HCA_SAMPLES_PER_SUBFRAME; s++) {
fsample = hca->channel[ch].wave[sf][s];
psample = (signed int) (fsample * scale);
if (fsample > 1.0f || fsample < -1.0f)
float fsample = hca->channel[ch].wave[sf][s];
if (fsample > 1.0f || fsample < -1.0f) { //improve?
clips++;
else if (psample == 0 || psample == -1)
blanks++;
}
else {
signed int psample = (signed int) (fsample * scale);
if (psample == 0 || psample == -1)
blanks++;
}
}
}
}
/* the more clips the less likely block was correctly decrypted */
if (clips > 0)
if (clips == 1)
clips++;
if (clips > 1)
return clips;
/* if block is silent result is not useful */
if (blanks == hca->channels * HCA_SUBFRAMES_PER_FRAME * HCA_SAMPLES_PER_SUBFRAME)
return 0;
/* block may be correct (but wrong keys can get this too) */
/* block may be correct (but wrong keys can get this too and should test more blocks) */
return 1;
}
#if 0
// it'd seem like resetting IMDCT (others get overwritten) would matter when restarting the
// stream from 0, but doesn't seem any different, maybe because the first frame acts as setup/empty
void clHCA_DecodeReset(clHCA * hca) {
unsigned int i;
@ -975,18 +994,18 @@ void clHCA_DecodeReset(clHCA * hca) {
for (i = 0; i < hca->channels; i++) {
stChannel *ch = &hca->channel[i];
memset(ch->intensity, 0, sizeof(ch->intensity[0]) * HCA_SUBFRAMES_PER_FRAME);
memset(ch->scalefactors, 0, sizeof(ch->scalefactors[0]) * HCA_SAMPLES_PER_SUBFRAME);
memset(ch->resolution, 0, sizeof(ch->resolution[0]) * HCA_SAMPLES_PER_SUBFRAME);
memset(ch->gain, 0, sizeof(ch->gain[0]) * HCA_SAMPLES_PER_SUBFRAME);
memset(ch->spectra, 0, sizeof(ch->spectra[0]) * HCA_SAMPLES_PER_SUBFRAME);
memset(ch->temp, 0, sizeof(ch->temp[0]) * HCA_SAMPLES_PER_SUBFRAME);
memset(ch->dct, 0, sizeof(ch->dct[0]) * HCA_SAMPLES_PER_SUBFRAME);
/* most values get overwritten during decode */
//memset(ch->intensity, 0, sizeof(ch->intensity[0]) * HCA_SUBFRAMES_PER_FRAME);
//memset(ch->scalefactors, 0, sizeof(ch->scalefactors[0]) * HCA_SAMPLES_PER_SUBFRAME);
//memset(ch->resolution, 0, sizeof(ch->resolution[0]) * HCA_SAMPLES_PER_SUBFRAME);
//memset(ch->gain, 0, sizeof(ch->gain[0]) * HCA_SAMPLES_PER_SUBFRAME);
//memset(ch->spectra, 0, sizeof(ch->spectra[0]) * HCA_SAMPLES_PER_SUBFRAME);
//memset(ch->temp, 0, sizeof(ch->temp[0]) * HCA_SAMPLES_PER_SUBFRAME);
//memset(ch->dct, 0, sizeof(ch->dct[0]) * HCA_SAMPLES_PER_SUBFRAME);
memset(ch->imdct_previous, 0, sizeof(ch->imdct_previous[0]) * HCA_SAMPLES_PER_SUBFRAME);
memset(ch->wave, 0, sizeof(ch->wave[0][0]) * HCA_SUBFRAMES_PER_FRAME * HCA_SUBFRAMES_PER_FRAME);
//memset(ch->wave, 0, sizeof(ch->wave[0][0]) * HCA_SUBFRAMES_PER_FRAME * HCA_SUBFRAMES_PER_FRAME);
}
}
#endif
//--------------------------------------------------
// Decode

View File

@ -123,6 +123,7 @@ void decode_hca(hca_codec_data * data, sample * outbuf, int32_t samples_to_do) {
void reset_hca(hca_codec_data * data) {
if (!data) return;
clHCA_DecodeReset(data->handle);
data->current_block = 0;
data->samples_filled = 0;
data->samples_consumed = 0;
@ -152,15 +153,18 @@ void free_hca(hca_codec_data * data) {
#define HCA_KEY_MAX_BLANK_FRAMES 15 /* ignored up to N blank frames (not uncommon to have ~10, if more something is off) */
#define HCA_KEY_MAX_TEST_FRAMES 10 /* 5~15 should be enough, but mostly silent or badly mastered files may need more */
#define HCA_KEY_MAX_ACCEPTABLE_SCORE 300 /* unlikely to work correctly, 10~30 may be ok */
#define HCA_KEY_MAX_ACCEPTABLE_SCORE 150 /* more is unlikely to work correctly, 10~30 isn't uncommon */
/* Test a number of frames if key decrypts correctly.
* Returns score: <0: error/wrong, 0: unknown/silent file, >0: good (the closest to 1 the better) */
* Returns score: <0: error/wrong, 0: unknown/silent file, >0: good (the closest to 1 the better). */
int test_hca_key(hca_codec_data * data, unsigned long long keycode) {
size_t test_frame = 0, current_frame = 0, blank_frames = 0;
int total_score = 0;
const unsigned int blockSize = data->info.blockSize;
/* Due to the potentially large number of keys this must be tuned for speed.
* Buffered IO seems fast enough (not very different reading a large block once vs frame by frame).
* clHCA_TestBlock could be optimized a bit more. */
clHCA_SetKey(data->handle, keycode);
@ -204,5 +208,6 @@ int test_hca_key(hca_codec_data * data, unsigned long long keycode) {
total_score = 1;
}
clHCA_DecodeReset(data->handle);
return total_score;
}