mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-12 01:30:49 +01:00
Improve HCA key testing
This commit is contained in:
parent
0c53449df1
commit
ec0043bf6b
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user