Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Different loose mid side algorithm compatible with multithreading #675

Merged
merged 1 commit into from
Mar 9, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 65 additions & 80 deletions src/libFLAC/stream_encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@
*/
#undef ENABLE_RICE_PARAMETER_SEARCH

#ifdef local_abs64
#undef local_abs64
#endif
#define local_abs64(x) ((uint64_t)((x)<0? -(x) : (x)))


typedef struct {
FLAC__int32 *data[FLAC__MAX_CHANNELS];
Expand Down Expand Up @@ -413,9 +418,6 @@ typedef struct FLAC__StreamEncoderPrivate {
FLAC__real *window[FLAC__MAX_APODIZATION_FUNCTIONS]; /* the pre-computed floating-point window for each apodization function */
FLAC__real *window_unaligned[FLAC__MAX_APODIZATION_FUNCTIONS];
#endif
uint32_t loose_mid_side_stereo_frames; /* rounded number of frames the encoder will use before trying both independent and mid/side frames again */
uint32_t loose_mid_side_stereo_frame_count; /* number of frames using the current channel assignment */
FLAC__ChannelAssignment last_channel_assignment;
FLAC__StreamMetadata streaminfo; /* scratchpad for STREAMINFO as it is built */
FLAC__StreamMetadata_SeekTable *seek_table; /* pointer into encoder->protected_->metadata_ where the seek table is */
uint32_t current_sample_number;
Expand Down Expand Up @@ -737,9 +739,6 @@ static FLAC__StreamEncoderInitStatus init_stream_internal_(
else if(!encoder->protected_->do_mid_side_stereo)
encoder->protected_->loose_mid_side_stereo = false;

if(encoder->protected_->loose_mid_side_stereo && encoder->protected_->num_threads > 2)
encoder->protected_->num_threads = 2;

if(encoder->protected_->bits_per_sample < FLAC__MIN_BITS_PER_SAMPLE || encoder->protected_->bits_per_sample > FLAC__MAX_BITS_PER_SAMPLE)
return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE;

Expand Down Expand Up @@ -921,20 +920,6 @@ static FLAC__StreamEncoderInitStatus init_stream_internal_(
}

encoder->private_->input_capacity = 0;
#ifndef FLAC__INTEGER_ONLY_LIBRARY
encoder->private_->loose_mid_side_stereo_frames = (uint32_t)((double)encoder->protected_->sample_rate * 0.4 / (double)encoder->protected_->blocksize + 0.5);
#else
/* 26214 is the approximate fixed-point equivalent to 0.4 (0.4 * 2^16) */
/* sample rate can be up to 1048575 Hz, and thus use 20 bits, so we do the multiply&divide by hand */
FLAC__ASSERT(FLAC__MAX_SAMPLE_RATE <= 1048575);
FLAC__ASSERT(FLAC__MAX_BLOCK_SIZE <= 65535);
FLAC__ASSERT(encoder->protected_->sample_rate <= 1048575);
FLAC__ASSERT(encoder->protected_->blocksize <= 65535);
encoder->private_->loose_mid_side_stereo_frames = (uint32_t)FLAC__fixedpoint_trunc((((FLAC__uint64)(encoder->protected_->sample_rate) * (FLAC__uint64)(26214)) << 16) / (encoder->protected_->blocksize<<16) + FLAC__FP_ONE_HALF);
#endif
if(encoder->private_->loose_mid_side_stereo_frames == 0)
encoder->private_->loose_mid_side_stereo_frames = 1;
encoder->private_->loose_mid_side_stereo_frame_count = 0;
encoder->private_->current_sample_number = 0;
encoder->private_->current_frame_number = 0;

Expand Down Expand Up @@ -3513,42 +3498,35 @@ FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_block
}
else if(encoder->private_->num_started_threadtasks == encoder->private_->num_threadtasks) {
/* If the first task in the queue is still running, check whether there is enough work
* left in the queue. If there is, start on some */
if(encoder->protected_->loose_mid_side_stereo) {
pthread_mutex_lock(&encoder->private_->threadtask[encoder->private_->next_thread]->mutex_this_task);
if(!encoder->private_->threadtask[encoder->private_->next_thread]->task_done)
pthread_cond_wait(&encoder->private_->threadtask[encoder->private_->next_thread]->cond_task_done, &encoder->private_->threadtask[encoder->private_->next_thread]->mutex_this_task);
}
else {
/* First, check whether the mutex for the next due task is locked or free. If it is free (and thus acquired now) and
* the task is done, proceed to the next bit (writing the bitbuffer). If it is either currently locked or not yet
* processed, choose between starting on some work (if there is enough work in the queue) or waiting for the task
* to finish. Either way, release the mutex first, so it doesn't get interlocked with the work queue mutex */
int mutex_result = pthread_mutex_trylock(&encoder->private_->threadtask[encoder->private_->next_thread]->mutex_this_task);
while(mutex_result || !encoder->private_->threadtask[encoder->private_->next_thread]->task_done) {
if(!mutex_result)
pthread_mutex_unlock(&encoder->private_->threadtask[encoder->private_->next_thread]->mutex_this_task);

pthread_mutex_lock(&encoder->private_->mutex_work_queue);
if(encoder->private_->num_available_threadtasks > (encoder->protected_->num_threads - 1)) {
FLAC__StreamEncoderThreadTask * task = NULL;
task = encoder->private_->threadtask[encoder->private_->next_threadtask];
encoder->private_->num_available_threadtasks--;
encoder->private_->next_threadtask++;
if(encoder->private_->next_threadtask == encoder->private_->num_threadtasks)
encoder->private_->next_threadtask = 1;
pthread_mutex_unlock(&encoder->private_->mutex_work_queue);
pthread_mutex_lock(&task->mutex_this_task);
process_frame_thread_inner_(encoder, task);
mutex_result = pthread_mutex_trylock(&encoder->private_->threadtask[encoder->private_->next_thread]->mutex_this_task);
}
else {
pthread_mutex_unlock(&encoder->private_->mutex_work_queue);
pthread_mutex_lock(&encoder->private_->threadtask[encoder->private_->next_thread]->mutex_this_task);
while(!encoder->private_->threadtask[encoder->private_->next_thread]->task_done)
pthread_cond_wait(&encoder->private_->threadtask[encoder->private_->next_thread]->cond_task_done,&encoder->private_->threadtask[encoder->private_->next_thread]->mutex_this_task);
mutex_result = 0;
}
* left in the queue. If there is, start on some
* First, check whether the mutex for the next due task is locked or free. If it is free (and thus acquired now) and
* the task is done, proceed to the next bit (writing the bitbuffer). If it is either currently locked or not yet
* processed, choose between starting on some work (if there is enough work in the queue) or waiting for the task
* to finish. Either way, release the mutex first, so it doesn't get interlocked with the work queue mutex */
int mutex_result = pthread_mutex_trylock(&encoder->private_->threadtask[encoder->private_->next_thread]->mutex_this_task);
while(mutex_result || !encoder->private_->threadtask[encoder->private_->next_thread]->task_done) {
if(!mutex_result)
pthread_mutex_unlock(&encoder->private_->threadtask[encoder->private_->next_thread]->mutex_this_task);

pthread_mutex_lock(&encoder->private_->mutex_work_queue);
if(encoder->private_->num_available_threadtasks > (encoder->protected_->num_threads - 1)) {
FLAC__StreamEncoderThreadTask * task = NULL;
task = encoder->private_->threadtask[encoder->private_->next_threadtask];
encoder->private_->num_available_threadtasks--;
encoder->private_->next_threadtask++;
if(encoder->private_->next_threadtask == encoder->private_->num_threadtasks)
encoder->private_->next_threadtask = 1;
pthread_mutex_unlock(&encoder->private_->mutex_work_queue);
pthread_mutex_lock(&task->mutex_this_task);
process_frame_thread_inner_(encoder, task);
mutex_result = pthread_mutex_trylock(&encoder->private_->threadtask[encoder->private_->next_thread]->mutex_this_task);
}
else {
pthread_mutex_unlock(&encoder->private_->mutex_work_queue);
pthread_mutex_lock(&encoder->private_->threadtask[encoder->private_->next_thread]->mutex_this_task);
while(!encoder->private_->threadtask[encoder->private_->next_thread]->task_done)
pthread_cond_wait(&encoder->private_->threadtask[encoder->private_->next_thread]->cond_task_done,&encoder->private_->threadtask[encoder->private_->next_thread]->mutex_this_task);
mutex_result = 0;
}
}
/* Task is finished, write bitbuffer */
Expand Down Expand Up @@ -3764,14 +3742,33 @@ FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderT
*/
if(encoder->protected_->do_mid_side_stereo) {
if(encoder->protected_->loose_mid_side_stereo) {
FLAC__ASSERT(encoder->protected_->num_threads < 3);
if(encoder->private_->loose_mid_side_stereo_frame_count == 0) {
uint64_t sumAbsLR = 0, sumAbsMS = 0;
uint32_t i;
if(encoder->protected_->bits_per_sample < 25) {
for(i = 1; i < encoder->protected_->blocksize; i++) {
int32_t predictionLeft = threadtask->integer_signal[0][i] - threadtask->integer_signal[0][i-1];
int32_t predictionRight = threadtask->integer_signal[1][i] - threadtask->integer_signal[1][i-1];
sumAbsLR += abs(predictionLeft) + abs(predictionRight);
sumAbsMS += abs((predictionLeft + predictionRight) >> 1) + abs(predictionLeft - predictionRight);
}
}
else { /* bps 25 or higher */
for(i = 1; i < encoder->protected_->blocksize; i++) {
int64_t predictionLeft = (int64_t)threadtask->integer_signal[0][i] - (int64_t)threadtask->integer_signal[0][i-1];
int64_t predictionRight = (int64_t)threadtask->integer_signal[1][i] - (int64_t)threadtask->integer_signal[1][i-1];
sumAbsLR += local_abs64(predictionLeft) + local_abs64(predictionRight);
sumAbsMS += local_abs64((predictionLeft + predictionRight) >> 1) + local_abs64(predictionLeft - predictionRight);
}
}
if(sumAbsLR < sumAbsMS) {
do_independent = true;
do_mid_side = true;
do_mid_side = false;
frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT;
}
else {
do_independent = (encoder->private_->last_channel_assignment == FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT);
do_mid_side = !do_independent;
do_independent = false;
do_mid_side = true;
frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_MID_SIDE;
}
}
else {
Expand Down Expand Up @@ -3903,17 +3900,14 @@ FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderT
/*
* Compose the frame bitbuffer
*/
if(do_mid_side) {
if((do_independent && do_mid_side) || encoder->protected_->loose_mid_side_stereo) {
uint32_t left_bps = 0, right_bps = 0; /* initialized only to prevent superfluous compiler warning */
FLAC__Subframe *left_subframe = 0, *right_subframe = 0; /* initialized only to prevent superfluous compiler warning */
FLAC__ChannelAssignment channel_assignment;

FLAC__ASSERT(encoder->protected_->channels == 2);

if(encoder->protected_->loose_mid_side_stereo && encoder->private_->loose_mid_side_stereo_frame_count > 0) {
channel_assignment = (encoder->private_->last_channel_assignment == FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT? FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT : FLAC__CHANNEL_ASSIGNMENT_MID_SIDE);
}
else {
if(!encoder->protected_->loose_mid_side_stereo) {
uint32_t bits[4]; /* WATCHOUT - indexed by FLAC__ChannelAssignment */
uint32_t min_bits;
int ca;
Expand All @@ -3922,7 +3916,6 @@ FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderT
FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE == 1);
FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE == 2);
FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_MID_SIDE == 3);
FLAC__ASSERT(do_independent && do_mid_side);

/* We have to figure out which channel assignent results in the smallest frame */
bits[FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT] = threadtask->best_subframe_bits [0] + threadtask->best_subframe_bits [1];
Expand All @@ -3935,23 +3928,21 @@ FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderT

/* When doing loose mid-side stereo, ignore left-side
* and right-side options */
ca = encoder->protected_->loose_mid_side_stereo ? 3 : 1;
for( ; ca <= 3; ca++) {
for(ca = 1; ca <= 3; ca++) {
if(bits[ca] < min_bits) {
min_bits = bits[ca];
channel_assignment = (FLAC__ChannelAssignment)ca;
}
}
frame_header.channel_assignment = channel_assignment;
}

frame_header.channel_assignment = channel_assignment;

if(!FLAC__frame_add_header(&frame_header, threadtask->frame)) {
encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
return false;
}

switch(channel_assignment) {
switch(frame_header.channel_assignment) {
case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
left_subframe = &threadtask->subframe_workspace [0][threadtask->best_subframe [0]];
right_subframe = &threadtask->subframe_workspace [1][threadtask->best_subframe [1]];
Expand All @@ -3972,7 +3963,7 @@ FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderT
FLAC__ASSERT(0);
}

switch(channel_assignment) {
switch(frame_header.channel_assignment) {
case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
left_bps = threadtask->subframe_bps [0];
right_bps = threadtask->subframe_bps [1];
Expand Down Expand Up @@ -4000,6 +3991,7 @@ FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderT
return false;
}
else {
FLAC__ASSERT(do_independent);
if(!FLAC__frame_add_header(&frame_header, threadtask->frame)) {
encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
return false;
Expand All @@ -4013,13 +4005,6 @@ FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderT
}
}

if(encoder->protected_->loose_mid_side_stereo) {
encoder->private_->loose_mid_side_stereo_frame_count++;
if(encoder->private_->loose_mid_side_stereo_frame_count >= encoder->private_->loose_mid_side_stereo_frames)
encoder->private_->loose_mid_side_stereo_frame_count = 0;
encoder->private_->last_channel_assignment = frame_header.channel_assignment;
}

return true;
}

Expand Down
Loading