Skip to content
Snippets Groups Projects
Commit 78f89fdb authored by Mathis Rosenhauer's avatar Mathis Rosenhauer Committed by Thomas Jahns
Browse files

Order FSM functions bottom up

parent fee6bbff
No related branches found
No related tags found
No related merge requests found
......@@ -27,15 +27,6 @@
#define ROS -1
static int m_get_block(struct aec_stream *strm);
static int m_get_rsi_resumable(struct aec_stream *strm);
static int m_check_zero_block(struct aec_stream *strm);
static int m_select_code_option(struct aec_stream *strm);
static int m_flush_block(struct aec_stream *strm);
static int m_flush_block_resumable(struct aec_stream *strm);
static int m_encode_splitting(struct aec_stream *strm);
static int m_encode_uncomp(struct aec_stream *strm);
static int m_encode_se(struct aec_stream *strm);
static int m_encode_zero(struct aec_stream *strm);
static inline void emit(struct internal_state *state,
uint32_t data, int bits)
......@@ -394,181 +385,48 @@ static int assess_se_option(uint64_t limit, struct aec_stream *strm)
*
*/
static int m_get_block(struct aec_stream *strm)
static int m_flush_block_resumable(struct aec_stream *strm)
{
/**
Provide the next block of preprocessed input data.
Pull in a whole Reference Sample Interval (RSI) of data if
block buffer is empty.
Slow and restartable flushing
*/
struct internal_state *state = strm->state;
if (strm->avail_out > state->cds_len) {
if (!state->direct_out) {
state->direct_out = 1;
*strm->next_out = *state->cds;
state->cds = strm->next_out;
}
} else {
if (state->zero_blocks == 0 || state->direct_out) {
/* copy leftover from last block */
*state->cds_buf = *state->cds;
state->cds = state->cds_buf;
}
state->direct_out = 0;
}
if (state->blocks_avail == 0) {
state->block = state->data_pp;
if (strm->avail_in >= state->block_len * strm->rsi) {
state->get_rsi(strm);
state->blocks_avail = strm->rsi - 1;
while(state->cds_buf + state->i < state->cds) {
if (strm->avail_out == 0)
return M_EXIT;
if (strm->flags & AEC_DATA_PREPROCESS) {
state->preprocess(strm);
state->ref = 1;
}
return m_check_zero_block(strm);
} else {
state->i = 0;
state->mode = m_get_rsi_resumable;
}
} else {
state->ref = 0;
state->block += strm->block_size;
state->blocks_avail--;
return m_check_zero_block(strm);
*strm->next_out++ = state->cds_buf[state->i];
strm->avail_out--;
strm->total_out++;
state->i++;
}
state->mode = m_get_block;
return M_CONTINUE;
}
static int m_get_rsi_resumable(struct aec_stream *strm)
{
/**
Get RSI while input buffer is short.
Let user provide more input. Once we got all input pad buffer
to full RSI.
*/
int j;
struct internal_state *state = strm->state;
do {
if (strm->avail_in > 0) {
state->data_raw[state->i] = state->get_sample(strm);
} else {
if (state->flush == AEC_FLUSH) {
if (state->i > 0) {
for (j = state->i; j < strm->rsi * strm->block_size; j++)
state->data_raw[j] = state->data_raw[state->i - 1];
state->i = strm->rsi * strm->block_size;
} else {
if (state->zero_blocks) {
state->mode = m_encode_zero;
return M_CONTINUE;
}
emit(state, 0, state->bits);
if (state->direct_out == 0)
*strm->next_out++ = *state->cds;
strm->avail_out--;
strm->total_out++;
return M_EXIT;
}
} else {
return M_EXIT;
}
}
} while (++state->i < strm->rsi * strm->block_size);
state->blocks_avail = strm->rsi - 1;
if (strm->flags & AEC_DATA_PREPROCESS) {
state->preprocess(strm);
state->ref = 1;
}
return m_check_zero_block(strm);
}
static int m_check_zero_block(struct aec_stream *strm)
static int m_flush_block(struct aec_stream *strm)
{
/**
Check if input block is all zero.
Flush block in direct_out mode by updating counters.
Aggregate consecutive zero blocks until we find !0 or reach the
end of a segment or RSI.
Fall back to slow flushing if in buffered mode.
*/
int n;
struct internal_state *state = strm->state;
uint32_t *p = state->block + state->ref;
uint32_t *end = state->block + strm->block_size;
while(p < end && *p == 0)
p++;
if (p < end) {
if (state->zero_blocks) {
/* The current block isn't zero but we have to emit a
* previous zero block first. The current block will be
* handled later.
*/
state->block -= strm->block_size;
state->blocks_avail++;
state->mode = m_encode_zero;
return M_CONTINUE;
}
state->mode = m_select_code_option;
return M_CONTINUE;
} else {
state->zero_blocks++;
if (state->zero_blocks == 1) {
state->zero_ref = state->ref;
state->zero_ref_sample = state->block[0];
}
if (state->blocks_avail == 0
|| (strm->rsi - state->blocks_avail) % 64 == 0) {
if (state->zero_blocks > 4)
state->zero_blocks = ROS;
state->mode = m_encode_zero;
return M_CONTINUE;
}
if (state->direct_out) {
n = state->cds - strm->next_out;
strm->next_out += n;
strm->avail_out -= n;
strm->total_out += n;
state->mode = m_get_block;
return M_CONTINUE;
}
}
static int m_select_code_option(struct aec_stream *strm)
{
/**
Decide which code option to use.
*/
uint64_t uncomp_len;
uint64_t split_len;
uint64_t se_len;
struct internal_state *state = strm->state;
uncomp_len = (strm->block_size - state->ref)
* strm->bit_per_sample;
split_len = assess_splitting_option(strm);
se_len = assess_se_option(split_len, strm);
if (split_len < uncomp_len) {
if (split_len < se_len)
return m_encode_splitting(strm);
else
return m_encode_se(strm);
} else {
if (uncomp_len <= se_len)
return m_encode_uncomp(strm);
else
return m_encode_se(strm);
}
state->i = 0;
state->mode = m_flush_block_resumable;
return M_CONTINUE;
}
static int m_encode_splitting(struct aec_stream *strm)
......@@ -643,47 +501,180 @@ static int m_encode_zero(struct aec_stream *strm)
return m_flush_block(strm);
}
static int m_flush_block(struct aec_stream *strm)
static int m_select_code_option(struct aec_stream *strm)
{
/**
Flush block in direct_out mode by updating counters.
Decide which code option to use.
*/
Fall back to slow flushing if in buffered mode.
uint64_t uncomp_len;
uint64_t split_len;
uint64_t se_len;
struct internal_state *state = strm->state;
uncomp_len = (strm->block_size - state->ref)
* strm->bit_per_sample;
split_len = assess_splitting_option(strm);
se_len = assess_se_option(split_len, strm);
if (split_len < uncomp_len) {
if (split_len < se_len)
return m_encode_splitting(strm);
else
return m_encode_se(strm);
} else {
if (uncomp_len <= se_len)
return m_encode_uncomp(strm);
else
return m_encode_se(strm);
}
}
static int m_check_zero_block(struct aec_stream *strm)
{
/**
Check if input block is all zero.
Aggregate consecutive zero blocks until we find !0 or reach the
end of a segment or RSI.
*/
int n;
struct internal_state *state = strm->state;
uint32_t *p = state->block + state->ref;
uint32_t *end = state->block + strm->block_size;
if (state->direct_out) {
n = state->cds - strm->next_out;
strm->next_out += n;
strm->avail_out -= n;
strm->total_out += n;
while(p < end && *p == 0)
p++;
if (p < end) {
if (state->zero_blocks) {
/* The current block isn't zero but we have to emit a
* previous zero block first. The current block will be
* handled later.
*/
state->block -= strm->block_size;
state->blocks_avail++;
state->mode = m_encode_zero;
return M_CONTINUE;
}
state->mode = m_select_code_option;
return M_CONTINUE;
} else {
state->zero_blocks++;
if (state->zero_blocks == 1) {
state->zero_ref = state->ref;
state->zero_ref_sample = state->block[0];
}
if (state->blocks_avail == 0
|| (strm->rsi - state->blocks_avail) % 64 == 0) {
if (state->zero_blocks > 4)
state->zero_blocks = ROS;
state->mode = m_encode_zero;
return M_CONTINUE;
}
state->mode = m_get_block;
return M_CONTINUE;
}
}
state->i = 0;
state->mode = m_flush_block_resumable;
return M_CONTINUE;
static int m_get_rsi_resumable(struct aec_stream *strm)
{
/**
Get RSI while input buffer is short.
Let user provide more input. Once we got all input pad buffer
to full RSI.
*/
int j;
struct internal_state *state = strm->state;
do {
if (strm->avail_in > 0) {
state->data_raw[state->i] = state->get_sample(strm);
} else {
if (state->flush == AEC_FLUSH) {
if (state->i > 0) {
for (j = state->i; j < strm->rsi * strm->block_size; j++)
state->data_raw[j] = state->data_raw[state->i - 1];
state->i = strm->rsi * strm->block_size;
} else {
if (state->zero_blocks) {
state->mode = m_encode_zero;
return M_CONTINUE;
}
emit(state, 0, state->bits);
if (state->direct_out == 0)
*strm->next_out++ = *state->cds;
strm->avail_out--;
strm->total_out++;
return M_EXIT;
}
} else {
return M_EXIT;
}
}
} while (++state->i < strm->rsi * strm->block_size);
state->blocks_avail = strm->rsi - 1;
if (strm->flags & AEC_DATA_PREPROCESS) {
state->preprocess(strm);
state->ref = 1;
}
return m_check_zero_block(strm);
}
static int m_flush_block_resumable(struct aec_stream *strm)
static int m_get_block(struct aec_stream *strm)
{
/**
Slow and restartable flushing
Provide the next block of preprocessed input data.
Pull in a whole Reference Sample Interval (RSI) of data if
block buffer is empty.
*/
struct internal_state *state = strm->state;
while(state->cds_buf + state->i < state->cds) {
if (strm->avail_out == 0)
return M_EXIT;
if (strm->avail_out > state->cds_len) {
if (!state->direct_out) {
state->direct_out = 1;
*strm->next_out = *state->cds;
state->cds = strm->next_out;
}
} else {
if (state->zero_blocks == 0 || state->direct_out) {
/* copy leftover from last block */
*state->cds_buf = *state->cds;
state->cds = state->cds_buf;
}
state->direct_out = 0;
}
*strm->next_out++ = state->cds_buf[state->i];
strm->avail_out--;
strm->total_out++;
state->i++;
if (state->blocks_avail == 0) {
state->block = state->data_pp;
if (strm->avail_in >= state->block_len * strm->rsi) {
state->get_rsi(strm);
state->blocks_avail = strm->rsi - 1;
if (strm->flags & AEC_DATA_PREPROCESS) {
state->preprocess(strm);
state->ref = 1;
}
return m_check_zero_block(strm);
} else {
state->i = 0;
state->mode = m_get_rsi_resumable;
}
} else {
state->ref = 0;
state->block += strm->block_size;
state->blocks_avail--;
return m_check_zero_block(strm);
}
state->mode = m_get_block;
return M_CONTINUE;
}
......@@ -816,8 +807,8 @@ int aec_encode(struct aec_stream *strm, int flush)
encoder.
*/
int n;
struct internal_state *state;
state = strm->state;
struct internal_state *state = strm->state;
state->flush = flush;
while (state->mode(strm) == M_CONTINUE);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment