mirror of https://github.com/xiph/flac
Different loose mid side algorithm compatible with multithreading (#675)
This commit is contained in:
parent
8d4ccdfbb1
commit
d2b2441056
|
@ -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];
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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÷ 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;
|
||||
|
||||
|
@ -3518,42 +3503,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);
|
||||
* 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;
|
||||
}
|
||||
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 */
|
||||
|
@ -3769,14 +3747,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 {
|
||||
|
@ -3908,17 +3905,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;
|
||||
|
@ -3927,7 +3921,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];
|
||||
|
@ -3940,23 +3933,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]];
|
||||
|
@ -3977,7 +3968,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];
|
||||
|
@ -4005,6 +3996,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;
|
||||
|
@ -4018,13 +4010,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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue